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

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();

【新しい記事】

【古い記事】

コメントを残す

メールアドレスが公開されることはありません。