Google Contacts import

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from BeautifulSoup import BeautifulSoup
import urllib
import httplib

GDATA_URL = '/accounts/ClientLogin'

class GdataError(Exception):
    pass

class Gdata:
    """
    A class to retrieve a users contacts from their Google Account.
    
    Dependencies:
    -------------
    * BeautifulSoup. 
    * That's it. :-)

    Usage:
    ------
    >>> g = Gdata('email@example.org', 'password')
    >>> g.login()
    (200, 'OK')
    >>> g.get_contacts()
    >>> g.contacts
    [(u'Persons Name', 'name@person.com'), ...]


    """
    def __init__(self, username='test@gmail.com', password='test', service='cp'):
        self.username = username
        self.password = password
        self.account_type = 'HOSTED_OR_GOOGLE'  # Allow both Google Domain and Gmail accounts
        self.service = service                  # Defaults to cp (contacts)
        self.source = 'google-data-import'            # Our application name
        self.code = ''                          # Empty by default, populated by self.login()
        self.contacts = []                      # Empty list by default, populated by self.get_contacts()
    
    def login(self):
        """
        Login to Google. No arguments.
        """
        data = urllib.urlencode({
            'accountType': self.account_type,
            'Email': self.username,
            'Passwd': self.password,
            'service': self.service,
            'source': self.source
        })
        headers = {
            'Content-type': 'application/x-www-form-urlencoded',
            'Accept': 'text/plain'
        }
        
        conn = httplib.HTTPSConnection('google.com')
        conn.request('POST', GDATA_URL, data, headers)
        response = conn.getresponse()
        if not str(response.status) == '200':
            raise GdataError("Couldn't log in. HTTP Code: %s, %s" % (response.status, response.reason))
            
        d = response.read()
        
        self.code = d.split("\n")[2].replace('Auth=', '')
        return response.status, response.reason
    
    def _request(self, max_results=200):
        """
        Base function for requesting the contacts. We'll allow other methods eventually
        """
        url = '/m8/feeds/contacts/%s/base/?max-results=%d' % (self.username, max_results)
        
        headers = {'Authorization': 'GoogleLogin auth=%s' % self.code}
        
        conn = httplib.HTTPConnection('www.google.com')
        conn.request('GET', url, headers=headers)
        response = conn.getresponse()
        if not str(response.status) == '200':
            raise GdataError("Couldn't log in. HTTP Code: %s, %s" % (response.status, response.reason))
        
        return response.read()
    
    def get_contacts(self, max_results=200):
        """ Parses the contacts (using BeautifulSoup) from self._request, and then populates self.contacts
        """
        soup = BeautifulSoup(self._request(max_results))
        self.contacts = []
        for entry in soup.findAll('title'):
            if len(entry.parent.findAll(['gd:email', 'title'])) == 2:
                s = entry.parent.findAll(['gd:email', 'title'])
                self.contacts.append((s[0].string, s[1].get('address')))
        
        return

Comments

simon (on March 22, 2008):

The problem with this approach is that you have to ask the user for their Gmail username and password, which they shouldn't be giving you as you aren't Google. Have you considered using the Google Contacts API instead?

#

henriklied (on March 22, 2008):

Yes, you're right, Simon, AuthSub is what most people should use. In my case, ClientLogin provided the most fluent experience for the user (which was what my client requested), so I went for it.

I could always throw up an example using AuthSub, for those interested.

#

(Forgotten your password?)

You may use Markdown syntax here, but raw HTML will be removed.