NodeJS + Selenium IDE/WebDriverで最強スクレイピング
ここ数日、「DIGAの番組表」と「東京電力の『でんき家計簿』」でスクレイピング用のプログラムを作成してみましたが、NodeJS+CasperJS+PhantomJSよりも、NodeJS+Selenium IDE/WebDriverの方が、簡単でした。スクレイピングには、NodeJS+Selenium IDE/WebDriverが最強な気がします。そこで、NodeJS+Selenium IDE/WebDriverを使ったスクレイピングの簡単な手順をメモとして残しておきたいと思います。
- DIGA番組名一括変更ツールの一部をCasperJSで記述 - Itsukaraの日記
- DIGA番組名一括変更ツールの一部をSelenium WebDriverを使って記述 - Itsukaraの日記
- 東京電力「でんき家計簿」の時間別グラフのデータ自動抽出 - Itsukaraの日記
NodeJS + Selenium IDE/WebDriverのうれしい点
Seleniumでは、スクレイピングしたいサイトにアクセスする手順をSelenium IDEが自動的に記録できるます。また、この記録結果を、適切な形式でエクスポートすると、ほぼそのままの形で、NodeJS + Selenium WebDriverで流用できます。以下、簡単に説明します。
アクセス手順をSelenium IDEで自動的記録
FireFoxとSelenium IDE(FireFoxのPlugin)がインストール済みの前提で記載します。
- FireFox:https://www.mozilla.org/ja/firefox/new/
- Selenium IDE:https://addons.mozilla.org/en-US/firefox/addon/selenium-ide/
Selenium IDEをインストールすると、FireFoxの画面右上にSelenium IDEのボタンが現れます。(下図のマウスカーソルの部分)
Selenium IDEのボタンをクリックするとSelenium IDEの画面が現れて、対象となるサイトへの操作が自動的に記録されます。下記は、「東京電力の『でんき家計簿』」にログインし、電気使用量の時間別グラフを表示、「前日」のデータを表示するまでの操作手順です(IDとPASSWORDは伏せています)。
どこをクリックすればよいか、何を入力すればよいのか、Selenium IDEが自動的に記録するので、非常に便利です。また、Selenium IDEでは、記録した操作手順(テストケースと呼んでいます)を実行して試すことができます。テストケースを試すには、「アクション」メニューの「現在のテストケースを実行」を選択するか、画面左上の緑三角ボタンをクリックします。
テストケースがうまくいかない場合は、エラーとなったコマンドが赤く表示されるので、直ぐに分かります。Selenium IDEでは、エラーとなったコマンドを削除・修正したり、途中にコマンドを挿入したり、など、色々な試行が、画面を見ながら簡単にできます。この点は、CasperJSと比べて段違いに便利と思います。(CasperJSでは画面ショットを取らないと、現在の状態が分からない...)
下記は、「DIGAの番組表」での操作手順(テストケース)を、実際に動くように編集したものです。画面表示を待つためにコマンド「pause(3000)」を幾つか挿入してます。また、記録されていたコマンド「selectWindow(name=leftframe)」は、エラーとなるために削除しました。(削除しても問題なく動きました)
Selenium IDEのテストケースをエクスポート
NodeJS + Selenium WebDriverで流用できるようなコマンドを得るためには、Selenium IDEのテストケースを、「Java / JUnit 4 / WebDriver」という形式でエクスポートします(下図参照)。Javaの形式でエクスポートするのですが、NodeJSで、その一部をほぼそのままの形で流用できます。
下記は、「東京電力の『でんき家計簿』」でのアクセス手順を上記形式でエクスポートした結果のうち、流用できそうな部分を抜粋したものです。
public void setUp() throws Exception { driver = new FirefoxDriver(); baseUrl = "https://www.kakeibo.tepco.co.jp/"; driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); } @Test public void test1() throws Exception { driver.get(baseUrl + "/dk/aut/login/"); driver.findElement(By.id("idId")).clear(); driver.findElement(By.id("idId")).sendKeys("xxxxxxxx"); driver.findElement(By.id("idPassword")).clear(); driver.findElement(By.id("idPassword")).sendKeys("xxxxxxxx"); driver.findElement(By.id("idLogin")).click(); driver.findElement(By.id("idNotEmptyImg_contents01.jpg")).click(); driver.findElement(By.id("bt_time_view.jpg")).click(); driver.findElement(By.id("doPrevious")).click(); }
上記を次のような形に少し追加・修正し、JSファイルとして保存し、nodeで実行すると、うまく動きます(idIdとidPasswordの設定値は修正が必要)。後は、下記の関数「extract_function()」の部分で、FireFox側で実行する情報取得スクリプトを追加するだけです。これに関しては、Developer toolsで色々と試せばよいので、非常に簡単です。
// Initial Setting var webdriver = require('selenium-webdriver'), By = webdriver.By, until = webdriver.until; var driver = new webdriver.Builder() .forBrowser('firefox') .build(); // @Before baseUrl = "https://www.kakeibo.tepco.co.jp/"; driver.manage().timeouts().implicitlyWait(3000); // @Test driver.get(baseUrl + "/dk/aut/login/"); driver.findElement(By.id("idId")).clear(); driver.findElement(By.id("idId")).sendKeys("xxxxxxxx"); driver.findElement(By.id("idPassword")).clear(); driver.findElement(By.id("idPassword")).sendKeys("xxxxxxxx"); driver.findElement(By.id("idLogin")).click(); driver.findElement(By.id("idNotEmptyImg_contents01.jpg")).click(); driver.findElement(By.id("bt_time_view.jpg")).click(); // Extract driver.executeScript(extract_function, "test1", "test2").then(function(extracted_data) { // return value of extract_function() can be accessed by extracted_data console.log(extracted_data); // "test1,test2" will be written }); // Function executed in FireFox function extract_function(arg1, arg2) { var extracted_data; // Here, extract data from web page to extracted_data extracted_data = arg1 + "," + arg2; return extracted_data; }
なお、上記では、1つのページの情報を取得するのみでしたが、「前日」のデータを表示するための操作である「driver.findElement(By.id("doPrevious")).click();」など、他の操作も組み合わせれば、全ての日のデータを取得できます。
あとがき
最初のうちは、上記の一部しか把握していなかったため、手作業でNodeJS用のスクリプトを書いていました。そもそも、Java向けにエクスポートしたファイルが、ほとんどそのままでJavascriptで使えるとは思っていませんでした。試してみたら、そのまま使えるので驚きました。
ここに書いた内容が、少しでも役立てば幸いです。
なお、上記で書いた内容とは少し異なりますが、「東京電力の『でんき家計簿』」のデータ取得用スクリプトは、下記をご覧ください。
itsukara.hateblo.jp