Scrapy

Scrapy メモ

More than 1 year has passed since last update.

Webページのスクレイピングと分析・可視化で使用したPython製WebクローラScrapyについて覚えたことについて記載する。
本記事はメモ程度の内容であり、情報の正確性については保証しない。必ず公式ドキュメントを参照すること。

サンプルコード

サンプルコード1

import scrapy

class QiitaCalendarSpider(scrapy.Spider):
    name = "qiita_calendar"
    allowed_domains = ["qiita.com"]
    start_urls = ["http://qiita.com/advent-calendar/2016/calendars"]

    custom_settings = {
        "DOWNLOAD_DELAY": 1,
    }

    def parse(self, response):
        for href in response.css('table.table.adventCalendarList tbody tr'):
            calendar_title = href.css('td.adventCalendarList_calendarTitle a::text').extract_first()
            calendar_url = href.css('td.adventCalendarList_calendarTitle a::attr(href)').extract_first()
            calendar_attendees = href.css(
                'td.adventCalendarList_progress span.adventCalendarList_recruitmentCount::text').extract_first()

            yield {
                'calendar_title': calendar_title,
                'calendar_url': response.urljoin(calendar_url),
                'calendar_attendees': calendar_attendees
            }

            for page in response.css('li.hidden-xs a'):
                next_page = page.css('::attr(href)').extract_first()
                if next_page is not None:
                    next_page = response.urljoin(next_page)
                    yield scrapy.Request(next_page, callback=self.parse)

サンプルコード2

    def start_requests(self):
        qiita_calendars = QiitaCalendarLoader()
        for url in qiita_calendars.urls():
            yield scrapy.Request(url=url, callback=self.parse)

コーディング

DOWNLOAD_DELAYは最初に設定するべき

DOWNLOAD_DELAYはクロール毎のインターバル時間を秒単位で設定するプロパティ。これを設定しないと簡単にWebサイトにDoSアタックをかけることになる。絶対に一番最初に設定すること

allowed_domains

必須ではないものの設定推奨。このリストに含まれるドメインしかクロールしない。

レスポンスの取扱い

parse(self, response)で渡されるresponseで主に使うのはtextcss()urljoin()の3つ。
response.textはhtml情報がテキスト形式で入っているので、このままBeautifulSoupに渡すことができる。
response.css()はCSSセレクタによりhtml内の任意のセクションのSelectorインスタンスのリストを返す。インスタンスに含まれるデータは extract() でアクセス可能。リストのままでも、extract_first()で最初の要素に対してのみextract()をかけることが可能。
response.urljoin(path)は、pathと現在クロールしているURLを合わせてURLのフルパスを返す。

start_urls と start_requests()

最初にクロールするURLの一覧はリストstart_urlsに書く以外に、start_requests()でyieldするという方法がある。(サンプルコード2)
今回の例では、カレンダー一覧ページで取得したカレンダーURLを含むjsonをロードし(QiitaCalendarLoader)、そのURLに対してクロールするという処理を行っている。

コマンド

プロジェクト作成

scrapy startproject <プロジェクト名> で作成可能。

参考: https://doc.scrapy.org/en/1.3/topics/commands.html#genspider

Spider生成

scrapy genspider <スパイダー名> <対象ドメイン>で作成可能だが、大したことはしないので別に使わなくてもいい。

参考: https://doc.scrapy.org/en/1.3/topics/commands.html#genspider

クローリング

scrapy crawl <スパイダー名>

プロジェクトを作成した場合はcrawlコマンドを使う。

参考: https://doc.scrapy.org/en/1.3/topics/commands.html#crawl

インタラクティブシェル

scrapy shell <URL>

ipythonによるインタラクティブシェルモードに入る。URLは省略可。
URLを指定した場合、既に response 変数にレスポンスが格納されている。
インタラクティブシェルモードを起動するとヘルプが表示されるが、特に覚えるべきメソッドは2つ。

shelp()

ヘルプを表示する。

fetch(url)

あらたにURLをクロールする。結果はresponseに格納される。

settings.py

プロジェクトを作成すると、settings.py という設定ファイルが作成される。DOWNLOAD_DELAYなど、全てのスパイダーで共通の設定を行うものはこちらに記述した方がいい。