サイトアイコン 上尾市のWEBプログラマーによるブログ

「Node.jsでブラウザを自動操作してみよう」の感想・備忘録1

kindle本「Node.jsでブラウザを自動操作してみよう」のまとめ。
Node.jsとseleniumを使ってブラウザを操作する、という内容だった。

点数

83点

良かった点

悪かった点

主な内容・参考になった点など

Selenium WebDriverとは

ブラウザを自分で書いたコードによって操作することできる。
以下2つのソフトが必要。

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のメソッド

スクリーンショット取得の例
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のメソッド

※submit()はChrome ver75からデフォルトでは使えなくなった。(W3CモードがデフォルトONになった)

Locatorの種類

xpathでの指定方法

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();
モバイルバージョンを終了