Scrapyをインストールしてバックグラウンドでスクレイピングするまで

1. Python2.7とpipのインストール

まずはPythonをソースからインストールします。

$ yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel
$ cd /usr/local/src
$ wget https://www.python.org/ftp/python/2.7.11/Python-2.7.11.tgz
$ tar xvfz Python-2.7.6.tgz
$ cd Python-2.7.6
$ ./configure --prefix=/usr/local
$ make
$ make altinstall

次にpipのインストールです。easy_installでpipを入れることもできますが、今では下記のコマンドで一発でpipを入れることができます。

$ curl -kL https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python

また、easy_installを使ってpipをインストールする方法は以下の通りです。easy_installを使うのにsetuptoolsではなくdistributeを利用しています。

$ wget http://pypi.python.org/packages/source/d/distribute/distribute-0.6.27.tar.gz
$ tar zxvf distribute-0.6.27.tar.gz
$ cd distribute-0.6.27
$ sudo python2.7 setup.py install
$ easy_install-2.7 pip

2. Scrapyのインストール

次にpipを使ってscrapyをインストールします。

$ pip install scrapy
    Compile failed: command 'gcc' failed with exit status 1
    creating tmp
    cc -I/usr/include/libxml2 -c /tmp/xmlXPathInitacjqEE.c -o tmp/xmlXPathInitacjqEE.o
    /tmp/xmlXPathInitacjqEE.c:1:26: error: libxml/xpath.h: そのようなファイルやディレクトリはありません
    *********************************************************************************
    Could not find function xmlCheckVersion in library libxml2. Is libxml2 installed?
    *********************************************************************************
    error: command 'gcc' failed with exit status 1

エラーですね。依存関係をクリアできなかったみたいです。libxml/xpath.hがないとのことなのでインストールします。

$ yum -y libxslt-devel

これで再度インストールすればうまくいきました。

$ pip install scrapy

3. Scrapyを使ってみる

Scrapyを使う簡単な流れは以下のようになります。

1. Scrapy プロジェクトの作成
2. 基本設定と抽出するアイテムの定義
3. スクレイピング&クロール用のSpider作成
4. 抽出したアイテムのパイプライン処理作成

3-1. Scrapy プロジェクトの作成

scrapyコマンドを使うことでプロジェクトを作成できます。プロジェクト名は英数字またはアンダースコアしか使えないので注意です。

$scrapy startproject sample_crawler

すると以下のようなディレクトリが作成されます。

sample_crawler/
├ sample_crawler
│ ├ __init__.py
│ ├ items.py
│ ├ pipelines.py
│ ├ settings.py
│ └ spiders
│    └ __init__.py
└── scrapy.cfg

ここで主に編集するのは、以下のファイルです。

items.py      データ保存のためのクラス
settings.py   基本的な設定
pipelines.py  抽出データの出力先を指定
spiders/      spiderのディレクトリ

3-2. 基本設定と抽出するアイテムの定義

settings.pyでクローラーの設定をすることができます。今回はサンプルなので、以下の部分のみ変更しました。

DOWNLOAD_DELAY=5
BOT_NAME = 'samplespider'

*settings.pyの詳しい設定内容はScrapyの公式ドキュメント:
http://doc.scrapy.org/en/latest/topics/settings.html

また、クロールで抽出するアイテムをitem.pyで定義します。以下はURLとタイトルを取得する例です。

# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy

class CrawlerItem(scrapy.Item):
    # define the fields for your item here like:
    URL = scrapy.Field()
    title = scrapy.Field()
    pass

3-3. スクレイピング&クロール用のSpider作成

scrapyコマンドでspiderのテンプレートを作成します。

$ scrapy genspider -t crawl sample_spider example.com

すると、spiders/以下にsample_spider.pyというファイルが作られていると思います。以下は簡単なサンプルです。

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy.selector import Selector
from crawler.items import CrawlerItem

class BaseSpider(CrawlSpider):
    name = 'sample_spider'
    # スクレイピングするドメインを指定します
    allowed_domains = ['example.com']

    # スクレイピングを開始するURL
    start_urls = ['http://example.com/']

    # ドメイン以下のURLに関して正規表現で指定します
    # /123など数字が連続しているURLはスクレイピングします
    allow_list = ['/\d+']
    # category, tag, pageなどが含まれるページはスクレイピングしません
    deny_list = ['category', 'tag', 'page']

    rules = (
        # スクレイピングするURLのルールを指定
        # parse_item関数がコールバック
        Rule(LinkExtractor( allow=allow_list, deny=deny_list ), callback='parse_item'),

        # spiderがたどるURLを指定
        # 今回はallowed_domainsの場合は全てたどります。
        Rule(LinkExtractor(), follow=True),
    )

    def parse_item(self, response):
        i = CrawlerItem()
        selector = Selector(response)
        i['URL'] = response.url
        i['title'] = selector.xpath('/html/head/title/text()').extract()
        return i

3-4. スクレイピングの実行

以下のコマンドでスクレイピングを実行します。実行結果は、test.csvに出力されます。

$ scrapy crawl sample_spider -o test.csv

クロールをはじめると、以下のような表示がされます。

▼クロール除外時
2015-12-11 16:21:46 [scrapy] DEBUG: Filtered offsite request to 'www.not-target.com': 

▼クロール時
2015-12-11 16:21:49 [scrapy] DEBUG: Crawled (200)  (referer: http://sample.com/)

また、ターミナルを閉じてでもバックグラウンドで実行したい場合は、nohupコマンドで使います。以下はバックグラウンドで実行し、title.csvに実行結果を吐き出す例です。

$ nohup scrapy crawl sample_spidersimple -o titles.csv &
  [1] 11564
  nohup: ignoring input and appending output to `nohup.out'

実行結果は以下のコマンドで確認できます。

$ tail -f nohup.out

【参考】
Scrapy 1.0が公開されました
ScrapyでWebサイトのタイトルとURLを再帰的に取得する
scrapy を用いてデータを収集し、mongoDB に投入する

TreeTaggerをインストールしてPython2.7で英語の形態素解析をしてみた

英語の形態素解析をするにあたり、TreeTaggerをいれてみました。

NLTK、Stanford NLPというのもあるそうなのですが、なんとなくTreeTaggerを選んでみました。

TreeTaggerをインストール

/usr/local/srcにインストールする場合の例です。
公式サイトから必要なものをダウンロードしてインストールします。

$ cd /usr/local/src
$ mkdir tree-tagger
$ cd tree-tagger/
# TreeTaggerのインストールに必要なものをダウンロード
$ wget http://www.cis.uni-muenchen.de/~schmid/tools/TreeTagger/data/tree-tagger-linux-3.2.tar.gz
$ wget http://www.cis.uni-muenchen.de/~schmid/tools/TreeTagger/data/tagger-scripts.tar.gz
$ wget http://www.cis.uni-muenchen.de/~schmid/tools/TreeTagger/data/english-par-linux-3.2-utf8.bin.gz
# インストール用シェルスクリプトをダウンロード
$ wget http://www.cis.uni-muenchen.de/~schmid/tools/TreeTagger/data/install-tagger.sh
# パーミッションを変更してシェルスクリプトを実行
$ chmod u+x install-tagger.sh
$ ./install-tagger.sh

必須ではないですが、.bashrcに追記をしてパスを通しておきます。

$ vi ~/.bashrc
    #以下の内容を追記
    PATH="$PATH":/usr/local/src/tree-tagger/cmd
    PATH="$PATH":/usr/local/src/tree-tagger/bin
$ bash

以下が実行できればOKです。

$ echo 'Hello world!' | tree-tagger-english 

PythonでTreeTaggerを使う方法

TreeTaggerには有志の人が作成したPythonラッパーがあるのでそれを利用します。

$ pip install treetaggerwrapper

pipでのインストールが成功したら、Pythonから使えることを確かめてみます。

$ echo "This is the sentence." | python -m treetaggerwrapper --pipe --debug

  ERROR Failed to find TreeTagger from automatic directories list.
  ERROR If you installed TreeTagger in a standard place, please contact the treetaggerwrapper author to add this place to this list.
  ERROR To continue working, setup TAGDIR env var to TreeTagger directory.
  ERROR Can't locate TreeTagger directory (and no TAGDIR specified).

TreeTaggerがインストールされているディレクトリが見つからなかったよとのことです。

TreeTaggerWrapperのドキュメントによると、TreeTageerオブジェクトに引数でTAGDIRを指定して渡せば良いそうなので下記のようなexample.pyを作成して実行してみます。

import treetaggerwrapper
tagger = treetaggerwrapper.TreeTagger(TAGLANG='en',TAGDIR='/usr/local/src/tree-tagger')
tags = tagger.TagText("This is the sentence.")
for tag in tags:
    print tag

スクリプトを実行。

$ python example.py

すると、以下のようなエラーが発生。Unicodeじゃないとダメだよってことらしいです。

treetaggerwrapper.TreeTaggerError: Must use *unicode* string as text to tag.

Python3だとデフォルトがUnicodeらしいのですが、Python2の場合はu”string”というように「u」をつけてあげる必要があります。

なので、先ほどのスクリプトを以下のように変更します。

tags = tagger.TagText(u"This is the sentence.")

そして、実行。

$ python example.py
  This      DT   this
  is        VBZ  be
  the	    DT   the
  sentence  NN   sentence

うまく形態素解析ができました。

TreeTagger公式サイト