Scrapyで画像収集クローラーを作ってみる

投稿:

Python製のクローラーフレームワークScrapyで画像収集をしたい時のメモです。

画像収集に関してもScrapyは簡単にスクレイピングできる仕組みを最初から持っているのでこれを使ってみます。

なお、Scrapyは1.6.0を利用しました。

スポンサードサーチ

pillowのインストール

まずはpillowというモジュールをインストールします。

$ sudo pip install pillow

python標準のPIL (Python Imaging Library)でも動くと公式は説明していますが、PILというモジュールはpython3系には無いらしいので推奨通りpillowを使います。

The Images Pipeline uses Pillow for thumbnailing and normalizing images to JPEG/RGB format, so you need to install this library in order to use it. Python Imaging Library (PIL) should also work in most cases, but it is known to cause troubles in some setups, so we recommend to use Pillow instead of PIL.

公式: https://docs.scrapy.org/en/latest/topics/media-pipeline.html

settings.pyの設定変更

次にsettings.pyに下記3行を追加します。

ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1}
IMAGES_STORE = './images'
MEDIA_ALLOW_REDIRECTS = True

パイプラインの処理は自分でもカスタマイズできますが今回はとりあえず標準の物を使います。

IMAGES_STOREは画像の保存先を指定。この例だとsettings.pyと同じ階層にimagesディレクトリを作ってます。

MEDIA_ALLOW_REDIRECTSはURLのリダイレクトを有効化するかどうか。

例えば http => https へリダイレクトされるケースがある場合に便利なので設定しておいて損はないと思います。

テスト用に混在コンテンツで作ったデモページをScrapyにクロールさせると、非SSLで埋め込まれた画像もリダイレクトして取得してくれます。

2019-03-04 14:34:23 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://demo.worklog.be/scrapy/image.html> (referer: None)
2019-03-04 14:34:27 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to <GET https://demo.worklog.be/scrapy/image/http.png> from <GET http://demo.worklog.be/scrapy/image/http.png>

■ 注意点

ITEM_PIPELINESに設定するImagesPipelineについて調べると下記のような古い?情報がヒットします。

ITEM_PIPELINES = {'scrapy.contrib.pipeline.images.ImagesPipeline': 1}

どうも古い公式情報を見ていたようで、Scrapy 1.6.0にこの設定したらこんなエラーが出ました。

ModuleNotFoundError: No module named 'scrapy.contrib'

ここで無駄にハマってしまいました…

items.pyに設定追加

items.pyはこのように設定を追加します。imagesとimage_urlsは予約語みたいです。

class BlogscrapyImage(scrapy.Item):
	images = scrapy.Field()
	image_urls = scrapy.Field()

画像収集クローラーの作成と実行

次はこのようなクローラーを書いてこのブログのアイキャッチ画像を全て取得してみます。

class DemoWorklogSpider(CrawlSpider):
	name = 'worklog'
	allowed_domains = ['worklog.be']
	start_urls = ['https://worklog.be/']

	rules = (
		Rule(LinkExtractor(allow=r'/page/', unique=True), callback='parse_item', follow=True),
	)

	def parse_item(self, response):
		item = BlogscrapyImage()
		item['image_urls'] = response.css('.entry-thumbnail img::attr(src)').extract()
		yield item

image_urlsに画像のURLを入れてあげれば後はScrapyが勝手にダウンロードして集めてくれます。

$ scrapy crawl worklog

画像は images/full/ 配下に、画像URLのsha1ハッシュ形式のファイル名で保存されます。

文字のスクレイピングだけじゃなく画像収集もScrapyは簡単です。

ただし微妙なポイントとしては画像は勝手にJPEG形式に変換されるという事、勝手にfullというディレクトリが出来てしまう事等があり、実稼働させるならここの処理はやっぱりオリジナルで実装が一番かなと思います。

ファイル名重複とかあると面倒臭いのでURLのsha1ハッシュ形式は個人的に歓迎ですが、どうせならこんな感じに保存したい。

images/e/6e/801f19bca10667c85c9ac5f62c3499ced489616e.jpg

ここの改良版はこれから作るので書いたらまたここにアップします。

よく読まれている記事

  • 本日
  • 週間
  • 月間