はじめに
近畿大学 Advent Calendar 2019の13日目の記事です.
はじめに注意なのですが, 基本的にスクレイピングは必要がないならするべきではない最終手段です. 今回はQiitaのタグランキングをスクレイピングしますが, Qiitaにはapiが存在しておりそこにタグランキングを取得するapiが存在しなかった(2019年12/8現在)のでスクレイピングをしました.もしあなたが欲しい情報がapiを用いて取得できるならばapiで取得しましょう. また, スクレイピングする際は接続時に待機時間を設け, 接続時間を空けましょう.
必要なもの
Docker
自分が使ってるバージョンは以下.
Docker version 19.03.5, build 633a0ea
docker-compose.yml
version: '3'
services:
selenium-hub:
image: selenium/hub
container_name: selenium-hub
ports:
- "4444:4444"
chrome:
image: selenium/node-chrome-debug
depends_on:
- selenium-hub
environment:
- HUB_PORT_4444_TCP_ADDR=selenium-hub
- HUB_PORT_4444_TCP_PORT=4444
python:
build: .
container_name: python
volumes:
- .:/workspace
command: /bin/bash
tty: true
stdin_open: true
FROM python:3.7
WORKDIR /workspace
RUN pip install \
selenium \
beautifulsoup4
dockerfileとcompose説明
今さらdokcer-composeやdockerfileとは何かというのは書かないのでわからなければDocker上でElixirのPhoenixとPostgreSQLを使ってみたという記事に詳しめに書いているのでそちらを参考にしてください.
では早速docker-compse.ymlから説明します.
動的サイトをスクレイピングするには現在では基本Selenium
一択だと思います.
selenium/hub
とselenium/node-chrome-debug
というイメージを使ってコンテナを作成します.
ここでselenium/node-chrome-debug
のほうでenvironment
が設定されています.これがなければスクレイピングできないので注意しましょう.
Dockerfileのほうではpythonの環境を構築しています.RUN
コマンドで必要なライブラリをDLしています.
これらのファイルと下にあるコードを同一階層上に配置して, docker-compose up -d --build
を実行すればコンテナが立ち上がりあます.
コード例
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from bs4 import BeautifulSoup
import pprint
class QiitaGetRanking():
"""
Qiitaからランキングデータを取得するクラス.
"""
def get_tag_ranking(self, browser: webdriver) -> dict:
"""
Qiitaからタグランキングに関する情報を取得する関数.
Parameters
----------
browser: webdrive
スクレイピングするためのwebdriverのオブジェクト
Returns
-------
tag_ranking_data: dict
タグランキングを収めた辞書オブジェクト.
"""
html = browser.page_source.encode('utf-8')
soup = BeautifulSoup(html, "html.parser")
ra_tag_names = soup.find_all(class_='ra-Tag_name pr-1')
tag_ranking_data = {}
for i, ra_tag_name in enumerate(ra_tag_names):
tag_ranking_data[i+1] = [ra_tag_name.text,
'https://qiita.com/tags/%s'%(ra_tag_name.text.lower())]
return tag_ranking_data
if __name__ == "__main__":
"""
main文. browserはhtmlの取得が終わり次第閉じること.エラーが出てきたときも同様.
"""
try:
browser = webdriver.Remote(
command_executor='http://selenium-hub:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME)
print("start scrape")
browser.get('https://qiita.com')
# javascriptが全て読み込まれるまで待機. 15秒経っても読み込みが終わらなければタイムアウト判定.
WebDriverWait(browser, 15).until(EC.presence_of_all_elements_located)
print("generate object")
qgr = QiitaGetRanking()
ranking_data = qgr.get_tag_ranking(browser)
browser.close()
browser.quit()
pprint.pprint(ranking_data)
except:
browser.close()
browser.quit()
コードはいたってシンプルだと思います.dockerでスクレイピングする際はseleniumサーバーを建ててスクレイピングした方がubuntu上にselenium環境を構築するより楽だし軽いです.
webdrriver.Remoteに関しては2.5. リモートWebDriverでSeleniumを使用するを参考にしてみてください.
実行結果
docker ps
で3つのコンテナが建っていることを確認してから,docker exec -it python python qiita.py
でプログラムを実行してください.
start scrape
generate object
{1: ['Python', 'https://qiita.com/tags/python'],
2: ['JavaScript', 'https://qiita.com/tags/javascript'],
3: ['AWS', 'https://qiita.com/tags/aws'],
4: ['Rails', 'https://qiita.com/tags/rails'],
5: ['Ruby', 'https://qiita.com/tags/ruby'],
6: ['初心者', 'https://qiita.com/tags/初心者'],
7: ['Docker', 'https://qiita.com/tags/docker'],
8: ['PHP', 'https://qiita.com/tags/php'],
9: ['Vue.js', 'https://qiita.com/tags/vue.js'],
10: ['Go', 'https://qiita.com/tags/go']}
こんな感じで表示されていたら完全勝利です.お疲れさまでした.
さいごに
今回はDockerを用いて動的サイトをスクレイピングする方法を紹介しました.皆さんも制限の範囲内でスクレイピングを楽しみましょう!