Pythonによるスクレイピング:Seleniumを使用したWebデータの収集
1.1 使用するライブラリ
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
1.2 処理の流れ
# 1. ブラウザを起動する
browser_driver = webdriver.Chrome()
# この方法ではブラウザのGUIが表示されます
# option = webdriver.ChromeOptions()
# option.add_argument("headless")
# browser_driver = webdriver.Chrome(options=option)
## この方法ではブラウザのGUIが表示されません
# 2. URLを指定してページを開く
browser_driver.get('http://xzqh.mca.gov.cn/map')
# 3. ページ上の要素を操作する
province_selector = Select(browser_driver.find_element(by=By.NAME, value='shengji'))
1.3 使用する関数
1. driver.find_element(by=By.*, value='...') または driver.find_elements(...)
# 機能:指定された条件に基づいて要素を取得します
# 例:driver.find_element(by=By.NAME, value='shengji')
# driver.find_element(by=By.CLASS_NAME, value="info_table")
# 戻り値の型:単一の要素(find_element)またはリスト(find_elements)
2. Select(ELEMENT)
# 機能:指定された要素からselectオブジェクトを生成します
# 例:s = Select(driver.find_element(by=By.NAME, value='shengji'))
# s.options[i] でselect内のオプションを取得できます
# 例:province = s1.options[i].text.split('(')[0]
# s.select_by_index()(またはselect_by_value)でオプションを選択できます
# 例:s1.select_by_index(i)
1.3 例:Seleniumを使用して中華人民共和国民政部のウェブサイトから行政区画情報を取得する
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
# ブラウザを起動する
browser_driver = webdriver.Chrome()
# 以下の方法でブラウザを起動すると、グラフィカルインターフェースを開かずに実行できます
# option = webdriver.ChromeOptions()
# option.add_argument("headless")
# browser_driver = webdriver.Chrome(options=option)
browser_driver.get('http://xzqh.mca.gov.cn/map')
# select要素を取得する
province_selector = Select(browser_driver.find_element(by=By.NAME, value='shengji'))
# 省とインデックスの対応関係を辞書に保存する
province_index_map = {}
index = 0
for option in province_selector.options:
province_index_map[option.text.split('(')[0]] = index
index += 1
target_provinces = ['湖北省', '湖南省', '四川省']
for province_name in target_provinces:
index = province_index_map[province_name]
# select要素を再取得する(ページ遷移後の要素)
province_selector = Select(browser_driver.find_element(by=By.NAME, value='shengji'))
# 目的の省を選択する
province_selector.select_by_index(index)
# 送信ボタン要素を取得する
submit_button = browser_driver.find_element(by=By.CLASS_NAME, value='select_bn')
# クリックして遷移する
submit_button.click()
# ページの読み込みを待つ
time.sleep(2)
# table要素を取得する
data_table = browser_driver.find_element(by=By.CLASS_NAME, value="info_table")
# area要素を取得する
city_elements = data_table.find_elements(by=By.NAME, value='hidzxs')
for city in city_elements:
print(province_name + ' ' + city.get_property('value'), city.get_property('alt'))
# 前のページに戻る
browser_driver.back()
1.4 最適化
1.4.1 問題の説明
上記の方法を使用する場合、ブラウザのGUIを開くかどうかに関わらず、処理が非常に遅いことがあります。その原因は、Seleniumのページ読み込み戦略の選択にあります。
Seleniumには3種類のページ読み込み戦略があります:
| 戦略 | 準備完了の状態 | 備考 |
|---|---|---|
| normal | complete | デフォルトで使用され、すべてのリソースのダウンロードが完了するまで待機します。 |
| eager | interactive | DOMへのアクセスが準備完了ですが、他のリソース(画像など)はまだ読み込み中の場合があります。 |
| none | Any | WebDriverを全くブロックしません。 |
使用方法:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.page_load_strategy = 'eager' # ここで戦略を選択します
browser_driver = webdriver.Chrome(options=options)
browser_driver.get("http://www.google.com")
browser_driver.quit()
戦略を選択しない場合、デフォルトでnormal戦略が使用され、すべてのリソースが読み込まれるまで待機するため、非常に遅くなります。
2022年7月17日更新
上記の戦略設定方法が現在、何らかの理由で使用できないため、以下の方法に変更しました。
from selenium.webdriver import DesiredCapabilities
desired_capabilities = DesiredCapabilities.CHROME # ページ読み込み戦略を変更する
desired_capabilities["pageLoadStrategy"] = "eager" # この2行をコメントアウトすると、最終出力結果の遅延が発生します。つまり、ページの読み込みが完了してから出力されます。