5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

岩手県立大学とか、岩手の人たちAdvent Calendar 2021

Day 17

Selenium webdriverの仕様&仕様変更でちょっとつまづいた話

Last updated at Posted at 2021-12-19

先日、とあるサイトのクローリングのためにスクリプトを書くことになったが、getリクエストをしただけでは取ってこれないサイトであったためSelenium-webdriverを使うことになった。
しかし結構いろんなことで躓いたのでメモとして残しておく。

① xpathの指定の際に添え字が使えない(これが大問題)

例えば、id=fugafugaのdiv→div→ulの中に

example.html
<li class="hoge">
    <div>
        <label class="hoge-label">
            <input type="checkbox" class="hoge-checkbox" value="目的のテキスト1">
            <span class="hoge-labelText">目的のテキスト1</span>
            <span class="hoge-count">目的のテキスト2</span>
        </label>
    </div>
</li>
<li class="hoge">
    <div>
        <label class="hoge-label">
            <input type="checkbox" class="hoge-checkbox" value="目的のテキスト1">
            <span class="hoge-labelText">目的のテキスト3</span>
            <span class="hoge-count">目的のテキスト4</span>
        </label>
    </div>
</li>
これが続く...

このようにli属性がたくさん書かれていて、
「目的のテキスト1,2,3,4…」の部分をxpath経由で取ってきたいとなった場合、
Chromeのデベロッパーツールでxpathをコピーすると

//*[@id="fugafuga"]/div/ul/li[1]/div/label/span[1]
//*[@id="fugafuga"]/div/ul/li[1]/div/label/span[2]

このようなフォーマットで出てくる。

しかし、これをそのままぶちこんで

driver.find_element(By.XPATH,f'//*[@id="fugafuga"]/div/ul/li[1]/div/label/span[{i}]')

なんてしてforループで回そう...なんて方法は使えない。
どうやら挙動を見たところ、Selenium-webdriverのfind_elementsは
マッチした要素を順番に配列に格納していくようである。
(ちなみにマッチした要素は selenium.webdriver.remote.webelement.WebElementで返ってくる)
そのため、今回の場合は

liの添字 1つめのspanが格納される添字 2つめのspanが格納される添字
0 0 1
1 2 3
2 4 5
$\vdots$ $\vdots$ $\vdots$
n 2n 2n+1
なので、
driver.find_elements(By.XPATH,'//*[@id="fugafuga"]/div/ul/li/div/label/span')[2*i].text
driver.find_elements(By.XPATH,'//*[@id="fugafuga"]/div/ul/li/div/label/span')[(2*i)+1].text

とすることでようやく出てくるのである。ちょっとした算数。

これが更に上の階層でも添字が用いられている場合は図や計算が複雑になるので省くが、ちょっと計算することになるという点にだけ注意。

② 画面遷移を挟む際に適当にsleepしないとStaleElementReferenceExceptionになる(当たり前)

driver.get('https://google.co.jp')

のようにページ遷移や更新などの処理をした際、ページが完全に読み込まれていないのに
即属性指定→クリックのような動作を行おうとするとエラーが出る。
ちゃんと適切な秒数sleepすること。

③find_elementとfind_elementsの違い

メソッド 戻り値
find_element 要素一つ
find_element s マッチした要素が格納された配列
適宜使い分けること。

④driver.find_element_by_*が非推奨になった(超重要)

selenium-webdriverは最近仕様変更が行われ、以前は

driver.find_element_by_xpath('hoge')

で要素取得できていたものが

driver.find_elements(By.XPATH,'hoge')

のように
By.*で第一引数に指定しなければならなくなった。
また、これを使うときには

from selenium.webdriver.common.by import By

でインポートしてやらなくてはならない。
詳しくはここを参照すること。
find_element_by_* commands are deprecated in selenium - StackOverflow

おわりに

添字が使えないってのはちょっとショックだった。
こういう感じでたまーに仕様変更があったりすると既存のサイトの情報が全く使えないなんてこともあるので気をつけなくては...

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?