Hatena::ブログ(Diary)

カストリブログ

2009-12-07

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

| 02:25

はじめに

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


ソースコード


・注意事項

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

・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履歴で認証と同じ処理を行っています。

  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履歴は取得できます。

nano0061nano0061 2010/04/01 08:26 こんばんは.

ずっと,Googleウェブ履歴をダウンロードできないかなーと思っていたので
非常に参考にさせていただいています.

質問させていただきたいのですが,私の環境では上手くプログラムが動作しません.具体的にはwgetコマンドを試すと「・・・失敗しました: Connection timed out.」と表示されてしまいます.

原因としては,私のネットワーク環境がProxy経由しているからだと思うのですが,Proxy経由で本プログラムを利用することは可能でしょうか?

もし可能であれば,どの辺りを修正すればよいかアドバイスいただけませんか?
よろしくお願い致します.

hippuhippu 2010/04/07 22:15 nano0061さん、こんにちは。

一週間ほどネットが使用できない環境にいたため、返信が遅れました。

ソースコードの298〜300行目にプロキシ環境下で使用する場合についてのコメントを書いておきました。
新しいソースコードは、この記事の上部のリンクからダウンロードできます。

ただし、現在、私はプロキシ環境下にいないので、動作確認はしていません。
なので、正直いって自信はありません。

nano0061nano0061 2010/04/08 00:19 hippuさん、こんばんは.

今、アップしていただいたソースコードをダウンロードして中身を眺めているところです.
成功/不成功に関しては、追って報告させていただきたいと思います.
また、分からない点があったら質問させてください.
対応していただき本当にありがとうございました!!

匿名希望匿名希望 2012/02/27 21:49 こんooは。これを見つけて実際に試してみましたが、うまく取れませんでした。

ソースそのまま
→urllib2.HTTPError: HTTP Error 401: Unauthorized

url = "https://accounts.google.com/ServiceLogin?hl=ja&continue=https://www.google.com/history/%3Fhl%3Dja&nui=1&authuser=0"
と2か所ソースのURLを変更してみる
→AttributeError: 'module' object has no attribute 'dumps'

url = "https://accounts.google.com/ServiceLoginAuth"
さらに…と2番目だけを変更する
→AttributeError: 'module' object has no attribute 'dumps'

2009-11-01

Google Web履歴のRSSの仕様

| 02:14

リクエスト時のパラメーター

単に履歴を取得する場合と、履歴を検索する場合とでリクエスト先のURLや使用可能なパラメータが異なる。


単に履歴を取得する場合

URL:http://www.google.com/history/lookup?output=rss&lr=lang_ja&hl=ja

パラメータ意味
max取得する履歴の日時の上限値(ローカル時間から求めたエポック時間)
min取得する履歴の日時の下限値(ローカル時間から求めたエポック時間)
num取得する履歴数(指定しなければ20?)
start取得する履歴のオフセット
yr
day日付
month
output履歴の出力形式。現在指定できるのはrssのみ
lr言語関係。lang_jaに指定してしておくのが無難
hl言語関係。jaに指定しておくのが無難
st取得する履歴の種類(web,img,ad,fg,blogs,news,bookds,vid)

履歴を検索する場合

URL:http://www.google.com/history/find?output=rss&lr=lang_ja&hl=ja

パラメータ意味
q検索クエリ。指定されていない場合は、単に履歴を取得
sort検索結果の表示順。dateを指定すると日付順、指定しなければ関連度順

(単に履歴を取得するときのパラメータはほぼ使用可能)


注意点

maxとminを同時に指定しない方がよいかも。

それは、maxとminで指定した時間の範囲内に含まれる履歴数がnum以下の場合、numに足りない分だけ最新の履歴データが出力されるためである。

2009-10-31

Google Web履歴からWeb活動履歴をダウンロード

| 02:12

注意

ここのプログラムは、不具合があるため、正常に動作しない可能性が高いです。不具合を修正したソースコードは、下記の記事から取得できます。

http://d.hatena.ne.jp/hippu/20091207/1260206750


はじめに

GoogleツールバーをWebブラウザにインストールすると、Googleが検索活動の履歴(検索クエリと検索結果の閲覧履歴)やを記録し始める。

設定次第では検索活動の履歴だけでなく、ハイパーリンクやブックマーク、ブラウザの戻る・進む操作などを利用したWebページへのアクセスも記録する。

記録された履歴は、Google Web Historyというサービスから閲覧したり、検索することができる。

Google Web Historyから活動履歴をダウンロードしようと思ったのだが、備え付けのダウンロード機能がなかった。

幸いにもGoogle Web Historyは活動履歴をRSS形式で出力してくれるので、それを利用して自分でダウンロードプログラムを作成した。

内容

  • プログラム概要
  • 出力内容

プログラム概要

  • 作成言語:python 2.6(jsonを使用、simplejsonなどを導入すれば2.5、2.4でも動くはず)
  • 機能概要
    • 全履歴のダウンロード
    • 日付範囲を指定したダウンロード
    • 履歴の検索結果のダウンロード
  • 出力形式
    • JSON
  • 使い方

下のソースコードに適当なファイル名filenameを付けて、コマンドラインからpython filename -hとすればヘルプが表示されるのでそちらを参考。

#-*- coding:utf-8 -*-
import urllib2, urllib
from datetime import timedelta, datetime
import time
import json
from xml.dom.minidom import parseString 
import sys
import getopt
from urlparse import urlparse, urlunparse
import urllib
import re

def getText(elm):
    nodelist = elm.childNodes
    rc = ""
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc = rc + node.data
    return rc

def toDict(elm):
    ob = {}
    ob["id"] = getText(elm.getElementsByTagName("guid")[0])
    ob["title"] = getText(elm.getElementsByTagName("title")[0])
    ob["link"] = getText(elm.getElementsByTagName("link")[0])
    ob["date"] = getText(elm.getElementsByTagName("pubDate")[0])
    category = getText(elm.getElementsByTagName("category")[0])
    ob["category"] = category
    ob["description"] = getText(elm.getElementsByTagName("description")[0])
    
    
    if category == "browser result":
        if elm.getElementsByTagName("smh:bkmk"):
             ob["bkmk"] = getText(elm.getElementsByTagName("smh:bkmk")[0])
             ob["bkmkId"] = getText(elm.getElementsByTagName("smh:bkmk_id")[0])
             
             ob["bkmkLabels"] = []
             for label in elm.getElementsByTagName("smh:bkmk_label"):
                 ob["bkmkLabels"].append(getText(label))
                 
             ob["bkmkTitle"] = getText(elm.getElementsByTagName("smh:bkmk_title")[0])
             ob["category"] = "bookmark"
    elif category.endswith("result"):
        ob["queryId"] = getText(elm.getElementsByTagName("smh:query_guid")[0])
    elif category.endswith("query"):
        pass
    else:
        raise Error("")
    
    return ob

def decideDateRange(startDate, endDate, all):
    if all:
        endDate = datetime.now() + timedelta(days=1)
        startDate = datetime(1900, 1, 1)
    else:
        if not startDate and not endDate:
            startDate = datetime.now() - timedelta(days=1)
            endDate = datetime.now()
        elif not startDate:
            startDate = endDate
            endDate = endDate + timedelta(days=1)
        elif not endDate:
            endDate = startDate + timedelta(days=1)
        elif endDate < startDate:
            temp = startDate
            startDate = endDate
            endDate = temp
            
    return startDate, endDate 

def getWebHistoryOrderByDate(opener, startDate, maxTime, num, query, length):
    if query:
        mode = "find"
    else:
        mode = "lookup"
        
    count = 0
    entries = []
    while True:
        params = {"hl" : "en", "output" : "rss", "lr" : "lang_ja", "max" : maxTime, "num" : num, "q" : query, "sort" : "date"}
        req = urllib2.Request('http://www.google.com/history/%s?%s' % (mode, urllib.urlencode(params)))
#       rssをutf8で出力させるのに必要
        req.add_header("User-Agent", "Mozilla/5.0")
        pagehandle = opener.open(req)
        
        if pagehandle.code != 200:
            raise Error("")
        
        dom = parseString(pagehandle.read())
        if not dom.getElementsByTagName("item"):
            dom.unlink()
            return entries
        
        for entry in dom.getElementsByTagName("item"):
            date = getText(entry.getElementsByTagName("pubDate")[0])
            d = datetime.strptime(date, "%a, %d %b %Y %H:%M:%S GMT") + timedelta(hours=9)
            tempTime = int(time.mktime(time.strptime(d.strftime("%y%m%d %H:%M:%S"), "%y%m%d %H:%M:%S")) * (10 ** 6))
            #サマータイムの都合で、maxTimeの一時間後の履歴までが取得されるため
            #重複した履歴を無視
            if tempTime > maxTime:
                continue
            
            if d < startDate or length <= count:
                dom.unlink()
                return entries
            
            entries.append(toDict(entry))
            count += 1
        
        d = datetime.strptime(entries[-1]["date"], "%a, %d %b %Y %H:%M:%S GMT") + timedelta(hours=9)
        maxTime = int(time.mktime(time.strptime(d.strftime("%a, %d %b %Y %H:%M:%S"), "%a, %d %b %Y %H:%M:%S")) * (10 ** 6))
        dom.unlink()
    
    return entries

def getWebHistoryOrderByRelation(opener, start, num, query, length):
    entries = []
    count = 0
    while True:
        params = {"hl" : "ja", "output" : "rss", "lr" : "lang_ja", "start" : start, "num" : num, "q" : query, "sort" : ""}
        req = urllib2.Request('http://www.google.com/history/find?%s' % (urllib.urlencode(params)))
#       rssをutf8で出力させるのに必要
        req.add_header("User-Agent", "Mozilla/5.0")
        pagehandle = opener.open(req)
        
        if pagehandle.code != 200:
            raise Error("")
        
        dom = parseString(pagehandle.read())
        if not dom.getElementsByTagName("item"):
            dom.unlink()
            return entries
        
        for entry in dom.getElementsByTagName("item"):
            if length <= count:
                dom.unlink()
                return entries
            else:
                entries.append(toDict(entry))
                count += 1
            
            
            
        l = len(dom.getElementsByTagName("item"))
        start += l
        dom.unlink()
        
    return entries    

def dateStrCmp(dateStr1, dateStr2):
    d1 = datetime.strptime(dateStr1, "%a, %d %b %Y %H:%M:%S GMT")
    d2 = datetime.strptime(dateStr2, "%a, %d %b %Y %H:%M:%S GMT")
    
    if d1 > d2: return 1
    elif d1 < d2: return -1
    else:   return 0
    
def correctRelation(entries):
    queries = {}
    p = re.compile("[0-9]+")
    for entry in entries:
        if entry["category"].endswith("query"):
            mob = p.match(entry["description"])
            if mob:
                count = int(mob.group())
            else:
                count = 0
            queries[entry["id"]] = [entry, count]
            
    unknownSearchResults = []
    for entry in entries:
        if entry["category"].endswith("result") and entry["category"] != "browser result":
            if entry["queryId"] in queries:
                queries[entry["queryId"]][1] -= 1
            else:
                unknownSearchResults.append(entry)
    
    unknownQueries = [[v[0], v[1]] for v in queries.values() if v[1] > 0]
    unknownQueries.sort(lambda x, y: -dateStrCmp(x[0]["date"], y[0]["date"]))
    
    for e in unknownSearchResults:
        if len(unknownQueries) == 0:
            break
        
        query, count = unknownQueries[0]
        if dateStrCmp(e["date"], query["date"]) < 0:
            unknownQueries = unknownQueries[1:]
        else:
            query, count = unknownQueries[0]
            e["queryId"] = query["id"]
            unknownQueries[0][1] -= 1
            if unknownQueries[0][1] <= 0:
                unknownQueries = unknownQueries[1:]
                
def discoverGoogleScholar(entries):
    for e in entries:
        if e["category"] == "browser result" and e["title"].startswith("http://scholar.google.co.jp"):
            o = urlparse(e["title"])
            
            if o.path in ["", "/", "/schp"]:
                e["title"] = "Google Scholar"
            elif o.path == "/scholar":
                query = {}
                for pair in o.query.split("&"):
                    k, v = pair.split("=")
                    k = urllib.unquote_plus(k)
                    v = urllib.unquote_plus(v)
                    query[k] = v
                
                if "q" in query and "start" not in query:
                    e["category"] = "scholar query"
                    e["title"] = query["q"].encode('raw_unicode_escape').decode('utf8')

#広告、画像などの断片ページのURLに頻出する文字列
FLAGMENT_PAGE_WORDS = [
                       "ad", "rot", "banner", "rss", "footer", "cookie", "headline", "gadget", "widget", "rcm", "doubleclick",
                       "right", "button", "send", "visitor", "affiliate", "img", "wrs", "topics", "thumb", "access"]

def findFlagmentPageWords(url):
    url = url.lower()
    for w in FLAGMENT_PAGE_WORDS:
        if url.find(w) != -1:
            return True
    return False

#断片的なページのURLにはほぼ出現しない文字列
NOT_FLAGMENT_PAGE_WORDS = ["pdf", "entry", "archive"]

def findNotFlagmentPageWords(url):
    url = url.lower()
    for w in NOT_FLAGMENT_PAGE_WORDS:
        if url.find(w) != -1:
            return True
    return False


def removeNoise(entries):
    entries = [e for e in entries if not (e["category"] == "browser result" and e["title"].startswith("https://"))]
    entries = [e for e in entries if not (e["category"] == "browser result" and findFlagmentPageWords(e["title"]))]
    entries = [e for e in entries if e["category"] != "browser result" or not e["title"].startswith("http://") or findNotFlagmentPageWords(e["title"])]
        
    entries = [e for e in entries if e["link"].lower().find("mail") == -1]
    entries = [e for e in entries if e["title"].lower().find("headline") == -1]
    entries = [e for e in entries if e["title"].lower().find(u"ヘッドライン") == -1]
    
    l = len(entries) 
    if  l <= 1:
        return entries
    
    resultEntries = []
    for i in range(0, l - 1):
        cur = entries[i]
        next = entries[i+1]
        
        if cur["link"].strip() == "":
            continue
        
        if cur["category"] == "browser result" and cur["link"] == next["link"]:
            cd = datetime.strptime(cur["date"], "%a, %d %b %Y %H:%M:%S GMT")
            nd =  datetime.strptime(next["date"], "%a, %d %b %Y %H:%M:%S GMT")
            td = cd - nd
            if td.seconds < 3600:
               continue
        resultEntries.append(cur)
    resultEntries.append(next)

    return resultEntries

def getWebHistory(user, passwd, startDate=None, endDate=None, all=False, num=500, query=None, sortedByDate=True, length=sys.maxint, start=0):
    if all:
        num = 1000
        start = 0
        length = sys.maxint
        
    num = min(num, length)
    
    passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
    passman.add_password(None, "www.google.com", user, passwd)
    authhandler = urllib2.HTTPBasicAuthHandler(passman)
    opener = urllib2.build_opener(authhandler)
    
    if sortedByDate:
        startDate, endDate = decideDateRange(startDate, endDate, all)
        print "startDate", startDate
        print "endDate", endDate
        maxTime = int(time.mktime(time.strptime(endDate.strftime("%y%m%d %H:%M:%S"), "%y%m%d %H:%M:%S")) * (10 ** 6))
        entries = getWebHistoryOrderByDate(opener, startDate, maxTime, num, query, length)
        
    elif query:
        entries = getWebHistoryOrderByRelation(opener, start, num, query, length)
    
    result = {"user" : user, "date" : datetime.now().strftime("%Y%m%d %H:%M:%S"), "entries" : entries, "query" : query, "all" : all, "sortedByDate" : sortedByDate, "start" : start}
    if sortedByDate:
        result["startDate"] = startDate.strftime("%Y%m%d %H:%M:%S")
        result["endDate"] = endDate.strftime("%Y%m%d %H:%M:%S")
    elif query:
        result["startDate"] = None
        result["endDate"] = None
    
    return result
        
def printHelp():
    print "Usage: getwebhistory.py -u username -p password [OPTION]"
    print u"-s <date> 履歴を取得する期間の始まりの日時をyyyymmddまたはyyyymmdd hh:mm:dd形式で指定"
    print u"-e <date> 履歴を取得する期間の終わりの日時をyyyymmddまたはyyyymmdd hh:mm:dd形式で指定"
    print u"-q <query> 履歴を検索するためのクエリを指定"
    print u"-l <length> 履歴の取得数を指定"
    print u"-n <num> 一回のHttpリクエストで取得する履歴の数(最大1000)を指定"
    print u"-h --help プログラムの使用方法を表示して、プログラムを終了"
    print u"-f <file> 取得した履歴を出力するファイル名を指定"
    print u"--all このオプションを指定すると履歴を全て取得します。-q、-f、--order-relation、--raw、--not-correct-relation以外のオプションは無視します"
    print u"--order-relation このオプションを指定すると履歴を関連度順に取得します。-qで空でないクエリを指定したときのみ有効です。"
    print u"--start=<num> 取得する履歴のオフセットを指定します。-qに空でないクエリを指定し、かつ--order-relationを指定したときのみ有効です。"
    print u"--raw このオプションを指定すると、Google Web Historyから取得した履歴をそのまま出力します。指定しない場合は、タイトルやURLから不要なページを推測し、それを除去します。"
    print u"--not-correct-relation このオプションを指定するとクエリのIDから単純に判断できないクエリと検索結果の対応の推測を行いません。オプションを指定しない場合は、この推測を行います。"
    
if __name__ == '__main__':
    print sys.argv
    opts, args = getopt.getopt(sys.argv[1:], ":u:p:s:e:q:l:n:hf:", ["all", "order-relation", "start=", "help", "raw", "not-correct-relation"])
    for o, a in opts:
        if o in ["-h", "--help"]:
            printHelp()
            sys.exit()
    
    user = None
    passwd = None
    startDate=None
    endDate=None
    query = None
    length = length=sys.maxint
    num = 300
    sortedByDate=True
    start=0
    fname = None
    all = False
    raw = False
    correctRelationFlag = True
    
    for o, a in opts:
        print o, a
        if o == "-u":
            user = a 
        elif o == "-p":
            passwd = a
        if o == "-s":
            try:
                startDate = datetime.strptime(a, "%Y%m%d")
            except ValueError:
                startDate = datetime.strptime(a, "%Y%m%d %H:%M:%S")
        elif o == "-e":
            try:
                endDate = datetime.strptime(a, "%Y%m%d")
            except ValueError:
                endDate = datetime.strptime(a, "%Y%m%d %H:%M:%S")
        elif o == "-q":
            query = a
        elif o == "-l":
            length = int(l)
        elif o == "-n":
            num = int(a)
        elif o == "-f":
            fname = a
        elif o == "--all":
            all = True
        elif o == "--order-relation":
            sortedByDate = False
        elif o == "--start":
            start = int(a)
        elif o == "--raw":
            raw = True
        elif o == "--not-correct-relation":
            correctRelationFlag = False
            
    result = getWebHistory(user, passwd, startDate, endDate, all, num, query, sortedByDate, length, start)
    
#    discoverGoogleScholar(result["entries"])
    if not raw:
        result["entries"] = removeNoise(result["entries"])
    
    if correctRelationFlag:
        correctRelation(result["entries"])
    
    #重複した履歴がないか確認
    entries = result["entries"]
    for i in range(0, len(entries) -1):
        d1 = datetime.strptime(entries[i]["date"], "%a, %d %b %Y %H:%M:%S GMT")
        d2 = datetime.strptime(entries[i+1]["date"], "%a, %d %b %Y %H:%M:%S GMT")
        if d1 < d2:
            print entries[i]["title"], entries[i+1]["title"]
            raise Exception("")

    if not fname:
        print json.dumps(result)
    else:
        fo = open(fname, "w")
        fo.write(json.dumps(result, indent=2))
        fo.close()

出力内容

このプログラムでは、取得した履歴のデータをJSON形式で出力します。

出力内容は、履歴の取得時に指定した条件と履歴のデータです。

履歴データの持つ情報は、履歴の種類によって異なります。

トップレベルの出力(187行目付近を参照)
  • user:ユーザ名
  • date:ダウンロード日時
  • entries:履歴データ
  • query:クエリ
  • all:全ての履歴を取得したか否か
  • start:取得開始位置
  • sortedByDate:
  • startDate:履歴の取得するときの日時の下限値
  • endDate:履歴の取得するときの日時の上限値
履歴データについて
  • id
  • title:閲覧ページ名、クエリ
  • link:閲覧ページや検索結果ページのURL
  • date:閲覧日時、検索実行日時
  • description:不明
  • category:閲覧データの種類
    • XXX query:検索クエリ(XXXにはweb, map, imagesなどが入る)
    • XXX result:検索結果中で閲覧したページ(XXXにはweb, map, imagesなどが入る)
      • queryId:検索クエリのID
    • browser result:進む・戻る、ブックマークからのページアクセスなどのブラウザ操作によるページ閲覧
    • bookmark:browser resultの内、Google Bookmarkに登録されているページへのアクセス
      • bkmk:
      • bkmkId
      • bkmkLabels:タグ
      • bkmkTitle:ブックマーク名

プログラム勉強生プログラム勉強生 2009/12/07 10:03 こんにちわ。
google の情報をこのような形で抜き出せるなんてしらず、感動しました。笑
しかし、現在、Web履歴のRSSのサーバは死んでいるようで、使えないのですが、
これはどういうことなのでしょうか?
このプログラムを走らせると502エラーを吐きます。
今日で5日目くらいです。
GoogleWeb履歴RSSサーバは落ちたのでしょうか?
分かる範囲で教えてくただけると勉強に成ります。
宜しくお願い致します。

hippuhippu 2009/12/08 02:44 こんにちは。

不具合の指摘してくださり、ありがとうございます。
指摘を頂くまで、全然気づきませんでした。自分にとって、このプログラムが動作しないと遠くない将来困るので、非常に助かりました。

さて本題の不具合の原因ですが、GoogleのRSSサーバが死んでいる訳ではなく、Cookieによる認証をしていなかったためと考えています。そのため、認証失敗を表す401のUnAuthorizedエラーになり、副次的に502エラーをGoogleは吐いたのでしょう。

この不具合を修正したプログラムと、もう少し詳細な原因考察は、下記のURLに記載したので、そちらを見て頂ければ幸いです。http://d.hatena.ne.jp/hippu/20091207/1260206750

プログラム勉強生プログラム勉強生 2009/12/09 01:26 めっちゃ詳しく書いて頂き有り難う御座いました。
大変勉強になりました。

ちょいちょい、見させて頂いております。
また、気になることがあったら書き込むかもしれませんが、
その時は相手して下さいね。笑