★関連記事
・CentOS環境の python3.6(pyenv環境)で Scrapy を利用してみる(Scrapy その1)
・Scrapyでデータ取得でクローリングで取得したURLから検索する(Scrapy その2)
・Scrapyでデータの保存をmongodbにして見る(Scrapy その4)
・CentOS7でscrapy-splashを使ってJavaScriptの解析 その2(Scrapy その5)
Splashについて
一般的にスクレイピング単体ではJavaScriptの解析ができないため、JavaScriptの解析にはSelenimumを使用したり、PhantomJSを使用したりします。
Scrapy でも JavaScript の解析にはSplashを利用します。
Splash は Scrapinghub 社が開発しているオープンソースの JavaScriptレンダリングサービスで、WebKitをベースにしたヘッダレスブラウザ(GUIのないブラウザ)を組み込んだサーバです。
Webサイトの通信はSplashを中継して行われ、JavaScriptを読み込んだ状態のHTMLを取得したり、JavaScriptの実行をしたりできます。
ScrapyでもSeleniumなどは利用できますが、Scrapyのメンテナンスを主にしている Scrapinghub 社が開発しているということもあり Splash を利用するケースの方が多いようです。
単純に Selenium より Sprasy の方が実行が早いというのもありますが。
Scrapy を利用するために実施する流れは以下となります。
- Scrapyサーバをインストール・起動する
- scrapy-splashというライブラリをインストールする
- SpiderでRrequestクラスの代わりにSplashRequestクラスを使う
Splashサーバのインストールと起動の方法
Splashサーバのインストールは主に以下の2つの方法があります。
- Dockerを使って構築
- 手動で構築(通常のインストール)
参考)
https://splash.readthedocs.io/en/stable/install.html
今回はCentOSで実施しますが、Dockerを使って構築を行います。
SIPやPyQt5を入れて手動で構築することもできますが、手順としては煩雑になります。
Ubuntuであれば手順も揃っているので手動での構築でも良いかもしれません。
Dockerのインストールと起動
事前準備としてdockerインストールの必要ライブラリをインストールし、リポジトリを読み込み、docker-ceのインストールを行います。
また、dockerの起動と起動設定も行っておきます。
1 2 3 4 5 6 7 8 |
# yum -y install -y yum-utils device-mapper-persistent-data lvm2 # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # yum -y install docker-ce # systemctl start docker # systemctl enable docker |
こちらでDocker環境の準備は完了です。
Splashサーバのインストール
インストールはdockerファイルを使って行います。
1 2 3 4 |
# docker pull scrapinghub/splash # docker run -p 8050:8050 -p 5023:5023 scrapinghub/splash |
こちらでインストールと起動は完了です。
通常は8050のHTTP用のポートを使って Scrapy から呼び出しを行います。
5023はtelnet用のポートです。
https://doc.scrapy.org/en/latest/topics/telnetconsole.html
scrapy-splashのライブラリのインストール
ソースコードはこちらになります。
https://github.com/scrapy-plugins/scrapy-splash
1 2 3 |
# pip install scrapy_splash |
Scrapyからのサンプルファイルの取得(事前確認)
今回、ファイルの取得は以下のサイトから行います。
https://colabmix.co.jp/sample/sample1.html
ファイルの中身は以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>sample1</title> <script type="text/javascript"> window.onload = function onLoad() { target = document.getElementById("contents"); target.innerHTML = "Contents"; } </script> </head> <body> <h1>Sample1</h1> <p> <div class="contents" id="contents">NoNoNo</div> </body> </html> |
表示される画面はこちらです。
JavaScriptのonloadイベントでdivの中身を書き換えているので、通常のScrapyのファイルだけではブラウザに表示されている値が取得できません。
Scrapyで値の取得を試してみます。
以下は「items.py」の設定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class SampleCrawlerItem(scrapy.Item): text = scrapy.Field() |
そして、spider本体である「spiders/devcolla.py」の設定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# -*- coding: utf-8 -*- import scrapy from sample_crawler.items import SampleCrawlerItem class DevcollaSpider(scrapy.Spider): name = 'devcolla' allowed_domains = ['developer-collaboration.com'] start_urls = ['https://developer-collaboration.com/sample/sample1.html'] def parse(self, response): item = SampleCrawlerItem() item['text'] = response.css('div.contents::text').extract_first() yield item |
こちらでクローラーを動かしてみます。
1 2 3 |
# scrapy crawl devcolla -o result.csv |
結果ファイルを確認します。
1 2 3 4 5 |
# cat result.csv text NoNoNo |
テキストの内容を確認すると画面表示とは違う「NoNoNo」が出力されていました。
Splashでのテキスト情報の取得
まず、Scrapyで動作を行うために「settings.py」の変更を行います。
設定の概要は公式の以下を参考にしています。
https://pypi.org/project/scrapy-splash/
追加された項目は以下となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
SPLASH_URL = 'http://localhost:8050/' DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810, } SPIDER_MIDDLEWARES = { 'scrapy_splash.SplashDeduplicateArgsMiddleware': 100, } DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter' HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage' |
ます、最初の「SPLASH_URL」でSplashサーバのアドレスを追加しています。
今回はローカルのdockerに接続しているので、localhostを指定しています。
次にSplashの「DOWNLOADER_MIDDLEWARES」でSplashミドルウェアを設定しています。
後ろの数字は読み込みの順番を表すプライオリティです。
次は「SPIDER_MIDDLEWARES」を追加しています。
そして、「DUPEFILTER_CLASS」と「HTTPCACHE_STORAGE」の設定を行います。
次にspider本体である「spiders/devcolla.py」の設定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# -*- coding: utf-8 -*- import scrapy from scrapy_splash import SplashRequest from sample_crawler.items import SampleCrawlerItem class DevcollaSpider(scrapy.Spider): name = 'devcolla' allowed_domains = ['developer-collaboration.com'] start_urls = ['https://developer-collaboration.com/sample/sample1.html'] def start_requests(self): yield SplashRequest(self.start_urls[0], self.parse, args={'wait': 0.5}, ) def parse(self, response): item = SampleCrawlerItem() item['text'] = response.css('div.contents::text').extract_first() yield item |
SplashRequestの読み込みを行い、リクエストをこちらから行っています。
JavaScriptの読み込みを行うため、起動時に0.5秒のwaitを設定しています。
こちらでクローラーを動かしてみます。
1 2 3 |
# scrapy crawl devcolla -o result.csv |
結果ファイルを確認します。
1 2 3 4 5 |
# cat result.csv text Contents |
今度は表示と同じ形でテキストが出力されました。
UserAgentの確認
最後にサーバ側でのアクセスログですが、上がSplashを使わない場合のログで、下がSplashを使った場合のログです。
どちらも同じUserAgentになりました。
1 2 3 4 |
XXX.XXX.XXX.XXX - - [13/Dec/2018:23:33:58 +0900] "GET /sample/sample1.html HTTP/1.1" 200 482 "-" "Scrapy/1.5.1 (+https://scrapy.org)" XXX.XXX.XXX.XXX - - [13/Dec/2018:23:31:58 +0900] "GET /sample/sample1.html HTTP/1.1" 200 482 "-" "Scrapy/1.5.1 (+https://scrapy.org)" |
表示されているUserAgentはScrapyのデフォルトのものなので、Splashでは追加でUserAgentのセットはしないようです。
このブログは株式会社CoLabMixによる技術ブログです。
GCP、AWSなどでのインフラ構築・運用や、クローリング・分析・検索などを主体とした開発を行なっています。
Ruby on RailsやDjango、Pythonなどの開発依頼などお気軽にお声がけください。
開発パートナーを増やしたいという企業と積極的に繋がっていきたいです。