Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pythonで作るWebクローラ入門

amacbee
September 21, 2016

 Pythonで作るWebクローラ入門

Pythonで作るWebクローラ入門の発表資料
https://pycon.jp/2016/ja/schedule/presentation/32/

amacbee

September 21, 2016
Tweet

More Decks by amacbee

Other Decks in Technology

Transcript

  1. 真嘉比愛(Ai Makabi) DATUM STUDIO 株式会社 PyLadies Tokyo 各種アカウント Slack: @amacbee

    Twitter: @a_macbee Facebook: ai.makabi Python ライブラリ厳選レシピ( 共著)
  2. Web クロー ラ Wikipedia より抜粋 混同されがちな言葉 クロー リング: Web ペー

    ジのリンクを辿りながら保存する作業 スクレイピング: 保存したペー ジから特定の情報を抽出する作業 クロー ラ(Crawler) とは、 ウェブ上の文書や画 像などを周期的に取得し、 自動的にデー タベー ス 化するプログラムである。 “ “
  3. 本セッションの内容 Python を利用したクロー ラ作成・ 運用方法を一通り 知ることを目標とする 1. Web クロー ラを利用する上での注意点

    2. Python 製クロー ラフレー ムワー ク「Scrapy」 Scrapy を利用してPyJobBoard クロー ラを作成 クロー ラ作成のTips 作成したクロー ラの管理 3. その他クロー ラ構築に有用なPython ライブラリ
  4. クロー リングの際に遵守したいこと デー タの収集/ 公開は著作権法に配慮して行う robots.txt に記載されたアクセス制限を守る API が容易されている場合はそちらを利用する サー

    バへアクセスする間隔は最低でも1 秒以上あけ るようにする 会員のみが閲覧できるペー ジは利用規約を守る 参考:Web スクレイピングの注意事項一覧
  5. Scrapy - latest: 1.1.2 Python 製のクロー ラフレー ムワー ク クロー

    ラ界におけるDjango のような存在 クロー ラ作成時に考慮しなければならない機能を オプションを指定するだけで簡単に実現可能 e.g. サイトクロー リング間隔,robots.txt の解釈 スケジュー リング, ジョブ管理,etc. 機能を内包 2016 年5 月にリリー スされたScrapy 1.1 より Python 3 に対応
  6. Scrapy 利用環境の構築 pip を使って簡単に導入できます $ pip install scrapy ※Windows 環境の場合,

    別途設定が必要 ※Ubuntu 環境ではapt-get も利用可能 $ sudo apt-get install python-scrapy
  7. Scrapy を用いたクロー リングの流れ www.python.org のサイトにあるJob Board をクロー ルするクロー ラを作成する 以下の手順を踏みます

    1. プロジェクトを作成 2. クロー ル対象を定義 3. クロー ラを作成 4. クロー リング& 結果の保存
  8. 1. プロジェクトを作成 $ cd 任意のフォルダ $ scrapy startproject プロジェクト名 e.g.

    pyjob プロジェクト ├ ─ ─ pyjob │ ├ ─ ─ __init__.py │ ├ ─ ─ __pycache__ │ ├ ─ ─ items.py # クロー ル対象について記載 │ ├ ─ ─ pipelines.py │ ├ ─ ─ settings.py # クロー ルオプション │ └ ─ ─ spiders # クロー ラ本体(spider) を格納 │ ├ ─ ─ __init__.py │ └ ─ ─ __pycache__ └ ─ ─ scrapy.cfg # デプロイ設定
  9. 2. クロー ル対象を定義 scrapy.Field() を利用して, 取得したい情報を item.py に追記( 今回は募集タイトル・ 社名・

    勤務場 所) import scrapy class PyjobItem(scrapy.Item): title = scrapy.Field() # タイトル company = scrapy.Field() # 社名 location = scrapy.Field() # 勤務場所
  10. 3. クロー ラを作成(1/7) scrapy genspider コマンドで雛形となるクロー ラ (spider) を自動的に作成 $

    scrapy genspider クロー ラ名 クロー ル対象ドメイン 例えば, python.org ドメインをクロー ルするクロー ラ の雛形を作成するには以下の通り実行 $ cd pyjob $ scrapy genspider pyjob_spider python.org ※ 作成されたクロー ラはpyjob/spiders 以下にある
  11. 3. クロー ラを作成(2/7) 作成したクロー ラの雛形の中身 自動作成された変数 name: クロー ラ名 allowed_domain:

    クロー ル対象ドメイン start_urls: クロー ル開始ペー ジのURL リスト 自動作成されたメソッド parse: クロー ルしたペー ジのパー ス ※ 後述
  12. 3. クロー ラを作成(3/7) e.g. python.org ドメイン中の python.org/jobs ペー ジ を起点にクロー

    リング from ..items import PyjobItem import scrapy class PyjobSpiderSpider(scrapy.Spider): name = "pyjob_spider" allowed_domains = ["python.org"] start_urls = ( 'https://www.python.org/jobs/', ) def parse(self, response): # 後述 ※ 複数のドメイン・URL を指定可能
  13. 3. クロー ラを作成(4/7) parse メソッドでは主に2 つの処理を行う 1. ペー ジからクロー ル対象の要素を抽出して返す

    Item クラスに必要な情報を格納 ※Item クラスの定義はitem.py で定義 2. 次のクロー ル対象ペー ジのURL を返す scrapy.Request(url) で返されたURL は新たなクロ ー リング対象となる(callback 引数にparse メソ ッドを指定すると, 再帰的にクロー ルを実行)
  14. 3. クロー ラを作成(5/7) def parse(self, response): # ペー ジ中のジョブオファー 情報を全て取得

    for res in response.xpath("//h2[@class='list..."): job = PyjobItem() job['title'] = res.xpath(".//span[@cla...")... job['company'] = res.xpath(".//span[@cla...")... job['location'] = res.xpath(".//a[start...")... yield job # 「Next」 のリンクを取得してクロー ルする next_page = response.xpath("//li[@cla...").extract() if next_page: url = response.urljoin(next_page[0]) yield scrapy.Request(url, callback=self.parse) タグ要素の取得にはXPath やCSS のセレクタを利用
  15. 3. クロー ラを作成(6/7) settings.py でクロー リングのオプションを設定 絶対に設定して欲しい項目は以下 パラメー タ 意味

    DOWNLOAD_DELAY クロー ル間隔( 秒) robots.txt に従うか否かを設定する ROBOTSTXT_OBEY は デフォルトで True (Scrapy 1.1+)
  16. 3. クロー ラを作成(7/7) e.g. pyjob のクロー リングオプション設定 BOT_NAME = 'pyjob'

    SPIDER_MODULES = ['pyjob.spiders'] NEWSPIDER_MODULE = 'pyjob.spiders' ROBOTSTXT_OBEY = True # robots.txt に従う DOWNLOAD_DELAY = 3 # 同一サイトへのアクセス間隔は3 秒
  17. 4. クロー リング& 結果の保存 $ scrapy crawl 作成したクロー ラ名 -o

    出力先ファイル名 e.g. pyjob クロー ラを実行して, 結果をCSV 形式で保 存( クロー リングの実行ログも残す) $ scrapy crawl pyjob_spider -o result.json \ --logfile pyjob.log ※ 拡張子からファイルタイプを自動判定 ※DB 等へデー タを保存する処理は, pipeline.py を編 集することで追加できるが, ここでは省略
  18. クロー リング結果を確認 result.json [ { "title": "Lead Python API and

    Automation Developers", "location": "Remote, USA", "company": "FICO" }, { "title": "Python Developer", "location": "London, UK", "company": "BMLL Technologies" }, ...
  19. クロー リングログを確認 pyjob_spider.log 2016-09-21 01:20:30 [scrapy] INFO: Scrapy 1.1.2 started

    (bot: pyjob) 2016-09-21 01:20:30 [scrapy] INFO: Overridden settings: {'NEWSPIDER_MODULE': 'pyjob.spiders', 'LOG_FILE': 'pyjob_spider.log', 'BOT_NAME': 'pyjob', 'SPIDER_MODULES': ['pyjob.spiders'], 'FEED_URI': 'result.json', 'ROBOTSTXT_OBEY': True, 'DOWNLOAD_DELAY': 3, 'FEED_FORMAT': 'json'} 2016-09-21 01:20:30 [scrapy] INFO: Enabled extensions: ['scrapy.extensions.corestats.CoreStats', ...
  20. クロー ラ作成のTips(2/3) scrapy shell を利用してスクレイピング結果をイン タラクティブに確認 $ scrapy shell 'https://www.python.org/jobs/'

    ... >>> response.css('title') [<Selector xpath='descendant-or-self::title' data='<title>Python Job Board | Python.org</ti'>] >>> response.xpath('//title') [<Selector xpath='//title' data='<title>Python Job Board | Python.org</ti'>] ※ requests + BeautifulSoup4 でも代替出来る
  21. クロー ラ作成のTips(3/3) クロー リング過程とスクレイピング過程を分ける サイト構造の変更によるスクレイピングの失敗 は珍しくない => 失敗してもクロー リングを再実行しない =>

    クロー リング/ スクレイピング共に失敗して いないか監視する 対象サイトにJavaScript が含まれているか確認する JavaScript が含まれるか含まれないかで難易度が 大きく変わるため,JavaScript が含まれる場合は 別サイトの利用も検討する
  22. [ まとめ] クロー ラ作成 with Scrapy 以下の手順を踏むことで, 特定サイトから欲しいデー タをクロー ル出来た

    1. プロジェクトを作成 2. クロー ル対象を定義 3. クロー ラを作成 4. クロー リング& 結果の保存
  23. Scrapy Cloud クロー ラ管理用クラウドサー ビス「scrapinghub」 上で動くScrapy 環境 https://scrapinghub.com/scrapy-cloud/ Scrapy Clound

    の便利なポイント ツー ルの導入が簡単( pip install shub ) API キー を使って簡単deploy( shhub login --> shub deploy ) 簡易かつリッチなUI スケジュー リングも容易( Periodic Jobs )
  24. Scrapy Cloud の課金体系 クロー ル範囲が1 サイト以下の場合は 無料 クレジットカー ドの登録も必要なし デー

    タ保存期間は1 週間 新しくクロー ル先を追加するたびに +9$ / month https://scrapinghub.com/pricing/
  25. scrapyd Scrapy のデー モン 作成したクロー ラのジョブ管理が行える インストー ルが容易 ( pip

    install scrapyd scrapyd-client ) シンプルなAPI を利用した操作 ※ Python 3 に対応していない
  26. クロー ラをscrapyd にdeploy 1. scrapy.cfg の [deploy] にあるurl をコメントアウト [deploy]

    url = http://localhost:6800/ project = pyjob 2. scrapyd を起動 $ scrapyd 3. 作成したクロー ラをscrapyd にdeploy $ scrapyd-deploy -p pyjob
  27. API を利用したジョブの登録 schedule.json: ジョブを登録 $ curl http://localhost:6800/schedule.json \ ß-d project=pyjob

    -d spider=pyjob_spider cancel.json: ジョブの中止 $ curl http://localhost:6800/cancel.json \ -d project=pyjob -d job= ジョブID その他のAPI: https://scrapyd.readthedocs.io/en/stable/api.html
  28. クロー ラ向けライブラリ(1/2) 1. requests 人間が利用することを意識して書かれた非常にシ ンプルなHTTP ライブラリ ( その限りではないが) 使い捨てのコー

    ドを書く のに最適 >>> import requests >>> res = requests.get('http://www.python.org/jobs/') >>> res.status_code 200 >>> with open('pyjob.html') as fout: ... fout.write(res.content)
  29. クロー ラ向けライブラリ(2/2) 2. aiohttp Python 3.4 から追加されたasyncio を利用した非同期 HTTP Server/Client

    1 プロセス内で複数のリクエス トを同時に実行(=IO 多重化) => 待ち時間を有効に活用して 高速に動作 公式サイト: http://aiohttp.readthedocs.io
  30. e.g. aiohttp を利用したシンプルなクロー ラ from aiohttp import request, wait import

    asyncio @asyncio.coroutine def get(*args, **kwargs): res = yield from request('GET', *args, **kwargs) return (yield from res.read_and_close()) @asyncio.coroutine def print(): page = yeild from get(url) print(page) urls = ['****', '****', '****'] f = wait([print(url) for url in urls]) loop = asyncio.get_event_loop() loop.run_untile_complete(f)
  31. 話したこと Web クロー ラについて説明 クロー ラの利用事例を紹介 クロー リング時の注意点について説明 Scrapy を利用したクロー

    ラ構築方法を一通り説明 クロー ラ構築方法について最低限の流れを説明 クロー ラ構築時のTips について共有 クロー ラの管理に便利なツー ルを紹介 ありがとうございました!