Posted at

Nodejsを使ってSeleniumでChromeを動かす

More than 1 year has passed since last update.


はじめに

Seleniumとは、WebアプリケーションのUIテストツール。

動的なサイトのスクレイピングツールとしても使われている。

今回はSeleniumをNode.jsで動かす方法を紹介する。


ドキュメント(英語版)

https://seleniumhq.github.io/selenium/docs/api/javascript/index.html


使用方法


事前準備(Windowsの場合)


インストール

npm i selenium-webdriver


ChromeDriverのダウンロード

ChromeDriver – WebDriver for Chrome

https://sites.google.com/a/chromium.org/chromedriver/downloads

実行ファイルと同じパスに配置


基本操作


ライブラリのインポート

const webdriver = require('selenium-webdriver');

const { Builder, By, until } = webdriver;

良く使うBuilder, By, untilをここで定義


設定(Chromeの場合)

const capabilities = webdriver.Capabilities.chrome();

capabilities.set('chromeOptions', {
args: [
'--headless',
'--no-sandbox',
'--disable-gpu',
`--window-size=1980,1200`
// other chrome options
]
});


Chrome Options

https://peter.sh/experiments/chromium-command-line-switches/


ブラウザの立ち上げ

const driver = await new Builder().withCapabilities(capabilities).build();

// ブラウザを終了する

driver.quit();

※基本的に返り値がpromiseなので、async/awaitを使う


ページ移動

await driver.get('https://www.youtube.com/');


要素の特定


// タグ名で特定
let el1 = await driver.findElement(By.tagName('hoge'));
let el2 = await driver.findElement({ tagName: 'hoge' });

// idで特定
let el1 = await driver.findElement(By.id('foo'));
let el2 = await driver.findElement({ id: 'foo' });

// classで特定
let el1 = await driver.findElement(By.className('bar'));
let el2 = await driver.findElement({ className: 'bar' });

// cssセレクタで特定
let el1 = await driver.findElement(By.css('#foo'));
let el2 = await driver.findElement({ css: '#foo' });

// 複数要素の特定
let els1 = await driver.findElements(By.css('.bar'));
let els2 = await driver.findElements({ css: '.bar' });


要素から属性の取得


let el = await driver.findElement(By.css('#foo'));

// テキストを取得
let text = await el.getText();
// ↑だとなぜか動かない場合はこちら
let innerHTML = await el.getAttribute('innerHTML');

// その他属性の取得
let href = await el.getAttribute('href');


応用編


待ち処理

/**

* xxx:関数名
* timeout:タイムアウト時間(ミリ秒)
*/

await driver.wait(until.xxx(), timeout);


要素の出現

// 要素の出現を待つ

await driver.wait(until.elementLocated(By.id('foo')), 10000);
await driver.wait(until.elementsLocated(By.className('bar')), 10000);


URL条件

// 完全一致

await driver.wait(until.urlIs('xxx'), 10000);

// 部分一致
await driver.wait(until.urlContains('xxx'), 10000);

// 正規表現
await driver.wait(until.urlMatches(/xxx/), 10000);


タイトル条件

// 完全一致

await driver.wait(until.titleIs('xxx'), 10000);

// 部分一致
await driver.wait(until.titleContains('xxx'), 10000);

// 正規表現
await driver.wait(until.titleMatches(/xxx/), 10000);


特定要素のテキスト条件

let el = await driver.findElement(By.css('#foo'));

// 完全一致
await driver.wait(until.elementTextIs(el, 'xxx'), 10000);

// 部分一致
await driver.wait(until.elementTextContains(el, 'xxx'), 10000);

// 正規表現
await driver.wait(until.elementTextMatches(el, /xxx/), 10000);


要素の状態

let el = await driver.findElement(By.css('#foo'));

// enabled
await driver.wait(until.elementIsEnabled(el), 10000);

// disabled
await driver.wait(until.elementIsDisabled(el), 10000);

// selected
await driver.wait(until.elementIsSelected(el), 10000);

// not selected
await driver.wait(until.elementIsNotSelected(el), 10000);

// visible
await driver.wait(until.elementIsVisible(el), 10000);

// not visible
await driver.wait(until.elementIsNotVisible(el), 10000);


スクリーンショットを撮る

// スクリーンショット画像をbase64でエンコードしたもの

let base64 = await driver.takeScreenshot();

// bufferに変換
let buffer = Buffer.from(base64, 'base64');


サンプル

Youtubeのスクリーンショットを撮るサンプル


sample.js

const fs = require('fs');

const { promisify } = require('util');
const webdriver = require('selenium-webdriver');
const { Builder, By, until } = webdriver;

const capabilities = webdriver.Capabilities.chrome();
capabilities.set('chromeOptions', {
args: [
'--headless',
'--no-sandbox',
'--disable-gpu',
`--window-size=1980,1200`
]
});

// awaitを使うので、asyncで囲む
(async () => {

// ブラウザ立ち上げ
const driver = await new Builder().withCapabilities(capabilities).build();

// Youtubeへ移動
await driver.get('https://www.youtube.com/');

// 検索ボックスが表示されるまで待つ
await driver.wait(until.elementLocated(By.id('search')), 10000);

let base64 = await driver.takeScreenshot();
let buffer = Buffer.from(base64, 'base64');

// bufferを保存
await promisify(fs.writeFile)('screenshot.jpg', buffer);

// ブラウザ終了
driver.quit();

})();