Google Web履歴からWeb活動履歴をダウンロード(Cookieによる認証版)

はじめに

 以前公開した、Web活動履歴ダウンロードプログラムに不具合が発生しました。その原因は、Cookie認証を利用していないことでした。そこで、プログラムをCookie認証するように変更しました。


ソースコード


・注意事項

  1. 詳細な使い方は、「python getwebhistory.py -h」の出力を参照してください。
  2. htmlパーサーのlxmlというpythonのライブラリを導入する必要があります。


・12月7日以降の修正

  • 12月9日:履歴中にvideo resultなどが含まれるときにエラーになる不具合の修正

発生した問題

 以前に記載したWeb活動履歴(以下、単に履歴)のダウンロードプログラムが、気づいたら502エラーを吐いて動作しなくなっていたことに気付いた。


 よくよく調べてみたら、Linuxwgetコマンドを使用した場合でも、下記のように502エラーと401エラーを吐いて、履歴のRSSが取得できなくなっていた。

wgetコマンドによる履歴の取得
$ wget --http-user=username --http-passwd=passwd 'https://www.google.com/history/lookup?hl=ja&output=rss'

--2009-12-08 00:57:16--  https://www.google.com/history/lookup?hl=ja&output=rss
www.google.com をDNSに問いあわせています... 66.249.89.99, 66.249.89.103, 66.249.89.104, ...
www.google.com|66.249.89.99|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 401 Unauthorized
www.google.com:443 への接続を再利用します。
HTTP による接続要求を送信しました、応答を待っています... 502 Bad Gateway
2009-12-08 00:57:17 エラー 502: Bad Gateway。

原因考察

 以前のダウンロードプログラムとwgetコマンドともに、履歴のRSSを取得できなくなった。しかし、Webブラウザ上では何事もなく履歴のRSSを閲覧することはできる。この2つの違いは、おそらく認証方法です。前者はCookieを利用せず、Didgest認証をしています。後者はCookieを利用した認証をしています。


以上のことから考えて、今回の不具合の原因は、Googleが主な認証方式として、Cookie認証を利用するためと考えました。


実は当初から、10月30日のダウンロードプログラムは、402エラーを吐くときがしばしば起こっていました。この原因は、基本的にはGoogleは認証方式としてCookie認証を利用しているものの、ごく一部のGoogleのサーバでは、Didgest認証も許可していたためと考えられます。

Cookie認証の利用

 履歴をGoogleから取得する前に、Cookie認証を行うように、ダウンロードプログラムを変更しました。

ソースコード


変更の味噌である箇所を解説します。

冒頭部分
import lxml.html import fromstring
import cookielib

まずは、htmlやxmlのパーサーのlxmlと、cookieを利用するためにcookielibをインポートします。cookielibはpythonの標準ライブラリですが、lxmlについては、別途導入が必要です。

Cookie認証部
def certifyByCookie(user, passwd):
    cj = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
    #プロキスを使用する場合
    #proxySupport = urllib2.ProxyHandler({'プロキシサーバのスキーム(httpなど)': 'プロキシサーバのURL'})
    #opener = urllib2.build_opener(proxySupport, urllib2.HTTPCookieProcessor(cj))
    
    #
    #認証時にPOSTするデータとCookieを取得
    #
    url = "https://www.google.com/accounts/ServiceLogin?hl=ja&nui=1&service=hist"
    req = urllib2.Request(url)
    req.add_header("User-Agent", "Mozilla/5.0")
    pagehandle = opener.open(req)
    doc = fromstring(pagehandle.read())
    #認証ページ中のinputタグの値を全て取得
    data = dict([(input.name, input.value) for input in doc.xpath('//input')])
    #ユーザIDとパスワードを設定
    data["Email"] = user 
    data["Passwd"] = passwd

    #
    #実際に認証
    #
    url = "https://www.google.com/accounts/ServiceLoginAuth?service=hist"
    #OSがWindowsであり、ここでエラーが出る場合、コメントアウト
    #data["signIn"] = u"ログイン".encode("sjis")
    req = urllib2.Request(url, urllib.urlencode(data))
    req.add_header("User-Agent", "Mozilla/5.0")
    pagehandle = opener.open(req)

    return opener

ここでは、Webブラウザの行うGoogle Web履歴で認証と同じ処理を行っています。

  1. 認証時にPOSTするデータ(data)とCookie(openerが内部的に保持)を取得
    1. 認証ページにアクセス
    2. 認証ページのhtmlをパースして、inputタグの値を取得
    3. ユーザIDとパスワードを設定
  2. 実際に認証
    1. httpリクエストを発行
    2. 認証に必要なCookie情報がopenerに内部的に保持される

後は、このcertifyByCookieが返すopenerを利用して、以前と同じようにGoogle Web履歴にRSS取得するためのHttpリクエストを発行することにより、不具合は修正なくなりました。

追記

wgetコマンドの方ですが、ブラウザの生成したcookieなどを利用すれば、Web履歴は取得できます。