Google Web履歴からWeb活動履歴をダウンロード(Cookieによる認証版)
はじめに
以前公開した、Web活動履歴ダウンロードプログラムに不具合が発生しました。その原因は、Cookie認証を利用していないことでした。そこで、プログラムをCookie認証するように変更しました。
・注意事項
・12月7日以降の修正
- 12月9日:履歴中にvideo resultなどが含まれるときにエラーになる不具合の修正
発生した問題
以前に記載したWeb活動履歴(以下、単に履歴)のダウンロードプログラムが、気づいたら502エラーを吐いて動作しなくなっていたことに気付いた。
よくよく調べてみたら、Linuxのwgetコマンドを使用した場合でも、下記のように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履歴で認証と同じ処理を行っています。
- 認証時にPOSTするデータ(data)とCookie(openerが内部的に保持)を取得
- 認証ページにアクセス
- 認証ページのhtmlをパースして、inputタグの値を取得
- ユーザIDとパスワードを設定
- 実際に認証
後は、このcertifyByCookieが返すopenerを利用して、以前と同じようにGoogle Web履歴にRSS取得するためのHttpリクエストを発行することにより、不具合は修正なくなりました。