diadia

興味があることをやってみる。自分のメモを残しておきます。

selenium使ってみる

困ったときの参照ページ

Python + Selenium で Chrome の自動操作を一通り
Selenium の API (Official)
Selenium with Python

使用準備

まずseleniumを扱う環境を作成した。anacondaを利用して環境を設定した。

conda create -n selenium python=3.6.4
pip install selenium

これだけではseleniumを利用することはできず、実際にブラウザを制御するドライバーも必要になる。windowsでの環境設定を試みたが、うまく行かなかったのでmacで行った。windowsについては最後まで環境構築できたら記録する。
ドライバーのダウンロード先:https://www.seleniumhq.org/download/
ダウンロードページの少しスクロールした先にThird Party Browser Drivers NOT DEVELOPED by seleniumhqがあり、Google Chrome Driverがある。これをクリックしてバージョンを指定するとmac用のソースがあるのでダウンロードする。

簡単なスクレイプコード

今回はwebdriverを呼び出して、特定のページを表示させ、そのページの特定のタグをスクレイピングするコードを書く。

python

from selenium import webdriver

driver = webdriver.Chrome("User/myusername/desktop/chromedriver")
#Chrorme内にはダウンロードしたwebdriverのフルパスを記述すること 
driver.get("https://yahoo.co.jp/")
for h2 in driver.find_elements_tag_name("h2")
    print(h2)

classで取得する


# class属性値であり、.classNameと書く必要はない
driver.find_element_by_tag_name("className")


入力フォームに入力する

入力フォーム(inputタグ)を要素として取得する。そして取得した要素に対し、入力したいキーワードをsend_keys()を使って入力する。

python 

from selenium import webdriver
driver = webdriver.Chrome("/users/myusername/desktop/chromedriver")
driver.get("https://google.co.jp")
input = driver.find_element_by_id("lst-ib")
#googleの検索フォームid名はlst-idである。
input.send_keys("ヤフーニュース")

seach_button = driver.find_element_by_name("btnK")
#検索のボタンはinputタグを取得する
search.click()
#click()を使うことでボタンを押すことができる。

これでヤフーニュースを検索する事ができた。取得したフォーム要素にclear()メソッドを使うと、フォームに入力した文字列を消去することができる。



現在表示されているウインドウ(ブラウザ)のURLを取得

seleniumはhtmlソースから要素を取得するだけでなく、htmlソース外からデータを取得することができる。具体的にはブラウザのurlである。

【Python】current_url・・・URLを取得する

current_urlメソッドを使うことでカレントページのURLを取得することができる。

current_url = driver.current_url

Chromewebdriverのヘッドレス化

通常運転するとseleniumchrome等のブラウザを立ち上げて、操作される。これではメモリを消費してしまう理由などからブラウザが見えない状態で操作される状態にすることができる。これは昔PhantomJSというwebdriverがその役割を担ってきたそうだが、メンテナンスをやめるということでPhantomJSからFirefoxChromeのヘッドレス化が一般になった模様だ。
ヘッドレス化はChromeのバージョンが59以降のものなら利用できる。バージョン確認方法はChrome://versionをブラウザに送ってあげると表示させることができる。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

CHROME_PASS = 'C:\\Users\\user\Desktop\chromedriver'

options = Options()
options.add_argument('--headless')
driver_headless = webdriver.Chrome(executable_path = CHROME_PASS, chrome_options=options)

#あとは普段どおりにseleniumのコードを書く

ポイントはwebdriverの定義でChromeに2種類の引数を渡すことだ。1つ目はChromedriverの実行ファイルのパスを**kwargsとして渡す。2つ目はヘッドレスのオプションを**kwargsとして渡すこと。


frame間の移動

iframeタグの中に存在する別のhtmlタグ以下の要素に対しては、そのまま要素を取得できない。そのため取得したい要素を含むiframeタグに移動し、そこから取得する流れに持ち込む。そのとき必要なのはswitch_to_frameやswitch_to_defaul_content()である。

3.4. Moving between windows and frames

driver.switch_to_frame("frameName")
#frameNameは要素の取得(find_element...)で定める。
driver.switch_to_default_content()
#親のフレームに戻る

別windowへ移動

aタグを押すことで別ウィンドウが開きそこの情報をスクレイピングしたいとする。webdriverはウィンドウが新たに開かれた場合にどのように挙動するのか?新たなウィンドウを開いたとて、現在のwebdriverのウィンドウを継続する。そのため新たに開いたウィンドウに移動する場合にはwebdriverのメソッド switch_to_window()を用いる必要がある。switch_to_window()の引数はwindowIDである。このwindowIDはwindow_handlesでリスト型のデータとしてwindowIDを取得することができる。

driver.get(URL)
window_ids = driver.window_handles
driver.swich_to_window(window_ids[-1]) 

https://stackoverflow.com/questions/13113954/selenium-webdriver-using-switch-to-windows-and-printing-the-title-doesnt-prin

python 3.7.1 selenium 3.14.1のバージョンだとswitch_to_window()が使えなかった。switch_to.window()として記述する必要がある。


classの名前が複数ある要素の取得について(有用)

例えばタグが以下のような状態の時、

input class=" first-part  copy-target"

このような場合には、いつもfind_element_by_class_nameを試みて、以下のようなエラーが返されていた。

selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: Compound class names not permitted

Compound class names not permittedとは複数のクラスネームの場合は対応できませんよってことだと思う。これに対する解決方法がわかった。それはfind_element_by_css_selectorを使うことだ。上記の場合には、

driver.find_elements_by_css_selector(".first-part.copy-target")

参考URL

Selenium Compound class names not permitted