kindle本「Node.jsでブラウザを自動操作してみよう」のまとめ。
Node.jsとseleniumを使ってブラウザを操作する、という内容だった。
点数
83点
良かった点
- 「JavaScriptでブラウザ操作を一通りできるようになる」という最低限の目的は達成できた
- 後半の動作テストでMochaとChaiが使われていたので勉強になった
悪かった点
- 不要なページが多く、無駄に長かった
- 目次の構成が甘く、読みづらかった
主な内容・参考になった点など
Selenium WebDriverとは
ブラウザを自分で書いたコードによって操作することできる。
以下2つのソフトが必要。
- Selenium Client:Seleniumを実行するためのライブラリー
- ChromeDriver:SeleniumからChromeを制御したり、Chromeの状態を取得するためのツール
Selenium ClientからChromeDriverへのメッセージはJsonWireProtocolを使ってHTTP通信で行われる。
(curlでlocalhostに通信して確認することもできるが、やる意味はないと思う)
node.jsでコードを書く場合、Selenium Clientはnpm install selenium-webdriver
でインストール可能。
ChromeDriverはseleniumのサイトでダウンロードできる。(npm install chromedriver
でも可能、その場合はnode_modules/chromedriverの中にファイルが格納される)
ChromeDriverはPATHが通ったディレクトリに置く、または、読み込み時にパスを指定する必要がある(後述)
Selenium IDEはFirefox55以降では使用できなくなった
awaitとasync
awaitはasyncを付けた関数の中だけで使用することができ、Promiseオブジェクトを返却するメソッドにawaitを付けて呼び出すと結果が返ってくるまで待機する。
awaitを付けないと戻り値はPromiseオブジェクトとなり、付けると戻り値はresolvedかrejectedの実行結果となる。
同じコードでもブラウザやサイトによっては動かないことがある。その場合は途中でsleepを入れるしかない。
自動操作のメソッド
WebDriverのメソッドとWebElementのメソッドがある。
https://selenium.dev/documentation/en/webdriver/browser_manipulation/
https://qiita.com/tonio0720/items/70c13ad304154d95e4bc
https://selenium.dev/selenium/docs/api/javascript/
WebDriverのメソッド
- 更新:driver.navigate().refresh();
- ウィンドウ最大化:driver.manage().window().maximize();
- ソース取得:driver.getPageSource();
- スリープ:driver.sleep(ミリ秒);
- JS実行:driver.executeScript(‘alert(“test”);’);
- スクリーンショット取得(バイナリのbase64):driver.takeScreenshot();
スクリーンショット取得の例
const fs = require('fs');
const encodedData = await driver.takeScreenshot();
await fs.writeFile('screenshot.jpg', encodedData, 'base64', (err) => {
if (err) {
// エラー時
} else {
// 正常時
}
);
スクリーンショット取得の例(Buffer.fromを使う場合)
const fs = require('fs');
const encodedData = await driver.takeScreenshot();
const buffer = Buffer.from(encodedData, 'base64');
const { promisify } = require('util');
await promisify(fs.writeFile)('screenshot.jpg', buffer);
WebElementのメソッド
- click()
- sendKeys()
- clear()
- isSelected()
- isEnabled()
- isDisplayed()
- getText()
※submit()はChrome ver75からデフォルトでは使えなくなった。(W3CモードがデフォルトONになった)
Locatorの種類
- CSSセレクタ:webdriver.By.css()
- リンクテキスト:webdriver.By.linkText()
(部分一致の場合はwebdriver.By.partialLinkText()) - xpath:webdriver.By.xpath(“//xpathをここに記述”)
xpathでの指定方法
- //タグ名[@属性名=’値’] ※完全一致
- //タグ名[text()=’テキスト’] ※完全一致
- //タグ名[contains(@属性名, ‘値’)] ※部分一致
- //タグ名[contains(text(),’テキスト’)] ※部分一致
- //タグ名[starts-with(@属性名, ‘テキスト’)] ※先頭一致
- //タグ名[starts-with(text(), ‘テキスト’)] ※先頭一致
タグ名は*ですべてのタグ
andで複数指定が可能。 - //a[@text=’あいう’ and @class=’hoge’]
/で親子指定が可能。 - //select[@id=’month’]/option[@value=’7′]
//following::で次の要素の指定が可能。 - //label[text()=’test’]//following::a[text()=”test2″]
Google検索を自動化するコード
const webdriver = require('selenium-webdriver');
const driver = new webdriver.Builder().forBrowser('chrome').build();
async function main() {
await driver.get('https://www.google.com/');
const element = await driver.findElement(webdriver.By.css('[name="q"]')).sendKeys('上尾 天気');
// 検索ボタンクリックがうまくいかないのでexecuteScriptを利用
// const element2 = await driver.findElement(webdriver.By.css('[name="btnK"]')).click();
await driver.executeScript("document.querySelector('" + '[name="btnK"]' + "').click()");
// リンクの出現を待つ
await driver.wait(webdriver.until.elementLocated(webdriver.By.xpath('//h3[text()="上尾市の天気 - Yahoo!天気・災害"]')), 10000);
await driver.findElement(webdriver.By.xpath('//span[text()="上尾市の天気 - Yahoo!天気・災害"]')).click();
}
main();
node search_google.js
で実行
chromedriverをPATHの通っていないディレクトリに格納する場合
以下のようにすると、任意のディレクトリに格納することができる。
(この例では、jsファイルと同じディレクトリにchromedriverを格納している)
const webdriver = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const driver = new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.setChromeService(new chrome.ServiceBuilder(__dirname + "/chromedriver.exe"))
.build();