pythonwise /

#!/usr/bin/env python
Port Google Bookmarks over to
* Export Google Bookmarks by hitting
* Get pinboard auth_token from

    ./ bookmarks.xml --auth-token <token>
import requests

from cStringIO import StringIO
from datetime import datetime
import httplib
import logging as log
import xml.etree.cElementTree as et

add_url = ''

# Example XML:
# <xml_api_reply version="1">
#   <bookmarks>
#     <bookmark>
#       <title>Finnish Doctors Are Prescribing Video Games For ADHD -
#       Slashdot</title>
#       <url></url>
#       <timestamp>1381590052580408</timestamp>
#       <id>536897562302183779</id>
#       <labels>
#         <label>psychology</label>
#         <label>adhd</label>
#         <label>video</label>
#         <label>games</label>
#       </labels>
#     </bookmark>
#   ...

def iter_xml(fo):
    tree = et.parse(fo)
    for bmk in tree.iterfind('.//bookmark'):
        title = bmk.find('title')
        ts = int(bmk.find('timestamp').text)
        yield {
            'title': title.text if title is not None else 'UNKNOWN TITLE',
            'url': bmk.find('url').text,
            'labels': [elem.text for elem in bmk.iterfind('.//label')],
            'timestamp': datetime.utcfromtimestamp(ts/1000000),

def bmk2params(bmk, auth_token):
    return {
        'url': bmk['url'],
        'description': bmk['title'],
        'tags': ','.join(bmk['labels']),
        'dt': bmk['timestamp'].strftime('%Y-%m-%dT%H:%M:%SZ'),
        'auth_token': auth_token,
        'replace': 'yes',

def parse_reply(reply):
    if reply.status_code != httplib.OK:
        return False

    root = et.parse(StringIO(reply.content)).getroot()
    code = root.get('code')
    if code != 'done':
        return False

    return True

def post_bookmark(bmk, auth_token):
    params = bmk2params(bmk, auth_token)

    reply =, params=params)
    return parse_reply(reply)

def main(argv=None):
    import sys
    from argparse import ArgumentParser

    argv = argv or sys.argv

    parser = ArgumentParser(description='Post Google Bookmarks to Pinboard')
    parser.add_argument('--start', help='start offset', type=int, default=0)
    args = parser.parse_args(argv[1:])

    with open(args.filename) as fo:
        bmks = list(iter_xml(fo))

    if args.start > 0:
        bmks = bmks[args.start:]

    for i, bmk in enumerate(bmks):
        print(u'{}: {}'.format(args.start + i, bmk['title']))
        if not post_bookmark(bmk, args.auth_token):
            raise SystemExit('error: cannot post {}'.format(bmk['title']))

if __name__ == '__main__':