scrapy-redisを使ってのクローリングです。
前回までで基本的な利用の仕方を記載して行きました。
★scrapy-redisを使って、redisを使ったクローリングを試してみる その1(基本的な設定)
https://colabmix.co.jp/tech-blog/scrapy-redis/
★scrapy-redisを使って、redisを使ったクローリングを試してみる その2
https://colabmix.co.jp/tech-blog/scrapy-redis-2/
ただ、実際に細かなクローリングを行なっていくと、パラメーターが「start_urls」だけだとデータの取得がうまくいかないケースがあります。
データをPOSTで送付したい時や、パラメーターを結果にも欲しい時、そもそもJavaScriptを利用してのリクエストなど厳しいものがあります。
今回は引数としてのパラメーター(parameter)を利用してのscrapy-redisの使い方です。
尚、scrapy-redisの設定に「REDIS_PARAMS」という項目がありますが、こちらはRedisに接続するためのパラメーターです。
前回と同じように構成としては以下です。
ServerA : redisサーバ
ServerB : scrapy-redis
データを送る側の設定(ServerA)
キューを出す側として以下のプログラムを使用してみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
import redis import json class ScheduledRequest: def __init__(self, url, meta_param1): self.url = url self.meta_param1 = meta_param1 conn = redis.StrictRedis(host='localhost', port=6379, db=0) conn.lpush( 'devcolla:start_urls', json.dumps({"url": "http://developer-collaboration.com/", "param1": "test_param"}) ) |
こちらでredisに必要なデータをjson.dumpして送っています。
尚、scrapy-redisでのキーは「[spider名」:start_urls」となります。
scrapy-redis側の設定
さて、クローリングする側の設定です。
まず、パラメーターとして設定した「param1: test_param」を結果ファイルにも出すためにitemsの編集を行います。
1 2 3 4 5 6 7 8 9 10 |
# -*- coding: utf-8 -*- import scrapy class SampleCrawlerItem(scrapy.Item): title = scrapy.Field() url = scrapy.Field() param1 = scrapy.Field() |
次にspiderの設定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# -*- coding: utf-8 -*- from sample_crawler.items import SampleCrawlerItem import scrapy import json from scrapy_redis.spiders import RedisCrawlSpider from ..utils import bytes_to_str class DevcollaSpider(RedisCrawlSpider, scrapy.Spider): name = 'devcolla' def __init__(self, *args, **kwargs): super(DevcollaSpider, self).__init__(*args, **kwargs) def make_request_from_data(self, data): data_dict = json.loads(bytes_to_str(data, self.redis_encoding)) request = scrapy.Request(url=data_dict["url"]) request.meta['param1'] = data_dict["param1"] return request def parse(self, response): for quote in response.css('article.post-list'): item = SampleCrawlerItem() item['title'] = quote.css('h1.entry-title::text').extract_first() item['url'] = quote.css('a::attr(href)').extract_first() item['param1'] = response.meta['param1'] yield item |
少し複雑になっていますが、scrapy-redisの「make_request_from_data」というデータを受け取りリクエストを作成する関数を書き換えています。
・Githubソース
https://github.com/rmax/scrapy-redis/blob/master/src/scrapy_redis/spiders.py
受け取ったキューの値をdictに戻し、リクエストの生成などを行っています。
ここで、ポイントになるのが「bytes_to_str」という関数です。
scrapy-redisの中で使用しているので、こちらのファイル(utils.py)を作成する必要があります。
1 2 3 4 5 6 7 8 9 10 |
import six def bytes_to_str(s, encoding='utf-8'): """Returns a str if a bytes object is given.""" if six.PY3 and isinstance(s, bytes): return s.decode(encoding) return s |
こちらで完了です。
起動と試験
以下のコマンドで起動が行われます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
$ scrapy crawl devcolla 2019-03-26 16:01:42 [scrapy.utils.log] INFO: Scrapy 1.5.2 started (bot: sample_crawler) 2019-03-26 16:01:42 [scrapy.utils.log] INFO: Versions: lxml 4.2.1.0, libxml2 2.9.8, cssselect 1.0.3, parsel 1.4.0, w3lib 1.19.0, Twisted 16.2.0, Python 3.6.7 (default, Dec 5 2018, 15:02:05) - [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)], pyOpenSSL 19.0.0 (OpenSSL 1.1.0i 14 Aug 2018), cryptography 2.3.1, Platform Linux-3.10.0-957.10.1.el7.x86_64-x86_64-with-centos-7.6.1810-Core 2019-03-26 16:01:42 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'sample_crawler', 'DUPEFILTER_CLASS': 'scrapy_redis.dupefilter.RFPDupeFilter', 'NEWSPIDER_MODULE': 'sample_crawler.spiders', 'ROBOTSTXT_OBEY': True, 'SCHEDULER': 'scrapy_redis.scheduler.Scheduler', 'SPIDER_MODULES': ['sample_crawler.spiders']} 2019-03-26 16:01:42 [scrapy.middleware] INFO: Enabled extensions: ['scrapy.extensions.corestats.CoreStats', 'scrapy.extensions.memusage.MemoryUsage', 'scrapy.extensions.logstats.LogStats'] 2019-03-26 16:01:42 [devcolla] INFO: Reading start URLs from redis key 'devcolla:start_urls' (batch size: 16, encoding: utf-8 2019-03-26 16:01:42 [scrapy.middleware] INFO: Enabled downloader middlewares: ['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware', 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware', 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware', 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware', 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware', 'scrapy.downloadermiddlewares.retry.RetryMiddleware', 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware', 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware', 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware', 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware', 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware', 'scrapy.downloadermiddlewares.stats.DownloaderStats'] 2019-03-26 16:01:42 [scrapy.middleware] INFO: Enabled spider middlewares: ['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware', 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware', 'scrapy.spidermiddlewares.referer.RefererMiddleware', 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware', 'scrapy.spidermiddlewares.depth.DepthMiddleware'] 2019-03-26 16:01:42 [scrapy.middleware] INFO: Enabled item pipelines: [] 2019-03-26 16:01:42 [scrapy.core.engine] INFO: Spider opened 2019-03-26 16:01:42 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) |
ServerAの方で「push.py」を実行すると以下の表示が行われます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
2019-03-26 16:02:37 [devcolla] DEBUG: Read 1 requests from 'devcolla:start_urls' 2019-03-26 16:02:39 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://developer-collaboration.com/robots.txt> (referer: None) 2019-03-26 16:02:42 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://developer-collaboration.com/> (referer: None) 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'Elasticsearchの形態素解析機Sudachiでユーザー辞書(dictionary)の活用', 'url': 'https://developer-collaboration.com/2019/01/30/elasticsearch-sudachi-user-dictionary/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'Elasticsearchのkuromojiの検索で重要な辞書(dictionary)と類義語(synonym)の設定', 'url': 'https://developer-collaboration.com/2019/01/30/elasticsearch-kuro-dictionary-synonym/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'CentOS7のPython3でMeCabのmecab-ipadic-neologdのインストールと利用', 'url': 'https://developer-collaboration.com/2019/01/30/centos7-python3-mecab-ipadic-neologd/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'CentOS7のPython3でJUMAN++のインストールと利用', 'url': 'https://developer-collaboration.com/2019/01/29/centos7-python3-juman/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'Elasticsearchでエイリアスの作成', 'url': 'https://developer-collaboration.com/2019/01/29/elasticsearch-aliases/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'CentOS7系の最新版のredisをyumでインストール', 'url': 'https://developer-collaboration.com/2018/12/20/centos7-redis-install/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'SumEvalというPythonのテキスト評価用のライブラリを試してみた', 'url': 'https://developer-collaboration.com/2018/12/20/sumeval-python/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'pythonを使ってmongodbの操作', 'url': 'https://developer-collaboration.com/2018/12/18/python-mongodb1/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'Scrapyでデータの保存をmongodbにして見る(Scrapy その4)', 'url': 'https://developer-collaboration.com/2018/12/16/scrapy-mongodb4/'} 2019-03-26 16:02:42 [scrapy.core.scraper] DEBUG: Scraped from <200 http://developer-collaboration.com/> {'param1': 'test_param', 'title': 'CentOS7系でmongodb4.0のインストール', 'url': 'https://developer-collaboration.com/2018/12/15/centos7-mongodb4-0-install/'} 2019-03-26 16:02:42 [scrapy.extensions.logstats] INFO: Crawled 2 pages (at 2 pages/min), scraped 10 items (at 10 items/min) |
無事、結果の方にもキューで設定したパラメーターがセットされています。
リクエストのカスタマイズができるので複雑なリクエストなどにも応用できます。
★関連記事
・scrapy-redisを使って、redisを使ったクローリングを試してみる その1(基本的な設定)
・scrapy-redisを使って、redisを使ったクローリングを試してみる その2
このブログは株式会社CoLabMixによる技術ブログです。
GCP、AWSなどでのインフラ構築・運用や、クローリング・分析・検索などを主体とした開発を行なっています。
Ruby on RailsやDjango、Pythonなどの開発依頼などお気軽にお声がけください。
開発パートナーを増やしたいという企業と積極的に繋がっていきたいです。