LoginSignup
8
17

More than 3 years have passed since last update.

今日から始めるPython Scrapyを利用したスクレイピング

Last updated at Posted at 2019-05-02

なんでScrapyをやろうと思ったか

世は2019年GWまっただ中。今後の仕事の効率化のため、この時間を活用してスクレーピングやらない手はない。何を効率化するかって?そんなことは、できるようになってから考えるとしよう。

Scrapyとは

An open source and collaborative framework for extracting the data you need from websites.In a fast, simple, yet extensible way.

Scrapy本家サイト

Webサイトから簡単に欲しい情報を抽出させてやるための仕組み。ということです。ざっくりでも何のためにあるか確認すると理解の助けになりますよね。

前提

  • OS:macOS High Sierra 10.13.6
  • Python:3.6.1
  • Scrapy:1.6.0

準備

仮想環境作成

$ cd [project dir]
$ python -m venv [venv name]

ここでは、[project dir]をscrapy、[venv name]をvenvにします。
以降は(venv)は仮想環境に切り替えている前提とします。([venv name]を別名にしている場合置き換えて下さい。)
ちなみに、仮想環境を作成するコマンドvenvはPython3.3以上の標準とのことなので、基本的にはこのコマンドを利用するようにする。

仮想環境に切り替える。

$ source venv/bin/activate

プロンプトの先頭が(venv)になっていることを確認する。

scrapyをインストールします。

(venv)$ pip install scrapy

もしかしたら依存関係でエラーになるかもしれないが、落ち着いて必要なライブラリをインストールしましょう。

インストールしたらScrapyのバージョンを確認します。

(venv)$ scrapy version
Scrapy 1.6.0

試しのScrapyに記載されているサンプルコードmyspider.pyを作成します。

myspider.py
import scrapy

class BlogSpider(scrapy.Spider):
    name = 'blogspider'
    start_urls = ['https://blog.scrapinghub.com']

    def parse(self, response):
        """
        blogタイトルを抽出し次のページに移動していく。
        """
        for title in response.css('.post-header>h2'):
            yield {'title': title.css('a::text').get()}

        for next_page in response.css('a.next-posts-link'):
            yield response.follow(next_page, self.parse)
  • parse():リクエストに対してダウンロードされたレスポンスを受け取るための呼び出されるメソッド。responseパラメータはページコンテンツを保持するTextResponseのインスタンスです。

Scrapyのドキュメント
日本語訳Scrapyドキュメント

作成したmyspider.pyを実行します。

(venv)$ scrapy runspider myspider.py -0 sample.jl
  • jl:JSON Lines形式のファイル。一度に1レコードずつ処理できる構造化データを格納するのに便利なフォーマットです。(jsonファイルだと、配列かつカンマ区切り列形式でファイル出力されます)

以下出力内容のsample.jlファイルが作成されます。

sample.jl
{"title": "From The Creators Of Scrapy: Artificial Intelligence Data Extraction API"}
{"title": "Scrapinghub\u2019s New AI Powered Developer Data Extraction API for E-Commerce & Article Extraction"}
 :

Scrapyの開始

Yahoo!ニュースをスクレイピングしてみます。
ScrapyではクロールやスクレイピングにSpiderを利用します。

Spiderのスクレイピングライフサイクル

  1. 最初のURLをクロールする最初のリクエストを生成し, それらのリクエストからダウンロードされたレスポンスで呼び出されるコールバック関数を指定します.
    • 実行する最初のリクエストは, start_requests() メソッドを呼び出すことによって取得されます. このメソッドは, デフォルトで start_urls で指定されたURLと Request のコールバック関数として呼ばれる parse メソッドで, Request を生成します.
  2. コールバック関数では, レスポンス(Webページ)を解析し, 抽出されたデータ, Item オブジェクト, Request オブジェクト, またはこれらのオブジェクトの反復可能なものを返します これらのリクエストには, コールバックが含まれ, Scrapyによってダウンロードされ, その後指定されたコールバックによってリクエストが処理されます.
  3. コールバック関数では, セレクタ を使用してページの内容を解析します(ただし, BeautifulSoup, lxmlなどの任意のメカニズムを使用することもできます).
  4. 最後に, スパイダーから返されたアイテムは, 通常, データベース(一部の アイテムパイプライン 内)に永続化されるか, または フィードのエクスポート を使用してファイルに書き込まれます.

引用:https://scrapy-ja.readthedocs.io/ja/latest/topics/spiders.html

Scrapyプロジェクトを作成

以下コマンドを実行してプロジェクトを作成します。
ここでは[project name]をmyprojectとしてます。

(venv)$ scrapy startproject [project name]
...
(venv)$ cd myproject
(venv)$ tree .
.
├── myproject
│   ├── __init__.py
│   ├── __pycache__
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       └── __pycache__
└── scrapy.cfg

まずは、最低限の環境設定を行います。
settings.pyのDOWNLOAD_DELAYのコメントを削除しWebサイトへのリクエストの間隔を秒単位に設定します。(接続先に負荷を与えないためにも必ず設定すること)

settings.py

#DOWNLOAD_DELAY = 3
 
DOWNLOAD_DELAY = 3

また、スクレイピングの結果をファイル出力する際の文字コードを追記し指定します。

settings.py
FEED_EXPORT_ENCODING = 'utf-8'

Itemを作成

スクレイピングは構造化されていないソース(通常はWebサイト)から構造化データを抽出することである。ScrapyではItemクラスを利用することでPythonの扱いやすい構造に収める事ができます。Itemクラスはscrapy.Itemを継承します。

items.py
import scrapy

class NewsTopics(scrapy.Item):
    title = scrapy.Field()
    summary = scrapy.Field()

Spiderを作成

(venv)$ scrapy genspider news news.yahoo.co.jp
Created spider 'news' using template 'basic' in module:
  myproject.spiders.news

spidersフォルダにnews.pyファイルが作成されます。

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

class NewsSpider(scrapy.Spider):
    name = 'news'
    allowed_domains = ['news.yahoo.co.jp']
    start_urls = ['http://news.yahoo.co.jp/']

    def parse(self, response):
        for url in response.css('ul.topicsList_main a::attr("href")').re(r'/pickup/\d+$'):
            yield scrapy.Request(response.urljoin(url), self.parse_topics)

    def parse_topics(self, response):
        item = Headline()
        item['title'] = response.css('title ::text').extract_first()
        item['summary'] = response.css('.tpcNews_summary').xpath(
            'string()').extract_first()
        yield item

Spiderの実行

(venv)$ scrapy crawl news -o topics.jl

topics.jlにスクレイピングした結果が出力されていることを確認します。

ここまでで、Scrapyを利用したクローリングとスクレイピングのやり方になります。
書簡としては、WebアプリケーションでいうとこのDjangoのように、スクレイピングのフレームワークだけあり小さく始めるにもとっつきやすいと思います。他にもパイプラインやシェルなどの仕組みがあるみたい。


今後調べたいこと。

  • 機械学習用のデータを収集方法について
  • クローリングとスクレイピングは機構を分けたほうがよいので、Scrapyを利用した分離方法について
  • SPAやログインが必要なサイトのクローリング方法について

終了

8
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
17