Node.jsでseleniumを使ってChromeを自動操作する手順まとめ

Seleniumとは、Webアプリケーションの自動化を実現するブラウザ駆動型のテストツール群です。

GoogoleChromeやFirefox、Safari、Edge、Internet Explorerなど、
主要なブラウザを操作して様々な自動操作を行うことができます。

バックグラウンドでのスクレイピングでは取得できない動的なサイトのWebスクレイピングや、
Webブラウジング、タスクの自動化などにオススメです。

今回はNode.jsを使ってSeleniumからGoogleChromeを自動操作する方法を解説します。

Seleniumのインストール

ターミナルを開いて以下のコマンドを実行しましょう。

$ npm i selenium-webdriver

たったこれだけでseleniumをインストールすることができます。

Chrome Driverをダウンロードする

今回はChromeを自動化するので、そのためのドライバーをダウンロードする必要があります。
以下のいずれかの方法でダウンロードしましょう。

Homebrewからインストール

ターミナルから以下のコマンドを実行しましょう。

$ brew tap homebrew/cask
$ brew cask install chromedriver

公式サイトからダウンロード

ChromeDriver – WebDriver for Chrome
https://sites.google.com/a/chromium.org/chromedriver/downloads

ダウンロードしたファイルは実行ファイルと同じパスに配置しましょう。

Seleniumの設定を書く

const webdriver = require('selenium-webdriver');
const { Builder, By, until } = webdriver;
let driver = await new Builder().forBrowser('chrome').build();

Builder, By, untilなどよく使うものはまとめて宣言しておきます。
また、Seleniumの返り値がpromiseなので、基本的にはasync/awaitを使って書きます。

起動するChromeの設定(ヘッダーやサイズ)を調整したい場合は、以下の方法で起動すると良いです。

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

設定のコマンドは以下を参考にしてください。
https://peter.sh/experiments/chromium-command-line-switches/

終了時にseleniumを閉じる

driver.quit();

終了イベントなどに上記のコードを書いておきましょう。
これがないと、セッションにChromeが溜まり続けて重くなります。

seleniumで特定のサイトを開く

いよいよChromeを起動します。
以下のように書くと、Chromeが起動して指定したURLを表示します。

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

ページを遷移させたい場合も同じコードを書いてくだあい。

seleniumでDOMの取得

以下のように表示中の要素を取得することができます。

// タグ名で取得
let element = await driver.findElement(By.tagName('foo'));

// idで取得
let element = await driver.findElement(By.id('foo'));

// classで取得
let element = await driver.findElement(By.className('foo'));

// cssセレクタで取得
let element = await driver.findElement(By.css('#foo'));

seleniumで複数のDOMを扱う

複数の要素をまとめて取得することもできます。

ただし、返り値は Primise なので各要素を扱う場合は以下のようにしてください。
(JavaScriptでDOMを取得し、配列をforEachなどで取ることは出来ません。)

// 複数要素の特定
let elements = await driver.findElements(By.css('.foo'));

// 取得した要素を1つずつ扱う
// 各要素のclassを表示
webdriver.promise.map(elements, function (element) {
  return element.getAttribute("class")
}).then(function (values) {
  console.log(values);
});

seleniumで要素から属性を取得

もちろん要素の各属性を取得することもできます。

// タグ名を取得
let text = await element.getTagName();

// IDを取得
let text = await element.getId();

// テキストを取得
let text = await element.getText();

// innerHTML
let innerHTML = await element.getAttribute('innerHTML');

// hrefなど、その他の属性
let href = await element.getAttribute('href');

seleniumで取得した要素を操作

seleniumで実行できる主な要素操作は以下の通りです。

// 要素をクリック
await element.click();

// 要素(フォーム)を送信
await element.submit();

// キーを入力
await element.sendKeys("text");

// スクリーンショットを撮る
let base64 = await element.takeScreenshot();
// スクリーンショットを画像で保存
let buffer = Buffer.from(base64, 'base64');
await promisify(fs.writeFile)('screenshot.jpg', buffer);

seleniumで待機処理

要素の出現を待つ

// id=fooの要素が出現するまで10秒待つ
await driver.wait(until.elementLocated(By.id('foo')), 10000);

上記の場合、タイムアウト時間の10秒が経っても出現しない場合はエラーが返ります。

要素が出現した場合は、即座に待機処理が終了し、次の処理に移ります。

URLの一致を待つ

// 完全一致
await driver.wait(until.urlIs('https://www.google.com/'), 10000);

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

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

seleniumの操作対象の切り替え

新しいウィンドウへの切り替え

通常のChromeと同じようにページを新しいウィンドウで開くことが出来ますが、
何もしなければseleniumの操作対象は元のウィンドウに固定されています。

以下のコードを実行することで、新しいウィンドウへ操作対象を切り替えることが出来ます。

const handles = await driver.getAllWindowHandles()
// ウィンドウが2つ以上あるとき
if (handles.length >= 2) {
    const handle = handles[handles.length - 1];
    // 操作対象を切り替える
    await driver.switchTo().window(handle);
}

インラインフレームへの切り替え

初期状態ではseleniumはiframeの中の要素を操作することが出来ません。

以下のコードを実行することで、iframe内へ操作対象を切り替えることが出来ます。

// iframeの出現待ち
await driver.wait(until.elementLocated(By.css("iframe")),10000);
const iframe = await driver.findElement(By.css('iframe'));
// 操作対象を切り替える
await driver.switchTo().frame(iframe);

Twitterでもプログラミングの有益情報を配信しています。フォローはこちらから→

おすすめの記事