Python3 + Scrapy1 - スクレイピングの練習環境構築

  • 5
    いいね
  • 0
    コメント

はじめに

 Python3 とスクレイピングのフレームワークである Scrapy を使ってスクレイピングの練習環境を作るよ(・∀・)!

環境

  • Linux x86-64 (Ubuntu)
  • Python3
  • Docker1
  • Bash

仮想環境の構築

 Docker でスクレイピング用の仮想環境を構築。イメージは Ubuntu の最新版をプル。走らせるコンテナにホストマシンのポートをフォワーディング。それからプロジェクト用のディレクトリ my-scrapy をコンテナ内の /root/my-scrapy にマウント。

docker
$ docker pull ubuntu:latest
$ docker run -itp 127.0.0.1:8000:80 -v /home/narupo/src/my-scrapy:/root/my-scrapy ubuntu:latest /bin/bash

開発ツールの準備

 コンテナ内に開発ツールを準備する。

apt-get
root# apt-get update
root# apt-get install vim less git python3 python3-pip

pip で scrapy をインストール

 pip を更新後、scrapy をインストール。

pip
root# pip3 install --upgrade pip
root# pip install scrapy

 しかし scrapy のインストール時にエラーが出る。エラーを解決する。

error
...
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

 インストール時のコンパイルでライブラリが足りていない様なので入れる。依存関係と戦う日々(´・ω・)(・ω・`)ネー。

apt-get
root# apt-get install libxslt1-dev libssl-dev

 scrapy のインストールと動作確認。

root# pip install scrapy
root# scrapy --version

Apache2 と MySQL のインストール

 練習用のサーバーとデータ保存用のDBをインストールして起動させておく。

apt-get
root# apt-get install apache2 mysql-server
root# service apache2 start
root# service mysql start

 Apache2 を起動したのでホストマシンのブラウザ上から localhost:8000 へアクセスして動作確認。

テスト用ウェブサイトのデプロイ

 作るのは時間がかかるので github で "dummy website" で検索。今回は https://github.com/crysxd/Herbboy-Dummy-Website をデプロイする。

deploy
root# cd /var/www/html/
root# git clone https://github.com/crysxd/Herbboy-Dummy-Website
root# mv Herbboy-Dummy-Website/ test
root# chown -R www-data:www-data ./test

 デプロイが完了したのでホストマシンのブラウザ上で http://localhost:8000/test にアクセスして動作確認。

開発

 準備が完了したので開発に入る。
 Scrapy のチュートリアル http://doc.scrapy.org/en/latest/intro/tutorial.html に従う。

shell

 いくつか飛ばして以下のコマンドを試す。scrapy ではシェルで対話式にスクレイピングの操作が出来る。便利ですね。

scrapy-shell
root# scrapy shell "http://localhost:80/test"

 シェルにログイン後、引数のURLの結果が表示される。

scrapy-shell
...
[s] Available Scrapy objects:
[s]   crawler    <scrapy.crawler.Crawler object at 0x7f09aea67048>
[s]   item       {}
[s]   request    <GET http://localhost:80/test>
[s]   response   <301 http://localhost:80/test>
[s]   settings   <scrapy.settings.Settings object at 0x7f09ad4555f8>
[s]   spider     <DefaultSpider 'default' at 0x7f09ad267710>
[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 <301 http://localhost:80/test> になっているので転送されているらしい。Docker のポートフォワーディングの影響? https://scholar.live/question/scrapy-301-redirect-in-shell を参考に fetch 後、無事にタイトルを取得できた。

scrapy-shell
# 再読み込み
>>> fetch(response.headers['Location'].decode())

# タイトルを取得
>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Carousel Template for Bootstrap</'>]

 shell では Python3 の構文も有効。

scrapy-shell
>>> for title in response.xpath('//title'):         
...     txts = title.xpath('text()').extract()
...     print(txts)
... 
['Carousel Template for Bootstrap']

プロジェクトの作成

 街を駆けまわるのはスパイダーマンだが、ネットを駆けまわるのは・・・・・・そう、 Spider だ(`・ω・´)<ヤカマシイワ。プロジェクトを開始して、編集のためにプロジェクトの所有者とグループをホストマシンに合わせる。

project
root# cd ~/my-scrapy
root# scrapy startproject tutorial
root# chown -R 1000:1000 ./tutorial

 ここからはマウントしたホストマシンのディレクトリからファイルを編集可能。チュートリアルに沿って tutorial/tutorial 直下の items.py を編集。なんとなく Django のモデルに似てますね。

items.py
# -*- 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 MyItem(scrapy.Item):
    title = scrapy.Field()

 spiders/ 以下に Spider の my_spider.py を作成。parse に shell で操作した response が渡される。MyItem をインポートしてパース時のデータ保存に利用する。

my_spider.py
import scrapy
from tutorial.items import MyItem

class MySpider(scrapy.Spider):
    name = 'my'
    allowed_domains = ['localhost:80']
    start_urls = [
        'http://localhost:80/test',
    ]

    def parse(self, response):
        for title in response.xpath('//title'):
            item = MyItem()
            item['title'] = title.xpath('text()').extract()
            yield item

 作成した Spider をクロールさせるとスクレイピングを開始。

scrapy-crawl
root# scrapy crawl my

 出力を保存したい場合は -o オプションで出力パスを指定する。

scrapy-crawl
root# scrapy crawl my -o items.json

 出力結果がログに紛れてわかりづらいが、無事に shell の時と同様にタイトルを取得できた。導入は手間だが、やはりフレームワークなだけあってサックリと書けます。全体的に Django と似てますね。