Pythonでpyqueryパッケージを用いて、ウェブスクレイピングを行う方法をご紹介する。ウェブ上には様々なデータがあるが、必要なデータがいつもファイルとしてダウンロードできるとは限らない。ここでご紹介する方法は、htmlファイルを直接解析して、必要な情報を取得するという方法である。

それでは、さっそく見ていこう。

Ubuntu 16.04LTSの場合の準備

Ubuntu 16.04では、python3系がデフォルトになった。そして、このpyqueryパッケージが標準のリポジトリに入ったので、次のコマンドでインストールが完了する。


$ suto apt-get install python3-pyquery

Ubuntu 14.04LTSの場合の準備

まずはPythonパッケージ管理ソフトのpipをインストールする。UbuntuではPython2系とPython3系ではアプリケーションが異なるので注意する。ここでは、Python3系のpipをインストールする。


$ sudo apt-get install python3-pip

次にpyqueryを使うために必要なライブラリをインストールする。


$ sudo apt-get install libxml2-dev
$ sudo apt-get install libxslt1-dev
$ sudo apt-get install zlib1g-dev

最後に、pip3を用いてpyqueryをインストールする。pyqueryはlxmlを使用しているので、lxmlをインストールした後、pyqueryをインストールする。


$ sudo pip3 install lxml
$ sudo pip3 install pyquery

これで、pyqueryを使用する準備が整った。
ちなみに、このpip3コマンドでインストールしたパッケージは「/usr/local/lib/python3.4/dist-packages/」ディレクトリに配置される。

pyqueryを用いてウェブスクレイピング

さて、ここからは実際にpyqueryを用いてウェブスクレイピングを行う。

ここでは例として、CRANパッケージのサイト「Table of available packages, sorted by date of publication 」から公開日、パッケージ名、URL、タイトルを抽出してみる。取得する情報は<table>で囲まれているので、各<tr>を抽出した後に<td>を見ていけばよい。


import urllib.request
from pyquery import PyQuery as pq

if __name__ == '__main__' :
    # Htmlファイル取得
    opener = urllib.request.build_opener()
    request = urllib.request.Request('http://cran.r-project.org/web/packages/available_packages_by_date.html')
    html = opener.open(request).read()

    for tr_node in pq(html).find('tr'):
        # tdノード取得
        td_nodes = pq(tr_node)('tr').find('td')
        # 公開日取得
        published = td_nodes.eq(0).text()
        # パッケージ名取得
        name = td_nodes.eq(1).text()
        # URL取得
        url = td_nodes.eq(1).find('a').eq(0).attr('href')
        # タイトル取得
        title = td_nodes.eq(2).text()
        # 表示
        if published and name and url and title:
            print(published + '\t' + name + '\t' + url + '\t' + title)

上記のコードを「test.py」として保存してPython3.4で実行してみる。


$ python3.4 test.py

結果は以下のように表示される。


2014-09-17	EntropyEstimation	../../web/packages/EntropyEstimation/index.html	Estimation of Entropy and Related Quantities
2014-09-17	fCopulae	../../web/packages/fCopulae/index.html	Rmetrics - Bivariate Dependence Structures with Copulae
2014-09-17	gamlss.dist	../../web/packages/gamlss.dist/index.html	Distributions to be used for GAMLSS modelling
2014-09-17	geostatsp	../../web/packages/geostatsp/index.html	Geostatistics using SpatialPoints and rasters
2014-09-17	simsalapar	../../web/packages/simsalapar/index.html	Tools for Simulation Studies in Parallel with R
2014-09-17	yuima	../../web/packages/yuima/index.html	The YUIMA Project package for SDEs
2014-09-16	berryFunctions	../../web/packages/berryFunctions/index.html	function collection related to hydrology, zooming and shapefiles
2014-09-16	compute.es	../../web/packages/compute.es/index.html	Compute Effect Sizes

簡単に解説すると、「pq(html).find(‘tr’)」の部分で、htmlファイルの中から<tr>の一覧を作成して、「pq(tr_node)(‘tr’).find(‘td’)」の部分で、取り出した一つの<tr>内の<td>の一覧を取得して、「td_nodes.eq(0).text()」の部分で、<td>の最初のノードのテキストを取得している。

find関数の引数は文字列でcssのように指定して抽出する。例えば、<a>のみを抽出したければ、「find(‘a’)」とすればよいし、<div class=”test”>内の<p>を抽出したければ、「find(‘div.test p’)」とすればよい。

ウェブスクレイピングの注意点

ここで、ウェブスクレイピングの注意点を述べておきたい。上記の例では一つのサイトのhtmlファイルを取得したのみだが、取得したURLを元に次々とhtmlファイルを取得することも容易だ。その際に、一時停止処理を組み込むことを忘れてはいけない。

もし、一時停止処理を組み込まなければ、1秒間に何十回もアクセスすることになり、相手サーバに多大な負荷を掛けてしまう。htmlファイルを取得したら、次のhtmlファイルを取得するまでに、最低でも1秒以上の間隔を設けるようにした方がよい。もちろん、間隔は長ければ長い方がよい。

一時停止処理はわずか2行で済む。Pythonファイルの最初に「import time」を追加して、一時停止したい箇所に「time.sleep(1)」を追加するだけだ。time.sleep(1)は1秒間の一時停止、time.sleep(60)は1分間の一時停止、一時停止したい秒数をtime.sleep関数の引数に指定する。

最後に

pyqueryを用いれば、ウェブスクレイピングを簡単に行うことができることがお分かりいただけたと思う。節度を守りつつ、効率よくウェブ上のデータを取得する手助けとなれば幸いだ。

Python pyqueryを用いて簡単にウェブスクレイピング