naritoブログ

このブログはDjangoとBootstrap4で作成されました
ソースコード

Python、Seleniumの基本

プログラミング関連 Selenium(Python) Python 約433日前
2016年6月10日16:34
https://torina.top/detail/266/
BeautifulSoup+requests版


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

インストール
pip install selenium


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


driver = webdriver.Firefox()
driver.get("https://torina.top/")
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の簡単な使い方


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

ダウンロードは、こちらです。
http://phantomjs.org/download.html

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

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


driver = webdriver.PhantomJS()  # ここがかわった
driver.get("https://torina.top/")
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://torina.top/")
for h2 in driver.find_elements_by_tag_name("h2"):
    print(h2.text)
driver.quit()


以下の書き方は、他にもいくつかの書き方ができます。
私のブログでは、<h2 class="panel-title">となっているので・・・
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


入力欄へ値を入力する場合は、例えば以下のように...
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)


スクリーンショットなどもとれます。
driver.save_screenshot("test.png")


もし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://torina.top/")
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://torina.top/")
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://torina.top/")
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://torina.top/")
driver.implicitly_wait(10)  # 見つからないときは、10秒まで待つ
h1 = driver.find_element_by_tag_name("h1")
print(h1.text)
driver.quit()


aタグからhrefなどを取得したい場合、以下のようにします。
url = data.find_element_by_css_selector('h3 > a').get_attribute('href')


現在開いているページのURLを取得したい場合は、こうです
driver.current_url


マルチプラットフォームで動くものを作りたい場合は、
https://github.com/mozilla/geckodriver/releases
から各プラットフォームのgeckodriverをダウンロードし、スクリプトと同階層に置きます。
そして以下のようなヘルパー関数を定義しておくと良いでしょう。
def get_driver():
    """各プラットフォームに合わせて、ブラウザを立ち上げる."""
    if sys.platform.startswith('linux'):
        path = './geckodriver'
    elif sys.platform.startswith('win'):
        path = 'geckodriver.exe'
    return webdriver.Firefox(executable_path=path)

driver = get_driver()


http://selenium-python.readthedocs.io/