selenium×Chromeによるスクレイピング- Python

seleniumとは

Pythonにはいくつかのスクレイピングライブラリがありますが、seleniumはその中でも、「ブラウザを操作する」タイプのライブラリです。

操作できるブラウザの種類も多く、ChromeやPhantomJS、FireFox、Edgeなどを自動操作することが出来ます。

操作するブラウザとして、以前は特別色々インストールせずともサクッと使いやすい PhantomJS が良く選ばれていたようですが、開発を終了したことや、そもそもクロームのシェアが高い事、Chromeが完全にヘッドレスに対応したこともあり、今ではChromeとの組み合わせで使うのが結構主流です。

selenium概要
  • ブラウザをマクロ的に自動操作できるライブラリ。
  • 本来はWebページのテスト用ツール。
  • データの取得・収集を目的とした、スクレイピングの用途にも使われる。
  • さまざまな種類のブラウザを操作可能。

seleniumでできる事

Pythonのスクレイピングライブラリとして非常にメジャーなhttpインターフェイスのrequestsと比較した場合、ブラウザ自動操作系のseleniumの最大の特徴としてJavaScriptの動作が挙げられます。

requestsなどのhttpリスエストのみを行うライブラリはJavaScriptによるサイトの内容の変化や、情報の展開を考慮することが出来ません。

JavaScriptによる動的な変化に対応したBot操作を行いたい場合はseleniumを選ぶことになるでしょう。

seleniumを使うメリット
  • JavaScriptによる動作を考慮したBotが作れる。
  • ログインの必要なページにも簡単にアクセスできる。

対して、デメリットとしてはJavaScriptなどによる実際のレンダリングエンジンが走るため、動作が遅い、且つ、クリックなどのメソッドは不安定になりがちです。

あと、超個人的な感想ですが、DOM操作系のメソッド記述がやたらダラダラと長ったらしいのも不満点だったりします。

純粋にスピードや安定感重視のBotを組みたいだけであれば、敢えてseleniumを選ぶメリットはありません。

seleniumを使うデメリット
  • ブラウザの描画処理があるので処理が遅い。
  • 動作は安定性に欠ける。
  • DOM操作系のメソッドの記述がやたらと長い。

seleniumのインストール

pipで一発インストールできます。

Chrome Driver のインストール

seleniumのインストールだけではブラウザを操作することが出来ません。

ブラウザとseleniumの間に中継するドライバが必要なのでそれをインストールする必要があります。

FireFoxなど元々seleniumにドライバが組み込まれている一部ブラウザであれば、この操作は必要ありません。

今回はChromeを操作するためのドライバーをインストールしていきます。当たり前ですが、ドライバー単体では動作しませんのでChromeの本体インストールは必須です。

Chrome Driverのインストールに関しては環境によるところが大きいので、今回は一般的なWindows環境を前提とします。

Chrome Driverのダウンロード

こちらからダウンロード

注意点として、インストール済みのChromeのバージョンとChromeDriverのバージョンを合わせてダウンロードする必要があります。

クロームのバージョン

Chrome Driverの設置

windowsのChrome Driver自体は一つの実行形式のexeファイルです。

任意のディレクトリに置いて、そのディレクトリにPathを通す必要があります。

seleniumでChromeを操作する

インポートして準備完了。

seleniumでChromeを立ち上げる

Chromeをヘッドレスで立ち上げる

VBAでいうところの IE.Visible = False のようなバックグラウンド状態でクロームを操作できます。

'--no-sandbox' と '--disable-gpu' は何なのかよく分かりませんが、これを指定しないと僕の環境ではエラーになります。環境によっては '--headless' だけで動作する場合もあるみたいです。

任意のURLにアクセス

現在のURLを取得

現在のページタイトルを取得

ブラウザで表示中の全ソースを取得

非常に個人的な感想ですが、単純にHTMLをパースするだけの使い方の場合は、selenuimはメソッドが長ったらしくてあまり好みではありません。

表示中のページソースを全て取得できるので、そのまま引き渡すことで、BeautifulSoupを使ったパースが可能になります。

ブラウザの更新

タブ(ウインドウ)を閉じる

現在アクティブのタブのみを閉じます。

全てのタブ(ウインドウ)を閉じる

特定の要素を取得

指定した要素がpage_source内に存在しない場合は例外が発生する。

特定の要素を全て取得

elementをelementsに変更するとリストで要素が返却されてきます。

idはページ内に1つしかないことが構文上の約束事ですが、seleniumではelementsとしても通ります。もちろんリストで返却されます。

要素が存在しない場合は例外ではなく、空のリストが返却されます。

要素が存在するかどうか確認する方法

[find_elements ~ ]では、該当する要素が存在しない場合は例外ではなく「空のリスト」が返却されてきますので、この性質を利用して、要素の存在を確認することが出来ます。

特定の要素をクリック

ブラウザを操作することが出来るので、要素をクリックすることもできます。

特定の要素までスクロール

クリックメソッドですが、ウインドウ内に要素をとらえていない場合、上手く実行できないときがあります。

そういった場合、その要素の位置までスクロールする必要があります。

事前に ActionChains の import が必要です。

特定の要素にテキストを入力

勿論、テキストを入力することも可能。ログインの操作などがrequestsと比べ楽に実装できます。ぶっちゃけ、これがselenium最大のメリット(使いどころ)だと個人的には思っています。

ちなみにエクセルのVBAによるIE操作と違って、NumLockされて変な感じになったり、OSで他の操作してたらsend_keysが失敗したりはしないので、安心して使えます。

テキスト以外のキーを入力

単純なテキスト入力ではなくキーボードのENTERやTABなどのキーを入力することもできます。事前に Keys の import が必要です。

send_keysに複数の引数を渡すと左から順に全てのkeyを送信します。

要素がウインドウ内に表示されているか

要素がアクティブかどうか

ボタンがグレーアウトして押せない場合などを判定できる。

要素が選択されているか

ウインドウサイズの最大化

覚えておくと便利な小技

ChromeDriverのゴミインスタンスを一括kill

エクセルのVBAを使ったスクレイピングを書いている時なんかもアリがちなんですが、デバッグやらなんやらでコードを書いているうちに殺しきれなかったChrome Driverのインスタンスのゴミが大量にバックグラウンドに残っている時があります。

夢中になってコード書いてると、一面Chromedriver.exeで埋め尽くされていることなんかもあります。

seleniumの場合はほとんどありませんが、VBAの場合なんかだとメモリ圧迫されまくってIEが立ち上がらなくなってから気づくんですよね(笑)

Pythonならsubprocess モジュール使って直接殺していってもいいんですが、僕はbatファイルをあらかじめ作ってそれで一気にkillするようにしています。

一括でChromeDriverをkillできます。

selenium × Chrome によるログイン処理

requestsなどのHTTPの送受信のみを行うインターフェイスと違いブラウザの自動操作系のインターフェイスの利点の一つにログイン処理を楽に行えるという点があります。

そもそもJavaScriptによってBot判定がなされているサイトもあり、ブラウザ利用以外でのログインが難しい場合も多いです。

selenium を使ってChromeを操作すれば、それらの認証を通過して、ログインユーザーにしか扱えないページにBotアクセスすることが可能になります。

selenium × ChromeでYahoo!にログインする

ヤフーのログインフォームを入力するサンプルです。

これでヤフーにログインした状態のブラウザの状態を作り出すことが出来ます。

一行ずつ追っていけば、普通のマクロ的な動作しかしていないので、割と簡単ですね。

ログイン状態を維持したまま操作をrequestsで行う

seleniumによるログイン処理は、普通にブラウザからアクセスするのと同じ操作をトレースすることで可能になりますので、非常に実装が楽になります。

ただ、情報を収集したり、変化を監視するといった用途のBotを組んでいく場合、seleniumは動作の速度や安定性に欠ける部分があります。

ブラウザの描画が必要な分、多少仕方ない部分ではありますが、ログイン処理後の動作にJavaScriptのエンジンが必要でない場合、その先をrequestsによって行うことが出来ます。

それぞれのライブラリに得意な部分のみを担当させるイメージです。

オススメの処理担当
  • ログイン処理 → selenium × Chrome
  • クロール処理→ requests × BeautifulSoup

HTTPと言うプロトコルは、一度のリクエストで完結し、前後の処理の相関を保持することが出来ません。簡単にいうと、一回ぽっきり。すぐに忘れます。つまり、HTTPはログインしたことなど、覚えていません。

では、何故ページをめくってWebサイトの中を回遊してもログイン状態が維持されているのか?というと、ログインセッションと言うのは基本的にCookieを使って管理されているからです。

Cookieと言うのはクライアント側(ブラウザ)に書き込まれる、メモ書きのようなもので、色々な用途に利用されますが、ログインの判定はその代表例です。

つまり、特定サイトにログインした状態のCookieがあり、尚且つ、そのCookieが有効期限内であれば、別のインターフェイスからそのサイトにアクセスしてもログイン状態を維持することが出来ます。

上記処理で、seleniumでログインした状態のChromeブラウザのクッキーをrequestsのsessionインスタンスに引き渡すことが可能です。

その後はログインユーザー用のページをsession.get()で取得可能になります。

サイトの構造によっては使えないパターンもありますが、多くのサイトで使えるはずです。

seleniumでユーザープロファイルを指定してChromeを立ち上げる

ここまで、seleniumを用いてログインの必要なページを操作する処理を紹介してきました。

が、普段からChromeをメインのブラウザとして使っているのであれば、面倒なログインの処理なんかはすっ飛ばして、ログインした状態を作り出すことが出来る方法があります。

見出しにもある通り、Chromeに備わっている、ユーザープロファイルと言う機能をオプションとして指定することによって、普段使っている状態のChromeブラウザをそのまま操作することが可能になります。

以下でどういうことなのか詳しく説明していきます。

seleniumでChromeを立ち上げた時

まずはユーザープロファイルの指定をせずに、seleniumからChromeを立ち上げた場合の挙動を見ていきます。

ブックマークやユーザー名、拡張機能など、全てまっさらな状態で立ち上がります。

「Chrome は自動テスト ソフトウェアによって制御されています。」という、アラートも確認できます。

seleniumでユーザープロファイルを指定してChromeを立ち上げた時

次に、普段使っているChromeと全く同じ状態でseleniumから起動させる方法です。

seleniumを立ち上げたときの自動操作のメッセージが出ながらも、拡張機能やブックマークなどが表示されているのが確認できると思います。

ちなみにユーザープロファイルのパスは環境によって変わります。

ユーザープロファイルフォルダの確認方法
  • Chromeを起動する。
  • URLバーに chrome://version と入力して開く。
  • [プロフィール パス] の欄にパスが記述されているので確認する。

これでいつも使っている状態のChromeで自動操作を行うことが可能になります。

これで厄介な「reCAPTCHA」も突破しやすくなります。

突破しやすくなるというよりは、そもそもログインした状態を維持して立ち上げられます。(サイトやログイン方法によりますが。)