Python、Seleniumの基本

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

Python - サードパーティ製ライブラリ
2018年11月22日21:25に更新(約21日前)
2018年11月7日21:40に作成(約36日前)

旧ブログ移行記事です。

Seleniumとは

スクレイピングやクローラーを作る際に、Seleniumはよく使います。 私はrequestsBeautifulSoupを使うことが多いですが、 JSでHTMLを動的に生成しているようなページの場合はそれでは難しいことがあります。 そのような場合は、Seleniumがよいでしょう。

インストール

pip install selenium

ちょっとしたサンプル

例えば、このブログのタイトルを抽出したい場合は以下のようになります。

from selenium import webdriver

driver = webdriver.Firefox()
driver.get(`https://narito.ninja/`)
for h2 in driver.find_elements_by_tag_name(`h2`):
    print(h2.text)
driver.quit()

結果

Pythonで、進捗バーを自作する
Djangoで、404ページを作る
Djangoでシンプルなアクセスカウンターもどき
Django、templateからよくincludeするhtml
Django、ブログに使えそうなModel
Django、管理画面へのリンク
Python、マルチスレッドを使い簡易チャット
ホームページ作成に役立つサイト(非デザイナー向け)
HTML・CSS、便利なテンプレート(Bootstrap)
Python、loggingの簡単な使い方

ブラウザを立ち上げないPhantomJS

上で使ったFireFox()は、FireFoxブラウザを実際に立ち上げます。

もしブラウザを立ち上げたくない、という場合はPhantomJSを使うことになります。

※ PhantomJSをSeleniumで使うのは非推奨になりました。
※ Chrome とFireFoxにヘッドレスモードがあるので、そちらをいずれ紹介します

例えばWindowsでは、解凍し中にあるphantomjs.exeをパスの通った場所に置くとOKです。 面倒ならば実行ファイルのあるディレクトリに置くとよいでしょう。

インストールが完了したら、以下のように書き換えるです。

from selenium import webdriver

driver = webdriver.PhantomJS()  # ここがかわった
driver.get("https://narito.ninja/")
for h2 in driver.find_elements_by_tag_name("h2"):
    print(h2.text)
driver.quit()

ユーザーエージェントの設定

以下の様な感じで変更できます。

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

des_cap = dict(DesiredCapabilities.PHANTOMJS)
des_cap['phantomjs.page.settings.userAgent'] = (
    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' +
    'Chrome/28.0.1500.52 Safari/537.36'
)
driver = webdriver.PhantomJS(desired_capabilities=des_cap)

driver.get("https://narito.ninja/")
for h2 in driver.find_elements_by_tag_name("h2"):
    print(h2.text)
driver.quit()

要素の取得方法

タグで指定する場合

driver.find_elements_by_tag_name("h2")

クラスの指定

driver.find_elements_by_class_name("panel-title")

CSSセレクタ

driver.find_elements_by_css_selector("h2.panel-title")

xpath

driver.find_elements_by_xpath("//h2[@class='panel-title']")

elementsは複数elementは1つ取得します。

# element
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector

# elements 複数、「リスト」が返る
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector

属性の取得

a要素からhref属性などを取得したい場合、以下のようにします。

url = data.find_element_by_css_selector('h3 > a').get_attribute('href')

現在開いているページのURL

凝ったクローラーなんかを作っていると、必要になることがありますね。

driver.current_url

入力やクリック処理

入力欄へ値を入力する場合は、以下のようにします。

login_id = driver.find_element_by_id("login")
password = driver.find_element_by_id("pass")
login_id.send_keys("id")
password.send_keys("pass")

ボタンのクリックは、click()で呼び出せます。

driver.find_element_by_id("next_button").click()
driver.find_elements_by_css("next")[0].click()

もしくは、エンターキーを押すのと同様の処理もできます。

from selenium.webdriver.common.keys import Keys

driver.find_element_by_name('spam').send_keys(Keys.RETURN)

スクリーンショット

スクリーンショットも案外使う機会が多いです。Seleniumを使った自動テストではお世話になる人も多いのではないでしょうか。

driver.save_screenshot("test.png")

BeautifulSoupにソースを渡す

もしseleniumが気に入らず、せめてHTMLのパースはBeautifulSoupを使いたい、なんてときはpage_sourceでHTMLのソースが取得できます。

soup = BeautifulSoup(driver.page_source, "html5lib")

要素があったかどうかの確認

スクレイピングにおいて、対象の要素が見つからないという場合はよくあります。例えば、サイトが更新されてidが変わったなどです。 そのときは以下のようにして、例外をキャッチするとよいでしょう。

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

driver = webdriver.Firefox()
driver.get("https://narito.ninja/")
try:
    h2 = driver.find_element_by_id("aaaaa")

except NoSuchElementException:
    print("要素がありませんでした...")

else:
    print(h2.text)

finally:
    driver.quit()

elements系の場合、あくまでリストが返ることに注意です。要素がなければ、空リストです。 ですので、elementsの場合は以下のようにして判定しましょう。

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

driver = webdriver.Firefox()
driver.get("https://narito.ninja/")
h2s = driver.find_elements_by_class_name("panel-title")
if h2s:
    print("要素ありました")
    for h2 in h2s:
        print(h2.text)

else:
    print("要素ありませんでした")
driver.quit()

クラスやIDが存在するはずなのに、NoSuchElementExceptionが送出される場合は、HTMLの描画が終わっていない、ということもあります。 この場合は描画を待つことができます。 簡単な方法だと、以下のようにtime.sleepができますし、

import time
from selenium import webdriver

driver = webdriver.Firefox()
driver.get("https://narito.ninja/")
time.sleep(5)  # 5秒まってみる
h1 = driver.find_element_by_tag_name("h1")
print(h1.text)
driver.quit()

以下の方法では、要素が見つからない場合は10秒間待ってくれます。 elementsの場合でもちゃんと待ってくれます。

import time
from selenium import webdriver

driver = webdriver.Firefox()
driver.get("https://narito.ninja/")
driver.implicitly_wait(10)  # 見つからないときは、10秒まで待つ
h1 = driver.find_element_by_tag_name("h1")
print(h1.text)
driver.quit()

参考リンク

公式ドキュメント
BeautifulSoup+requests版

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

記事にコメントする