Pythonライブラリのscrapy splashでスクレイピングする | COMMONS NOTE

Pythonライブラリのscrapy splashでスクレイピングする

こんにちはマダラです。
Pythonのスクレイピングに特化したライブラリ、Scrapyを使用したのでその使い方備忘録としてまとめようと思います。
また、クロール先でJavaScriptイベントを実行できるsplashも合わせて併用したのでそちらも書きます。
splashも合わせた日本記事の情報はあまりなかったので、ピンポイントなニーズがあるのではないでしょうか???

scrapyとは

クローラーを実装するためのフレームワーク。
BeautifulSoup や lxml などの HTML パーサーがよく使用されるが、 Scrapy はこれらのライブラリと違うレイヤーのもので、クローラーのアプリケーション全体を実装するためのフレームワークである。
Scrapy はクローラーを実装・運用するために欲しい機能がいろいろ用意されている
  • Items は抽出したいデータ構造のモデル
  • Spider は対象サイトへのリクエストとレスポンスのパーサー
  • Pipeline は抽出したデータに対する加工・保存 (など)
詳しくはQiitaの10分で理解するScrapyも参考になります。
インストール
$ pip install scrapy
 
プロジェクトの作成
$ scrapy startproject test_scrapy

Spiderの実装

では実際にSpiderを実装してスクレイピングできるようにしていきましょう。
作成されたプロジェクト内にあるItems.pyにスクレイピングしたい要素を設定していきましょう。
すでにサンプルのクラスが設定されていますが、自由に書き換えてしまって大丈夫です。
下記のような感じで追加していきます。
items.py
class TestItem(scrapy.Item): 
    url = scrapy.Field() 
    title = scrapy.Field()
ちなみにFieldにはいろいろ設定できて、1個目だけを取得したりタグは排除したり、リストで取ってきたり色々できます。
class TestItem(scrapy.Item):
   name = scrapy.Field(
      input_processor=MapCompose(remove_tags, str.strip),
      output_processor=TakeFirst(),
   )
   category = scrapy.Field(
      input_processor=MapCompose(remove_tags, str.strip),
      output_processor=Join(),
   )
ではSpiderを追加しましょう。スクレイピングしたいサイトのURLを設定します。
$ cd ./test_scrapy
$ scrapy genspider test_spider hogehoge.com

ひな型ファイルはこのようになっています

class ScrapyBlogSpiderSpider(scrapy.Spider): 
    name = 'test_spider' 
    allowed_domains = ['blog.scrapinghub.com'] 
    start_urls = ['http://blog.scrapinghub.com/'] 

    def parse(self, response): 
        pass

start_urls に指定されているurlがクロールされます。
単純に複数クロールしたければ、ここに追加していけばいいですね!

レスポンスを受け取るとparse()メソッドが呼び出されます。

あとはこんな感じでSpiderを実装しましょう

test_spider.py

class ScrapyBlogSpiderSpider(scrapy.Spider): 
name = "test_spider"
target = "url末尾"
allowed_domains = ["www.hogehoge.jp"]
start_urls = [f"http://www.hogehoge.jp/{target}"]

def spider_idle(self, spider):
     print("クロールが終わったんだぜ〜〜〜ワイルドだろ〜〜〜")

def parse(self, response):
   for ranking in response.css("div.クラス名"):
      item_loader = ItemLoader(item=TestItem(), selector=ranking)
      item_loader.add_css("name", "div.クラス > a::text")
      item_loader.add_css("url", "div.クラス > a::attr(href)")

      next_url = ranking.css("div.listing_title > a::attr(href)").extract_first()
      if next_url is not None:
         next_page = response.urljoin(next_url)
         yield scrapy.Request(next_page, callback=self.parse_item, meta={"item": item_loader.load_item()})

   next_url = response.css("div.pagination > a.next::attr(href)").extract_first()
   if next_url is not None:
      next_page = response.urljoin(next_url)
      yield scrapy.Request(next_page)
   self.crawler.signals.connect(self.spider_idle, signal=signals.spider_idle)

def parse_item(self, response):
   info = response.css("div#ID名")
   item_loader = ItemLoader(item=response.meta["item"], selector=info)
   item_loader.add_css("name", "div.クラス名 > div.クラス名.クラス名 > div > span::text")
     item_loader.add_css("url", "div.クラス名 > div.クラス名.クラス名 > div > a::attr(href)")
   yield item_loader.load_item()
勝手にページングしたり、終了時にお伝えしてくれる処理も入ってます。
スラックかラインにでも通知させてあげると便利ですね。
実行です(sql,csv,jsonが使える)
$ scrapy crawl spider名 -o ファイル名.json

まとめ

文字書くのって苦手です。。すごい疲れますね。
やはり私はブロガーには向いていない、、、
JavaScriptを実行できる、つまりクロール中にボタンをクリックしたりできるSplashに関しても書きたかったけど疲れたので、また気が向いたら書きます。

これができると、通常は隠されている要素も取得できたり、条件を絞ったりできるようになります。
つかれた