Python3 で Webスクレイピング (python3 + scrapy1.1)

  • 82
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Python3 のスクレイピングライブラリ

ネットで調べると情報が多すぎてどのライブラリを使うのが最適なのか迷ってしまいます。まずは今どのようなライブラリがあるのか、主要なものだけリストアップしてみました。

ライブラリ名
フレームワーク scrapy
HTTPリクエストを行うライブラリ requests
htmlパーサのライブラリ lxml
HTMLを解析するライブラリ beautifulsoup4 / pyquery

このリストから考えると、想定しうる組み合わせは

  1. requests + beautifulsoup4 ( + lxml )
  2. requests + pyquery
  3. scrapy

という感じになりそうです。

beautifulsoup 4 系は htmlパーサを選べるようになったので、パーサに lxml を使うことでより高速に処理できるそうです。
pyquery は jQuery ライクのセレクタを使えるライブラリで、内部では lxml が使われているらしい。
scrapy は 今年 (2016年) 5月に公開された バージョン 1.1 でようやく python3 に対応したそうです。
scrapy はフレームワークなのでサクッと書くには向かないんじゃないかと思えますが、1ファイルだけ書いて軽く使ってみることもできるようです。
今回リストアップしませんでしたが、mechanize というスクレイピングライブラリがかつて有ったそうです。python3 には未対応で、もう開発が止まってるっぽい。

上記を踏まえて、今回はチャレンジのつもりで python3 に対応したばかりの scrapy 1.1 を使って Webスクレイピングしてみることにしました。

動作検証バージョン

今回の手順を検証するにあたって導入した各ソフトウェア / ライブラリのバージョンは以下の通りです。

Version
OS Amazon Linux AMI 2016.03.3 (ami-374db956)
python 3.5.2
scrapy 1.1.0

各ソフトウェアのインストール

python3 のインストール

手順は省略します。

scrapy のインストール

pip install scrapy

※途中でインストールに失敗した場合、本記事の一番下に書いた Appendix を読んでみてください。

ここから先は公式のチュートリアル ↓ に従って進めてみます。
http://doc.scrapy.org/en/latest/intro/tutorial.html

プロジェクトひな形の作成

scrapy startproject tutorial

上記コマンドを実行すると、以下のようなファイル群が作成されます。

tutorial
  - scrapy.cfg
  - tutorial
    - __init.py__
    - items.py
    - pipelines.py
    - __pycache__
    - settings.py
    - spiders
      - __init.py__
      - __pycache__

スパイダーの作成と修正

スパイダーの自動生成

プロジェクトディレクトリ内に入り genspider コマンドを使ってスパイダーファイルを作成します。
公式チュートリアルでは dmoz.org を例にしているので、本記事でも dmoz.org を例に使います。

cd tutorial
scrapy genspider dmoz_spider dmoz.org

これでspiders ディレクトリの下に ↓ のようなファイルが自動生成されたはずです。

dmoz_spider.py
# -*- coding: utf-8 -*-
import scrapy


class DmozSpiderSpider(scrapy.Spider):
    name = "dmoz_spider"
    allowed_domains = ["dmoz.org"]
    start_urls = (
        'http://www.dmoz.org/',
    )

    def parse(self, response):
        pass

※genspider を実行する際のカレントディレクトリは、プロジェクトディレクトリの下だったらどこでもいいみたいです、たぶん。

スパイダーの修正

自動生成されたスパイダーをそのまま実行しても何も取得できません。parse 関数の中身にコードを書く必要があります。
公式のチュートリアルにはその見本があるのですが、掲載されている内容は少し古いらしく、そのままコピペしても dmoz.org の内容をうまく取得できませんでした。
(以前は <ul><li>を指定してリストを取得できたようですが、今は dmoz.org のページ構成が変わってしまっているようです)

ですので、僕はサンプルコードを少し改変し、dmoz_spider.py を以下のように修正しました。

dmoz_spider.py
# -*- coding: utf-8 -*-
import scrapy

class DmozSpiderSpider(scrapy.Spider):
    name = "dmoz_spider"
    allowed_domains = ["dmoz.com"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
    ]

    custom_settings = {
        "DOWNLOAD_DELAY": 0.5, #0.5秒ごとにクロール
    }

    def parse(self, response):
        for sel in response.xpath("//div[@class='title-and-desc']"):
            title = sel.xpath("a/div[@class='site-title']/text()").extract()
            link = sel.xpath('a/@href').extract()
            desc = sel.xpath("/div[@class='site-descr ']/text()").extract()
            print (title, link, desc)

クロール実行

crawl コマンドで作成したスパイダーファイルを指定すると、クローラが実行されます。

scrapy crawl dmoz_spider

上記コマンドを実行すると、改行コード等がたくさん混じってやや不格好ではありますが、title、link、desc の一覧を取得できました。

['Core Python Programming ']
['http://www.pearsonhighered.com/educator/academic/product/0,,0130260363,00%2Ben-USS_01DBC.html']
['\r\n\t\t\t\r\n By Wesley J. Chun; Prentice Hall PTR, 2001, ISBN 0130260363. For experienced developers to improve extant skills; professional level examples. Starts by introducing syntax, objects, error handling, functions, classes, built-ins. [Prentice Hall]\r\n ', '\r\n ']
(以下省略)

取得したい要素を抽出する方法

セレクタを指定するメソッドには xpath と css の2つがあります。どちらを使っても、HTML中の要素を同じように抽出することができます。
例えば、HTML 中の <title> の本文を抽出したい場合、xpath では '//title/text()'、css では 'title::text' と指定します。

>>> response.xpath('//title/text()')
[<Selector (text) xpath=//title/text() data='xxx'>]

>>> response.css('title::text')
[<Selector xpath='descendant-or-self::title/text()' data='xxx'>]

xpath / css メソッドの書き方

1) 全ての <a> タグの href 属性を抽出

>>> response.xpath('//a/@href').extract()
['http://example.com/']

>>> response.css('a::attr(href)').extract()
['http://example.com/']

2) src属性 に「image」という文字列が含まれる全ての <img> タグの、src 属性 を抽出

>>> response.xpath('//img[contains(@src, "image")]/@src').extract()
['image1.png',
 'image2.jpg',
 'image3.gif']

>>> response.css('img[src*=image]::attr(src)').extract()
['image1.png',
 'image2.jpg',
 'image3.gif']

3) class属性 が「description」 という文字列である全ての <div> タグの、本文を抽出

>>> response.xpath("//div[@class='description']/text()").extract()
['abcdefg']

>>> response.css("div[class*='description']::text").extract()
['abcdefg']

抽出結果の検証

shell コマンドを使うと指定したページのデータ抽出結果を検証することができます。

scrapy shell "(取得したいページURL)"

上記コマンドを実行すると、以下のようなメッセージが表示され、インタラクティブシェルが起動します。

[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser
>>>

インタラクティブシェル起動後に、response.xpath … というようにコマンドを打つと、その抽出結果を検証することができます。

Appendix

必要なライブラリが不足していると scrapy のインストールに失敗します。僕が遭遇したエラーを2つ紹介しますので、ご参考まで。

インストールエラー 1

scrapy をインストールするには Twisted というライブラリの 10 以上が必要です。
Twisted を入れずに scrapy を入れようとすると以下のエラーが出ます。

Could not find a version that satisfies the requirement Twisted>=10.0.0 (from scrapy) (from versions: )
No matching distribution found for Twisted>=10.0.0 (from scrapy)

Twisted のインストール方法

cd /tmp
wget https://pypi.python.org/packages/source/T/Twisted/Twisted-16.1.1.tar.bz2
tar -xjvf Twisted-16.1.1.tar.bz2
cd Twisted-16.1.1
python setup.py install

インストールエラー 2

scrapy は lxml を内部で使っているので、それを実行するのに必要な libxml2 や libxslt が無いと以下のようなエラーが出て、インストール失敗します。

Could not find function xmlCheckVersion in library libxml2. Is libxml2 installed?

以下の手順で必要なライブラリをインストールしておきましょう。

sudo yum install libxml2-devel
sudo yum install libxslt-devel

以上です。