2012年2月12日日曜日

HTTPリクエストパラメータを抽出する

テストケースのないシステムをメンテンナンスをすることもあると思います。 HTTPで提供するAPIのテストケースを作成しなければならない場合は、 とにかくログを投げまくってテストするなどの方法が有効だったりするんですが、 (まあそもそもテストケースがないシステムについてのツッコミは受け付けません) ログから有効なテストケースを抽出するために、 リクエストパラメータの組み合わせによるURLの抽出なんかが一つの案です。 ということでログからリクエストパラメータの抽出を行うスクリプトをざっくり書いてみました。

import sys
from collections import defaultdict
from furl import furl

sampling_urls = defaultdict(dict)

for line in sys.stdin:
    url = line.strip()
    f = furl(url)
    param_keys = tuple(sorted(f.args.keys()))
    param_combination = sampling_urls[str(f.path)]
    if param_keys not in param_combination:
        param_combination[param_keys] = url

for path, param_combination in sampling_urls.items():
    for combination, sample_url in param_combination.items():
        print path, combination, sample_url

インプットログ
http://xxx/api?param1=a&param2=a
http://xxx/api?param1=b&param2=b
http://xxx/api?param1=c&param2=c&param3=c
http://xxx/api?param1=d&param2=d&param3=c
http://xxx/api?param1=e&param2=d&param4=d
http://xxx/api2?param1=e&param2=d&param4=d
http://xxx/api3?param1=e&param2=d&param4=d
実行結果
$ python sampling.py < input 
/api2 ('param1', 'param2', 'param4') http://xxx/api2?param1=e&param2=d&param4=d
/api ('param1', 'param2', 'param3') http://xxx/api?param1=c&param2=c&param3=c
/api ('param1', 'param2', 'param4') http://xxx/api?param1=e&param2=d&param4=d
/api ('param1', 'param2') http://xxx/api?param1=a&param2=a
/api3 ('param1', 'param2', 'param4') http://xxx/api3?param1=e&param2=d&param4=d
前に記事に書いたfurlというurlパーサーを利用しています。 itertools.combinationsとかを使わないとできないかと思いましたが、 tupleを辞書のキーにすることで簡単にできました。 valueが空の時の処理などは必要に応じて作成する必要がありますが、 それなりに有効そうです。

2012年1月30日月曜日

furlを使ってみた

ブログを久しく書いていないので、ライブラリの覚書を少しずつ書くことにする。

最近少し話題になったfurlについて使い方を簡単に書いておく。

インストールはいつものように
easy_install furl
pip install furl
でできる。

使ってみたログを書いてみる
>>> from furl import furl
>>> url = furl("http://pypi.python.org/pypi?%3Aaction=search&term=test&submit=search")
>>> url.host
'pypi.python.org'
>>> url.port
80
>>> url.query
Query('term=test&%3Aaction=search&submit=search')
>>> url.query.params
{'term': 'test', ':action': 'search', 'submit': 'search'}
>>> url.args
{'term': 'test', ':action': 'search', 'submit': 'search'}
cgi.parse_qsとかよりは結構使いやすい気がするが一点気になることが・・・
>>> url = furl("http://pypi.python.org/pypi?%3Aaction=search&term=test&submit=search&term=test2")
>>> url.args
{'term': 'test', ':action': 'search', 'submit': 'search'}
>>> url.query.params
{'term': 'test', ':action': 'search', 'submit': 'search'}
リクエストパラメータに同じキーのものが複数入っていた場合、
どちらか一方しかargsに入らない。

HTTPの仕様では同じキーに別の値を入れることができて、
サーバ側では配列で受け取れるようになっているのだとばっかり。

そのようなリクエストは、このままでは正しくparseできない。(やり方発見できず)
簡単に使えるし、良い感じなだけに惜しいなー。