アクセスログ解析ソフトは検索キーワードを抽出してくれるものが多いのですが、このアルゴリズムというかパターンはどうなっているのかと思って探ってみました。

読んだコードは Vistors です。C言語で書かれています。

まずは Referrer を取り出す

アクセスログに検索キーワードが隠れているのは Referrer の部分です。 まずはこいつをどうやって抜き出すかですが、たいして難しいことはありませんので、これは Visitors に頼らなかったです。

awk でも python でも良いのでデリミタを指定して簡単に行をワードへ分割できる言語を使ってください。 自前のアプリケーションでもログを行単位に取り出して分割するロジックを書けば良いだけです。

サンプルコード: AWK で Referrer を抽出する

Apache の combined のアクセスログから AWK で Referrer を取り出すサンプルコードです。 セパレート フィールドに " を設定して4番めのフィールドを print します。

awk -F '"' '{print $4}' /var/log/apache2/httpd-access.log > ref.txt

いざ抽出

とりあえず検索キーワードのリクエスト パラメータを知らなければなりません。

Google なら q 、Yahoo! だと p です。検索エンジン毎に違うので自力で発見するか、 Analog で使う SearchQuery.txt で調べます。

Visitors の手法

Visitors は解析対象の検索エンジンが Google だけなのでロジックは短めでした。 該当の関数は vi_process_google_keyphrases() です。

Referrer 文字列から ?q=&q= の位置を探して、その位置から +3 文字目を検索キーワードの開始とみなします。 http://www.google. の文字数 18 を足してから、パラメータの位置を探しています。

if ((s = strstr(ref+18, "?q=")) == NULL &&
        (s = strstr(ref+18, "&q=")) == NULL) return 0;

検索キーワードの終了位置は検索キーワードの開始位置の次に & が出現する位置か、Referrer 文字列の終了位置になります。

if ((e = strchr(s+3, '&')) != NULL)
    *e = '\0';

そして最後に検索キーワード開始位置と終了位置の部分を URL デコードしてます。

vi_urldecode(urldecoded, s+3, VI_LINE_MAX);

http://www.google. の文字数 18 というのは、リファラが Google であるかどうかを判定するための情報で、 通常ならリファラのホスト名を解析して www.google. とマッチするレコードだけを処理するでしょう。 おそらく処理速度を上げるために、このような仕様にしたのだと思われます。

実際にやってみる

Python で書いたコードです。自前のツールからの抜粋なので注釈を付けておきます。Visitors を真似たものです。

#
# _google_link_len = len("http://www.google.")
# ref = referrer 文字列
#

# search query start position
s = ""
if string.find(ref, "&q=", _google_link_len) is not -1:
    s = string.find(ref, "&q=", _google_link_len) + 3
elif string.find(ref, "?q=", _google_link_len) is not -1:
    s = string.find(ref, "?q=", _google_link_len) + 3
else:
    return None

# end of search query position
e = ""
if string.find(ref, "&", s) is not -1:
    e = string.find(ref, "&", s)
else:
    e = len(ref)

q = ref[s:e]
keyphrase = string.replace(urllib.unquote(q), "+", "") # URL デコードと + 文字を削除
keyphrase = keyphrase.strip()
keyphrase = unicode(keyphrase, "utf8", "replace") # Unicode object


最終更新日: 2015年05月16日(土)

Back to top