Search code examples
pythonplist

iterating over all the bookmarks in Bookmarks.plist


The Bookmarks.plist file is how Safari stores its bookmarks. How do I count all URLStrings?

I can get the bookmarks file with:

BOOKMARKS_PLIST = '~/Library/Safari/Bookmarks.plist

convert it to text from binary with:

converted = subprocess.call(['plutil', '-convert', 'xml1', bookmarksFileCopy])

and for example, access a single entry with:

'print plist['Children'][5]['Children'][1]['Children'][2]'

It seems I should use recursion to walk down the 'leaves of the tree' but I cannot get the syntax right in python. As you can tell, I am a beginner.

EDIT: Thank you Jose. Although your solution gave the error I described below, I did get this to work:

import plistlib
import subprocess
import os

def countURLStrings(plistDict):
    childURLCounts = 0
    if 'Children' in plistDict.keys():
        for child in plistDict['Children']:
            childURLCounts += countURLStrings(child)
    if 'URLString' in plistDict.keys():
        childURLCounts += 1
        print plistDict.URLString
    return childURLCounts

BOOKMARKS_PLIST = '/Users/me/Desktop/Safari-20150403175048/Bookmarks.plist'
converted = subprocess.call(['plutil', '-convert', 'xml1', BOOKMARKS_PLIST])

pl = plistlib.readPlist(BOOKMARKS_PLIST)

ct = countURLStrings(pl)

print ct

And as a bonus, this iterated version is faster than the recursion I tried and failed at.


Solution

  • The first code example works in Python 3.4.2. The load() method is not available in 2.x and the readPlist() method encounters an error. The second code example was tested successfully with Python 2.7.6.

    BOOKMARKS_PLIST

    • Replace username in the definition of (BOOKMARKS_PLIST) with the correct username
    • The method provided [countURLStrings(plistDict)] recursively calls itself with every encountered instance of a 'Children' dictionary and increases the count by one for every 'URLString' encountered.

    Sample Code Python 3.4.2

    import plistlib
    
    def countURLStrings(plistDict):
        childURLCounts = 0
        if 'Children' in plistDict.keys():
            for child in plistDict['Children']:
                childURLCounts += countURLStrings(child)
        if 'URLString' in plistDict.keys():
            childURLCounts += 1
        return childURLCounts
    
    BOOKMARKS_PLIST = '/Users/username/Library/Safari/Bookmarks.plist'
    
    with open(BOOKMARKS_PLIST, 'rb') as fp:
        pl = plistlib.load(fp)
    
    countURLStrings(pl)
    

    Sample Code Python 2.7.6

    import biplist
    
    def countURLStrings(plistDict):
        childURLCounts = 0
        if 'Children' in plistDict.keys():
            for child in plistDict['Children']:
                childURLCounts += countURLStrings(child)
        if 'URLString' in plistDict.keys():
            childURLCounts += 1
        return childURLCounts
    
    BOOKMARKS_PLIST = '/Users/jaburaschi/Library/Safari/Bookmarks.plist'
    
    with open(BOOKMARKS_PLIST, 'rb') as fp:
        pl = biplist.readPlist(fp)
    
    countURLStrings(pl)