一日に何度も検索を実行しますが、そのたびに特定サイトの検索窓で文字を入力するのは結構手間がかかります。
例えば、書評サイトで気になった本を図書館で蔵書があるか、貸し出し可能か、あるいは書店の在庫を調べる場合、複数の本を一つ一つ繰り返し図書館や書店の検索ページで調べるのは面倒です。
そこで、Python標準モジュールを利用して、検索語をファイルから読み取らせて検索リクエストを送り、レスポンスから書籍情報などのリンクだけ抜き取って、自分で検索結果HTMLを作成するスクリプトを作成すれば、ファイルに単語を入力するだけで結果が得られます。
必要な手順は、以下の3つです。
- 対象とする検索サイトの検索方式(GET、POST)や文字コードを調べる
- 対象とする検索サイトの結果表示方法を調べ、必要な情報のパターンを調べる
- 検索サイトに合わせたリクエストを作成・テストする
実際の作業の流れは以下のような感じです。
対象とする検索サイトのページソースを確認して文字コードを調べます。続いて検索form要素の周辺を調べます。form要素のmethod、action、POSTなら入力欄の入力内容のnameなどが必要な情報です。
次に、対象のサイトで実際に適当な単語で検索を試し、表示された結果のうち、自分が欲しい検索結果のパターンを探します。基本的にはaタグやimgタグですが、サイト内の別のリンクや画像が当てはまらない、結果のみに当てはまるパターンを見つけます。
ここまで出来たら材料はそろっているので実際のスクリプトを作成します。
まず、単純なGETメソッドにクエリパラメータをつけた場合。
クエリパラメータが一つだけであれば、検索URLを「?パラメータ名=」まで決め打ちして、%エンコードしたパラメータ値を足せば検索URLができます。
クエリパラメータが複数ある場合は、辞書などでパラメータを作ってurlencodeします。
項目 | メソッド等 |
---|---|
import | urllib.parse, urllib.request |
%エンコード | q = urllib.parse.quote('検索語', encoding='文字コード') |
URLエンコード | q = urllib.parse.urlencode('クエリ辞書') |
検索URL | url = 'サイトの検索URL' + q |
検索結果ページ | html = urllib.request.urlopen(url) |
POSTの場合はヘッダー情報のUser-Agentを設定しないと結果が得られなかったり、何度か試しながら必要な情報を探りながら作っていきます。作成中は対象のサーバーに負荷をかけないように、forなどで大量のリクエストを送らないように注意します。
項目 | メソッド等 |
---|---|
検索語 | data = {'入力欄のname': '検索語'} |
%エンコード、バイト化 | data2 = urllib.parse.urlencode(data).encode() |
ヘッダー | h = {'User-Agent': 'agent', 'Content-Length': len(data2)} |
リクエスト | req = urllib.request.Request(url=url, data=data2, method='POST', headers=h) |
検索結果ページ | html = urllib.request.urlopen(req) |
ユーザーエージェントなどのヘッダー情報やブラウザが付加しているPOST情報は、Chromのデベロッパーツールを利用して実際に検索を試した結果のRequestヘッダーを確認して、必要そうなものを足していきます。
結果ページが取得出来たら、一行ずつ取り出して、欲しい結果かどうか確認していきます。正規表現モジュールがとても便利で、だいたい特徴的なタグのパターンを.+でつなぎ、()を使って欲しい部分を囲めば何とかなる場合がほとんどです。
パターンが一致した結果があれば、マッチオブジェクトのgroupで欲しい部分を抜き出し、結果を集めておくリストにappendします。
連続して検索する場合は、timeモジュールを使ってtime.sleep(5)などとして、サーバーに負荷をかけないように間をおいて実施します。
最後に取得したリストを自分用の検索結果表示HTMLに書き込めば完成です。
複数のサイトで同じ単語を検索したい場合は、個々のサイトごとにスクリプトを作ってメソッド化します。そして、それらをimportした検索スクリプトを作成して、そこでファイルから検索語を読み込み、forで検索を繰り返せばまとめて結果を得ることができます。