見出し画像

【python】seleniumを使ってブラウザの操作を自動化する


seleniumをインストール

$ pip install selenium

Chrome用のドライバーをインストール

ここから、自分の使っているChromeと同じバージョン用のドライバーをダウンロードして解凍。任意の場所に置いておく。

※Chromeブラウザ側がちょいちょい自動アプデしちゃうので注意。安定稼働させたい場合は自動アプデを切っておく。(ただし手動でアプデする仕組みをちゃんと作っておかないとセキュリティ的にアレ)

とりあえず、任意のサイトにアクセスしてスクリーンショットを撮ってみる

from selenium import webdriver

# chromedriver.exeを置いたところのパスを「chromedriver.exe」まで込みで
driver_path = "./chromedriver.exe"

# driverを作る
driver = webdriver.Chrome(executable_path = driver_path)

# アクセス先のURLを設定してスクショを撮る
driver.get('https://www.google.com/')
driver.save_screenshot('sample.png')
driver.quit()

パス設定して、ドライバー作って、アクセス先のURL設定したらスクショを撮りまーす、で撮れます。

ここでTypeError: WebDriver.init() got an unexpected keyword argument 'executable_path'が出る場合

あなたが使っているseleniumのバージョンが4、あなたが参考にしている記事(上記のサンプルを含め)で使っているseleniumのバージョンが3です。

そのまま4を使う場合、driverを作成するときに直接ドライバーのパスを渡すのではなく、いったんServiceクラスのインスタンスを作ってからdriverに渡します。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

# chromedriver.exeを置いたところのパスを「chromedriver.exe」まで込みで
driver_path = "./chromedriver.exe"

# Serviceクラスにドライバーのパスを設定して、Serviceをwebdriverに与えてdriverを作る
service = Service(executable_path=driver_path)
driver = webdriver.Chrome(service=service)

# アクセス先のURLを設定してスクショを撮る
driver.get('https://www.google.com/')
driver.save_screenshot('sample.png')
driver.quit()

に、します。

なお、ここから先はselenium4を使って進めます

ヘッダーレスで(ChromeのGUIを起動せずに)実行する

バッチなどで実行する場合に、いちいちブラウザ立ち上げる必要ないよね、というときにはヘッダーレスで(ブラウザを立ち上げずに)実行できます。

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

# chromedriver.exeを置いたところのパスを「chromedriver.exe」まで込みで
driver_path = "./chromedriver.exe"

# Optionsにヘッダーレスで動かす命令を足す
options = Options()
options.add_argument('--headless')

# Serviceクラスにドライバーのパスを設定する
service = Service(executable_path=driver_path)

# ServiceとOptionsを与えてwebdriverを作る
driver = webdriver.Chrome(service=service)

driver.get('https://www.google.com/')
driver.save_screenshot('sample.png')
driver.quit()

できました。

任意の要素を操作する

必要なリンクをクリックしたり、テキストエリアに文字を入力したり、ドロップダウンメニューを選んだりして画面を操作します

任意の要素を取得する

まず、操作したい要素を取得します。
「要素」というのはHTMLタグで囲まれたひとかたまりです。例えば

<div id="main">
  <a href="https://sample.com">サンプルリンク</a>
</div>

という記述がある場合、「div要素」の中に「a要素」があるという状態です。

これを特定するのにちょっとコツがいるというか、例えばaタグを取得したい場合に、画面上に沢山あるaタグの中から、目的の一つを特定する必要があります。目的の要素にidが付いていればいいんですけど、世の中のウェブサイトが全部そんなにお行儀が良いわけではないので……
なので、親タグのidで取得してからその子孫のaを特定していく……とか、nameタグで特定するとかaタグならアンカーテキストで特定するとか、大体工夫が必要です。

①diverを作り、任意のページにアクセスする

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from time import sleep

# chromedriver.exeを置いたところのパスを「chromedriver.exe」まで込みで
driver_path = "./chromedriver.exe"

# Serviceクラスにドライバーのパスを設定して、Serviceをwebdriverに与えてdriverを作る
service = Service(executable_path=driver_path)
driver = webdriver.Chrome(service=service)

# 任意のサイトにアクセスする
url = "https://sample.com"
driver.get(url)
sleep(5)

これで任意のページにアクセスできます。
実行してみると、自動でchromeのウインドウが立ち上がり、任意のページが表示されて5秒後に消えます。
sleepしないと一瞬で消えるので、後続の操作が完成するまではテスト用にsleepを入れておくと良いです。

②idで特定する
上記のdriverが出来たら、driverを操作して要素を取得します。

# driver作成は省略(①参照)

from selenium.webdriver.common.by import By

main_contents = driver.find_element(by= By.ID, value= "main")

※このとき、selenium3を使っているとここも大分記法が変わりますのでご注意ください。上記サンプルはselenium4です。

driverのfind_elementメソッドを使い要素を取得します。
引数に「by」というのが用意されているので、selenium.webdriver.common.byからByクラスをインポートしてあげて、「By.ID」という形式で「どれを目印に探すか」を指定します。まずはid属性で探してみます。
id属性は、本来は、ページ内で一意になっているはずなので、お行儀の良いウェブサイトで、id属性が各要素にちゃんと用意されている場合、要素の特定が非常に楽になります。
ただ、世の中にはお行儀の悪いウェブサイトが予想以上に多いです。かなしみ。

③要素名で特定する

id属性による特定が上手く行かない場合、要素名(タグ名)で特定出来るケースがあります。
例えば

<div id="main">
  <a href="https://sample.com">サンプルリンク</a>
  <span>上記のリンクをクリックしたいんじゃが</span>
</div>

こんな風になっていて、a要素を取得したいのにa要素にはidがない。しかしページ内にa要素は一つしかない。と言うような場合はラッキーです。a要素を引っこ抜けばいいです。

link = driver.find_element(by= By.TAG_NAME, value= "a")

要素名(タグ名)が「a」のものだけちょーだい、という命令です。

ただ、実際の所、aがページ内に1個だけなんてことは早々ないですね。そういう場合、list形式で取得されます。なので、ページの構成が固定で、常に上から3番目のリンクを踏みたいようなときは

links = driver.find_element(by= By.TAG_NAME, value= "a")
target_link = links[2]

のように特定してあげることもできます。

④XPATHで指定する

他にもclass属性で指定したり色々できますが、コレ一つ使えれば大概の事ができちゃうのがXPATHによる指定です。
コレを使えば、アンカーテキスト(aタグの中身じゃなくて、aタグが囲んでる文字列)や、ボタンに書いてあるテキストで要素を特定したり、タグの階層構造を追いかけて特定したり、などのトリッキーなことが出来ます。

# 「投稿」と書かれたボタンを取得する
commit_button = driver.find_element(by=By.XPATH, value= '//input=[@value="投稿"]' )

# 「リンク」という文字列に貼られたリンクを取得する
a_link = driver.find_element(by=By.XPATH, value='//a[text()="link"]')

# tableタグの子孫のtr要素の子孫のtd要素の子孫であるlinkタグを取得する
a_in_table = driver.find_element(by=By.XPATH, value='//table//tr//td//a')
  • XPATHはタグの階層構造を「//」で区切りながら記述することが出来ます。最初に「//」を書くと後方一致的な感覚になります。

  • XPATH内で「"」が必要になる場合、「value='…'」に使うクオーテーションをシングルにします。

  • value属性を持つタグのvalue属性で特定したいときは、「//input=[@value="HOGE"]」が使えます。

  • アンカーテキストで特定したいときは「//a[text()="HOGE"]」が使えます

⑤一度取得した要素の中からさらに要素を絞り込む

<div id = "main">
  <a href="https://sample.com/hoge">
    <h1> pagetitle </h1>
  </a>
</div>
<div id = "sub">
  <a href="https://sample.com/page1">page1</a>
  <a href="https://sample.com/page2">page2</a>
</div>

たとえばこのような構造のHTMLがあったとして、「main」のdivの中にあるa要素だけ取りたい……と言うときは、まずmain要素を取得して、その中からさらにa要素を絞り込む、と言うことが出来ます。

main_contents = driver.find_element(by= By.ID, value= "main")
main_a = main_contents.find_element(by= By.TAG_NAME, value = "a")

と言う具合に、find_element()から返ってきたオブジェクトに対してまたfind_element()が掛けられます。

大体このいずれかの方法を使えば、大半の要素は特定出来るかと思います。

テキストボックスのテキストを操作する - send_keys()、clear()、get_attribute()

テキストボックス(input要素)を取得したら、テキストが入力出来ます。

text_box = driver.find_element(by= By.ID, value="text-input")
text_box.send_keys("入力したいテキスト")

これだけ。

ちなみに、send_keysメソッドは「今入っているテキストの末尾に追記」なので、既にテキストが入力されているテキストボックスの場合、一度内容を削除する必要があります。

text_box.clear()

で消えます。

また、「今入っているテキストの頭に追加」したい場合、いったんテキストの内容を取得しておく必要があります。

text = text_box.get_attribute("value")

でテキストを取得することが出来ます。
取得したテキストに必要な文字を足してsend_keys()すれば文頭への追記ができます。

ドロップダウンリストを選択する - Select、select_by_visible_text()

ドロップダウンメニューを操作するには、まず取得した要素を使ってSelectオブジェクトを作ります。その後、select_by_visible_textを使って選びたい選択肢を選ばせます。(表示されている選択肢テキストを指定する方法です)

from selenium.webdriver.chrome.service import Select

dropdown = Select(driver.find_element(by= By.ID, value="dropdown"))
dropdown.select_by_visible_text("選択肢1")

選択肢に振られたIDなどで選択する方法もありますが、とりあえず選択肢のテキストで選べれば、ひとまず困ることはないかなと……

ボタンやリンクをクリックする - click()

そのまんまですね。

submit = driver.find_element(by=By.ID, value="submit")
submit.click()

で、クリック出来ます。

とりあえずここまでで、ページにアクセスして、操作や入力をして、確定ボタンを押す、という作業が出来るようになります。

この記事が気に入ったらサポートをしてみませんか?