どうも、nippa です。
スクレイピングの必要性が出てきたので、Selenium で Web 操作を自動化したいと思います。
Web 開発でのモンキーテストにも使えるので、知っていて損はないかと思います。
Web サイトによってはスクレイピングが禁止されているところもありますので、ご注意ください。
環境
パッケージ管理
パッケージは poetry を使って管理していきます。利用するパッケージは
の2つです。
以前までは、PC にインストールされている Chrome のブラウザのメジャーバージョンを調べ、そのバージョンにあったドライバを用意する必要がありました。
chromedriver-binary-auto
は自動でインストールされている Chrome のバージョン取得して、それに合うドライバをインストールしてくれます。
以下のコマンドでインストールを行います。
poetry add selenium chromedriver-binary-auto
今回は自動で Google 検索を行って、検索内容について 100 件取得することを題材とします。
まずは、Selenium の簡単な使い方になります。 url を指定して、Chrome で開き、5 秒スリーブごにブラウザを閉じるコードになります。
import time
import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
if __name__ == "__main__":
base_url = "https://www.google.com/"
url = f"{base_url}/"
options = Options()
driver = webdriver.Chrome(options=options)
driver.get(url)
time.sleep(5)
driver.close()
Google 検索で、「python selenium」を検索してみます。
スクレイピングでは html の構造を理解している必要があります。
Chrome であれば、Developer Tools を使うことで、html の構造を確認することができます。
また、beautifulsoup4 ライブラリを使えば html の構造ごと取得することもできます。
import sys
import time
import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
if __name__ == "__main__":
base_url = "https://www.google.com/"
url = f"{base_url}/"
options = Options()
driver = webdriver.Chrome(options=options)
driver.get(url)
name = "q"
search_word = "python selenium"
try:
marker = driver.find_element(By.NAME, name)
marker.send_keys(search_word)
marker.send_keys(Keys.ENTER)
except Exception as err:
print(err)
sys.exit(1)
time.sleep(5)
driver.close()
Google.com の検索用の input の name はq
のため name を指定して、element を取得しています。
取得した element に検索するワードを送り、Enter key コマンドを送付して、検索を行います。
検索結果表示後、5秒間スリーブして、ブラウザを閉じるという動作になっています。
検索結果のタイトルと URL の取得
xpath
を使って、検索結果のタイトルと URL を取得します。
google の検索結果の html の構造は以下のようになっています
...
<dvi id="search">
<dvi>
...
<a hred="リンク">
<h3>タイトル</h3>
</a>
...
</dvi>
</dvi>
このときのタイトルを取得するためのxpath
の書き方としては、//div[@id='search']//a/h3
となります。
//
は複数の element 意味します。
また親の element を取得する場合は..
で一つ上のxpath
を意味します。
import sys
import time
import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
if __name__ == "__main__":
base_url = "https://www.google.com/"
url = f"{base_url}/"
options = Options()
driver = webdriver.Chrome(options=options)
driver.get(url)
name = "q"
search_word = "python selenium"
try:
marker = driver.find_element(By.NAME, name)
marker.send_keys(search_word)
marker.send_keys(Keys.ENTER)
xpath = "//div[@id='search']//a/h3"
title_elements = driver.find_elements(By.XPATH, xpath)
except Exception as err:
print(err)
sys.exit(1)
for title_element in title_elements:
if len(title_element.text) > 0:
href_element = title_element.find_element(By.XPATH, "..")
print(
f'titele={title_element.text.replace(" ...", "")} url={href_element.get_attribute("href")}'
)
time.sleep(5)
driver.close()
これで検索 1 ページ目の検索結果のタイトル(一部)と URL を取得することができます。
複数のページの検索結果のタイトルと URL の取得
複数のページの検索結果を取得する場合、ページ移動を挟んで取得していきます。
ページ移動にはリンクの URL を取得して、そのページをロードする形にし、そのページが表示されたら、データを取得します。
xpath = "//div[@id='botstuff']//a[@id='pnnext']"
next_element = driver.find_element(By.XPATH, xpath)
next_page_url = next_element.get_attribute("href")
driver.get(next_page_url)
実際に python でスクリプト化すると以下のようになります。
以下ではpython selenium
という検索ワードで 10 ページ分の検索結果をタイトル、url を表示するものになっています。
また、--headless
オプションを利用しています。
from typing import List, TypedDict, Optional
import sys
import time
import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
class ResultData(TypedDict):
title: Optional[str]
url: Optional[str]
def get_title_and_url(driver: webdriver.Chrome) -> List[ResultData]:
data: List[ResultData] = []
try:
xpath = "//div[@id='search']//a/h3"
title_elements = driver.find_elements(By.XPATH, xpath)
except Exception as err:
print(err)
sys.exit(1)
for title_element in title_elements:
if len(title_element.text) > 0:
href_element = title_element.find_element(By.XPATH, "..")
result_data: ResultData = {
"title": title_element.text.replace(" ...", ""),
"url": href_element.get_attribute("href"),
}
data += [result_data]
return data
if __name__ == "__main__":
base_url = "https://www.google.com/"
url = f"{base_url}/"
options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
driver.get(url)
search_word = "python selenium"
max_page = 10
try:
name = "q"
marker = driver.find_element(By.NAME, name)
marker.send_keys(search_word)
marker.send_keys(Keys.ENTER)
except Exception as err:
print(err)
sys.exit(1)
data: List[ResultData] = []
for i in range(max_page):
data += get_title_and_url(driver)
time.sleep(1)
if i < max_page - 1:
xpath = "//div[@id='botstuff']//a[@id='pnnext']"
next_element = driver.find_element(By.XPATH, xpath)
next_page_url = next_element.get_attribute("href")
driver.get(next_page_url)
driver.close()
for _data in data:
print(f'titele={_data["title"]} url={_data["url"]}')
感想
今回、Google の検索結果をスクレイピングを selenium を使って書いてみました。
Web テスト用として利用する準備として、今回試しに使ってみています。
スクレイピングはサイトによっては禁止されていますので、サイトのルールに則ってください。
ではでは、また次回。