先日、とあるサイトのクローリングのためにスクリプトを書くことになったが、getリクエストをしただけでは取ってこれないサイトであったためSelenium-webdriverを使うことになった。
しかし結構いろんなことで躓いたのでメモとして残しておく。
① xpathの指定の際に添え字が使えない(これが大問題)
例えば、id=fugafugaのdiv→div→ulの中に
<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
おわりに
添字が使えないってのはちょっとショックだった。
こういう感じでたまーに仕様変更があったりすると既存のサイトの情報が全く使えないなんてこともあるので気をつけなくては...