PythonでFirefox3の検索履歴にアクセスする

firefox3の検索バーに出てくる履歴の正体はsqliteで管理されたデータらしい。winXPでは、%APPDATA%\Mozilla\Firefox\Profiles\xxxxxxxx.default\formhistory.sqlite
(xxxxxxxxはランダム)のmoz_formhistoryテーブルが直接対応している。

$ sqlite3 formhistory.sqlite
sqlite> select * from moz_formhistory;
....(出力)

これで確認できる。

formhistory.sqliteには検索バーからの検索されたキーワードだけでなく、googleのページから検索されたキーワードも記録されていた。Pythonにはsqlite3を扱うモジュールがある。ってことであわせて使ってみた。今のところwinXPのPython2.5.2でしか動作確認していないのでlinuxで動くかどうか分からない。それでも、データベースへの適切なパスを変数dbpathに代入すれば使えるはず。windows98,Meもプロファイルの場所が違うのでdbpathを書き換える必要がある。

参考資料:
プロファイル http://support.mozilla.com/ja/kb/Profiles
プロファイルフォルダの構成 http://support.mozilla.com/ja/kb/%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AE%E6%A7%8B%E6%88%90

#! /bin/python
# coding: sjis

import sys
import os
import sqlite3
from glob import glob

dbname = "formhistory.sqlite"
profpat = "????????.default"
# フォームの履歴を保持するsqliteデータベースのパスを判別
pf = sys.platform
if pf == "win32":
    dbpath = os.environ["APPDATA"] + "\\Mozilla\\Firefox\\Profiles\\"
    dbpath = glob(dbpath+"\\"+profpat)[0] + "\\" + dbname
elif pf == "linux":
    dbpath = "~/.mozilla"
    dbpath = glob(dbpath+"/"+profpat)[0] + "/" + os.listdir(dbpath)[0] + "/" + dbname
# ここまでに変数dbpathにデータベースへのパスをバインドしておく

def querywords():
    # 検索ワードをリストで返す
    conn = sqlite3.connect(dbpath)
    curs = conn.cursor()
    ncurs = curs.execute("select value from moz_formhistory where fieldname='q' or fieldname='searchbar-history'")
    ws = [x[0] for x in ncurs.fetchall()]
    conn.close()
    return ws

def frequency_dictionarize(lst):
    # {単語: 出現回数}の辞書にする関数
    # 英字は小文字化する
    d = {}
    for n in lst:
        keys = n.lower().split()
        for k in keys:
            if d.has_key(k):
                d[k] += 1
            else:
                d[k] = 1
    return d
def trans(dic):
    # {単語:出現回数}の辞書を{出現回数:単語}にする
    d = {}
    for k in dic.keys():
        freq = dic[k]
        if d.has_key(freq):
            d[freq].append(k)
        else:
            d[freq] = [k]
    return d

def main():
    ws = querywords()

    fdict = frequency_dictionarize(ws)
    tdict = trans(fdict)

    # 回数の多い順から内容を表示
    for k in sorted(tdict.keys(), lambda x,y: cmp(int(y),int(x))):
        print k,"|",
        for n in tdict[k]:
            print n,
        print ""
if __name__ == '__main__':
    main()
    

実行結果

343 | python 
168 | haskell 
128 | cygwin 
118 | c言語 
85 | ruby 
83 | windows 
79 | c 
75 | 2ch 
74 | c++ opengl 
57 | scheme 
54 | google 
44 | firefox 
41 | java 
40 | mac 
36 | meadow mini 
34 | unix インストール 
32 | 和英 eeebox 
31 | linux 
30 | eclipse rails 
29 | django 
28 | thinkpad glut 
27 | プログラミング 
26 | 英和 
25 | emacs 
24 | hopengl tkinter 
23 | r31 
22 | yahoo mysql 数学 podcast 
21 | ダウンロード gui iphone フォント コマンド 
20 | the eeepc901 chrome 
19 | itunes sqlite 設定 
18 | ライブラリ ghc lisp fedora ニュートン法 
17 | eeepc プログラム マニュアル on 
16 | dell gcc 
.. (大幅に略)

このプログラムとデータをもとにグラフを書くと面白いかもしれない。あとは、、家族や学生同士で共有しているPCで使うと見てはいけないものが見えるかもしれない。

特徴的だったのは4300ぐらいある単語のうち、2800語ぐらいは1度しか検索されていなかったことで、出力の6割以上が1度しか検索していない単語のリストでかなり長い。その多くは長いキーワードとtypo、それと、単純にあまり調べない事柄に関するキーワードだ。例えば、「無線lan環境に必要なもの」とか、「makeifle」とか(makefile)。

typoが面白い。

謎の検索ワードたち

  • 退院具
  • oidon
  • バス飽和
  • マルチスレッド朝青龍

マルチスレッド朝青龍って何だ。

(追記:9/13)
Google Chromeでは、C:\Documents and Settings\%USERNAME%\Local Settings\Application Data\Google\Chrome\User Data\Default\Historysqliteデータベースになっていて、このデータベースのkeyword_search_termsが履歴を管理するテーブルでした。windowsの場合はこちらも参照して集計するともっと面白いかも。