Help us understand the problem. What is going on with this article?

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

})();
valuesccg
「インターネット行動ログ分析サービス」など、デジタルマーケティング領域での新たな価値創造を通し、各企業の成長支援を行っています。エンジニア募集中。
https://www.valuesccg.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした