入社してこの方、全く開発をしていない僕も一応はITエンジニアを名乗るだけの人権を手に入れるべく、ここ三ヶ月ほどPythonの勉強をしている。
Pythonにおけるクローリング*1やスクレイピング*2のライブラリ*3にSeleniumというものがあり、これが使えるとかなり色々なことができて楽しい。
参考書として『退屈なことはPythonにやらせようーノンプログラマーにもできる自動化処理プログラミング』(オライリー・ジャパン)を使用していて、これがまたわかりやすい。
ノンプログラマー向けを謳っているだけあって、クラスだのなんだのの説明は省いて、ひとまず最低限の知識でできる自動化処理を広く解説してくれている。
大体7割ほど読み進めたところだが、以下のようなことはできるようになった。
- 指定したWebサイトへの自動ログイン
- 特定の時間にネットワーク速度を測定してエクセルへ記録
- 米ドルー日本円の為替状況を自動収集 等々
一方で、クローリングやスクレイピングはなかなか一筋縄ではいかないことも多い。
SeleniumはWebサイト*4を読み込んで、その要素を取り出しているわけだが、Webサイトも千差万別、エラー原因もそれこそ山のようにある。
せっかくなので、僕がSeleniumで足止めを喰らったエラーと原因、その解決策を備忘がてら書いていく。
解決策は基本的に諸先輩がたのをお借りするとともに、掲載先のリンクを貼っておくので、興味がある方や詳しく知りたい方はそちらも参照されると良い。
【エラー】そもそも欲しい情報(要素)が取得できない
Seleniumでは、まず欲しい情報(要素)をfind_element()またはfind_elements()で指定して取得するのだが、大体ここでつまづくことが9割。
取得できない原因は大きく分けて、二つある。
- 要素の指定方法が間違っている
- Webサイト(ソースコード)に何か原因がある
7割くらいは前者(つまりは僕の凡ミス)なのだが、後者っぽいと思った場合に、Webサイト上のどこに原因があるのかを探っていくことになる。
【解決策1】親タグから順に取得してみる。
取得したい要素のタグ*5(要素)に向かって、最も上位のタグ(htmlタグ)から順々に要素の取得(htmlタグ→bodyタグ→...といった感じ)を試してみると、どこかでエラーを吐くので、そのタグに何か原因がないか確認してみる。
誰に聞いたわけでもないが、色々と試行錯誤していく中で割と効果的だなと感じた方法。
ここからは個々の原因とその解決策について
【原因】画面の読み込みが完了していない。
Webサイトによっては画面の読み込みに時間がかかる場合がある。
こうなると、Seleniumが要素を探そうにも、対象がないわけなので、エラーとなる。
【解決策】待機処理を入れる。
解決策は簡単、待ってあげよう。
【原因】別のWebサイトが埋め込まれている。(iframe)
Webサイト上にYouTubeの動画が埋め込まれているのを見かけるかと思うが、あれはiframeという機能を使って別のWebサイトを埋め込んでいる(らしい)。
Seleniumで指定した動作対象(Webサイト)にはiframeで埋め込んだ別のWebサイトは含まれない。
YouTubeのように露骨に埋め込みだとわかる場合は良いのだが、私が見たWebサイトは一部のデータ項目だけiframeで埋め込まれていて、一見すると通常のWebサイトにしか見えなかった。
【解決策】動作対象をiframe内に移してから要素を取得する。
対象を一度iframe内に移してから要素を取得することで可能になることがある。
【エラー】ボタンがクリックできない。
Seleniumはclick()で取得した要素(ボタン)をクリックすることができるのだが、これも結構な確率で動作しないことがある。押して。
【原因】ボタンが画面外にある。
click()は画面外にあるボタンは押せない仕様。
【解決策】画面をスライドし、ボタンを画面内に入れる。
ボタンが画面内にくるように、ボタンもしくはその周囲の要素を対象に画面をスライドさせてあげる。
【原因】ボタンが不活性(disable)
たとえば、ログイン画面でIDとパスワードが入力されるまでボタンがクリックできないWebサイトがあるかと思うが、あれはボタンが不活性(disable)状態にある。
IDとパスワードをSeleniumで自動入力し、click()でボタンを押そうとした時に、入力後にボタンが活性化される速度よりもSeleniumの動作が早いとclick()できなくてエラーに。
【解決策】待機処理を入れて活性化されるのを待つ。
待機処理を入れてボタンが活性化されるのを待つ。
【エラー】テキストが取得できない(空白が返ってくる)
取得した要素から、Webサイト上に表示されているテキストを取得しようとしたところ、なぜか空白文字列が取得されてしまった。
【原因】CSSプロパティが非表示(:none, ::hidden)になっている
CSSプロパティがdisplay:noneやvisibility:: hiddenに設定されている要素は非表示扱いになり、テキストが取得できないとのこと。なんじゃそりゃ。
【解決策】get_attribute()を使用
要するに、表示されているテキストではなく、要素の属性(attribute)として設定されている値を取得すれば、表示・非表示とは関係なく値が取得可能といった感じ。
他にも色々あった気はするが、ひとまずはこれくらい。
それにしても、しっかり解決策を出されていて本当に素晴らしい。