Help us understand the problem. What is going on with this article?

PythonのScrapyの便利技まとめ

PythonのScrapyはいろいろできるスクレイピング、クローリング専用のライブラリ

最近業務でスクレイピングの仕事がちょくちょく入るようになりました。
以前がsimplehtmlというPHPのライブラリでスクレイピングを実装していましたが

  • フォームの自動提出
  • 専用のCLIがある
  • 単に流行っている

という理由から最近はPythonのScrapyを使ってスクレイピング業務をしています
(PHPは楽ですがPHPからは卒業したいという個人的な思いもあります。)

Scrapyの奥が深いと思う理由

Scrapyがなぜよいかというと主に以下の理由からです

  • 複雑なスクレイピングを組むことができる
  • CLIのコマンドツールで試し打ちができる

が挙げられると思います。これまでスクレイピングはURLのパターンを読解してやっていましたが
Scrapyでは画面遷移させるためのメソッドが用意されていてseleniumでできるブラウザの自動化よりもはるかにすくないメモリのリソースで例えばフォーム提出などができます。

Scrapyで発見した便利技

基本

scrapyのインストール

$pip install scrapy

scrapyのSpiderのプロジェクトを始める

$scrapy startproject [project_name] [project_dir]

コマンドライン編

作成したSpiderのプロジェクトを一覧する

$scrapy list

作成したプロジェクトに新規のSpiderを作成する

#ドメイン名を追加する
$scrapy genspider [spider_name] mydomain.com

コマンドライン実行時にURLを指定する

$scrapy crawl -a start_urls="http://example1.com,http://example2.com" [spider_name]

CSVで出力する

$scrapy crawl -o csv_file_name.csv [spider_name]

JSONで出力する

$scrapy crawl -o json_file_name.json [spider_name]

シェル編

Scrapyシェルを起動する

$ scrapy shell [URL]

ページをすべて表示する

#responseは定義せず使える
response.body

リンクをすべて取得する

for link in response.css('a::attr(href)'):
   print link.get()

ライブラリ編

正規表現を使う

#aタグのhrefの中の特定のファイルがマッチした場合
matched = response.css('a::attr(href)').re(r'detail\.php')
if len(matched) > 0:
   print 'matched'

#aタグの文字列の中の特定の日本語がマッチした場合
matched = response.css('a::text').re(u'まとめ')
if len(matched) > 0:
   print 'matched'

タグを取得

#aタグを取得
response.css('a')

セレクタで取得

#aタグを取得
response.css('a.link')

#複数のクラスを取得<li class="page next"></li>
response.css('li.page.next')

相対パスをURLに変換する

for link in response.css('a::attr(href)'):
   print response.urljoin(link.get())

フォーム情報を送信

scrapy.FormRequest(response,formdata={"username":"login_username","password":"login_password"}

XPathで取得した要素の子要素の繰り返し処理

#DIV要素を取得
divs = response.xpath('//div')
#DIVの中のP要素を繰り返す
for p in divs.xpath('.//p'):  
     print(p.get())

別ページに遷移する

#self.parse(self,response)をコールバック関数として定義
yield scrapy.Request([url],callback=self.parse)

そのほか

Itemを作る(Project直下のitems.pyを編集)
元ネタ

class Product(scrapy.Item):
    name = scrapy.Field()
    price = scrapy.Field()
    stock = scrapy.Field()
    tags = scrapy.Field()
    last_updated = scrapy.Field(serializer=str)

サンプル

一覧のアイテムがなくなるまで詳細ページに遷移する(そのままでは動かないのでクラスの中に入れてください)

    def parse(self, response):
            title = a.css('::text').extract_first()
            title_match = a.css('::text').re(u'研修')
            if len(title_match) > 0:
                    "title":title,
                    "url":response.urljoin(link_param)
                }
                ptn = re.search("\/jinzaiikusei\/\w+\/",url)
                if ptn:
                    self.scraping_list.append(url)
        yield scrapy.Request(self.scraping_list[0],callback=self.parse_detail)
        pass

    def parse_detail(self, response):
         for item in response.css('a'):
             title =  item.css('::text').extract_first()
             url =  item.css('::attr(href)').extract_first()
             title_matched = item.css('::text').re(u'研修')
             url_matched = item.css('::attr(href)').re(r'jinzaiikusei\/.*\/.*\.html')
             if url_matched:
                 item = {
                         "title":title,
                         "url":url
                    }
                 yield item
         self.current_index = self.current_index + 1
         if self.current_index < len(self.scraping_list):

             yield scrapy.Request(self.scraping_list[self.current_index],callback=self.parse_detail)
         else:
             pass

更新履歴

  • 2019/12/06 新規作成
  • 2019/12/07 ライブラリの技を追加
  • 2019/12/09 ライブラリの技を追加(フォームの入力など)
  • 2019/12/16 itemsについての章を追加
  • 2019/12/21 コマンド編追記
  • 2020/1/20 シェルのパートに追記
  • 2020/2/12 urljoinを追加
  • 2020/2/13 サンプルを追加
negisys
自社で新規開発のお仕事をしています。
https://callapi.xyz
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away