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

【puppeteer】基本情報&逆引き

puppeteerとは

Chrome または Chromium を操れるライブラリ。スクレイピングや自動テストに使える。Node.jsから使用できる。

公式サイト
https://pptr.dev/

前提条件

Node.jsがインストールされていること。

インストール

任意のプロジェクトフォルダで下記コマンドを実行。

npm i puppeteer

既定では、puppeteerをインストールすると、最新バージョンのChromiumも一緒にダウンロードされる。ダウンロードさせたくない場合は、環境変数で設定を変更するか、puppeteer-coreの使用を検討すると良い。

puppeteer-core

v1.7.0から追加されたパッケージ。Chromiumのダウンロードを行わない。代わりに既にPCにあるChrome/Chromiumなどを使用する。
大体の場合はpuppeteerの方を使えば良いが、使用するブラウザがChromeでなければダメな場合など、Chromiumのダウンロードが必要ないときはpuppeteer-coreを使う方が容量を取らなくて良さそう。

ブラウザの起動と終了

const LAUNCH_OPTION = {
     headless : false
    ,executablePath : 'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe'
};

const browser = await puppeteer.launch(LAUNCH_OPTION);
try {
    const page = await browser.newPage();   // 新しいタブを開く

    // ここにスクレイピングを実装

} finally {
    browser.close();
}

指定したURLへ移動

page.goto(url[, options])

optionsのwaitUntilでどれくらい待つか指定できる。

waitUntil

  • load - ページの読込みが、画像などを含めて完全に終わるまで待つ。
  • domcontentloaded - HTMLの読込みが終わるまで待つ。
  • networkidle0 - ネットワーク接続が0件の状態が500ミリ秒続くまで待つ。
  • networkidle2 - ネットワーク接続が2件以下の状態が500ミリ秒続くまで待つ。

ページ移動を待つ

page.waitForNavigation([option])

  • options <Object>
    • timeout <number> 最大待機時間をミリ秒で指定する。0を指定するとタイムアウトなしになる。既定値:30秒。既定値はpage.setDefaultNavigationTimeout(timeout)またはpage.setDefaultTimeout(timeout)で変更可能。
    • waitUntil <string|Array<string>> どれくらい待つか指定する。既定値:load。複数指定した場合は、指定したすべてのイベントが終わるまで待つ。詳細は前述。
  • 戻り値: <Promise<?Response>>

クリックなどでナビゲーションが発生する場合、クリックと共にこの関数を実行し、ナビゲーションが終わるのを待たせる必要がある。

クリック後のナビゲーションを待機するサンプル
const [response] = await Promise.all([
  page.waitForNavigation(waitOptions),
  page.click(selector, clickOptions),
]);

ページ移動を伴うナビゲーションであればwaitUntildomcontentloadedなどを指定すればよいが、非同期のナビゲーションであれば、networkidle0などを指定する。

要素の出現or指定秒を待つ

page.waitFor

引数に、セレクタを指定するか、ミリ秒を指定するかで挙動が変わる。

要素が存在するか調べる

page.$(selector)
ページ内で、document.querySelectorを実行する。
要素が見つからない場合はnullを返すため、nullかどうかで存在チェックができる。

要素が表示されるまで待つ

page.waitForSelector(selector, {visible:true});

クリックする

page.click(selector[, options])

  • selector <string> 対象となる要素のセレクタ
  • options <Object>
    • button <"left"|"right"|"middle"> 既定値:left
    • clickCount <number> 既定値:1
    • delay <number> mousedownmouseupの間隔をミリ秒で指定する。既定値:0
  • 戻り値: <Promise>

click()でナビゲーションが発生する場合、page.waitForNavigation()を使ってナビゲーションが終わるまで待機する必要がある。

文字を入力する

page.type(selector, text[, options])

  • selector <string> 対象となる要素のセレクタ
  • text <string> 入力する文字列
  • options <Object>
    • delay <number> キー入力間の待機時間をミリ秒で指定する。既定値:0。

テキストを取得する

const ele = await page.$(".scrape");
const text = await page.evaluate(elm => elm.textContent, ele);

Pageオブジェクトにテキスト取得のメソッドはないため、evaluateメソッドを代わりに使用する。
evaluateメソッドは、引数で指定した関数をページ内で実行する。第1引数に実行する関数、第2引数に関数へ渡す引数を指定する。この引数に、page.$()などで取得したElementHandleを渡すことが可能。

Chromeで動的に生成される要素を調べる

一時停止(F8)を押すか、要素で右クリック→「検証」を選ぶ。

javascript - マウスカーソルを乗せている間だけ表示される要素を、開発者ツールで調べるには - スタック・オーバーフロー

ログインが必要なページへのアクセス

以下の方法がある:

  • IDとパスワードを入力してログインする動作をスクリプトに実装する。
    • 良いところ:単純で分かりやすい。
    • 悪いところ:Googleには弾かれる。
  • ChromeからCookieをエクスポートし、それをpuppeteerに読み込ませて使用する。
    • 良いところ:Googleにもログインできる。
    • 悪いところ:Cookieをエクスポートするのが手間。Cookieの有効期限も考慮しなければならない。

アカウント+パスワードでGoogleにログインするスクリプトを作成し実行したところ、ページが以下のようになってログインできなかった。

puppeteerの操作を自動テストツールと判定して、ログインを阻止していると思われる。こういう場合、Cookieを使う方法だとログインせずともページがログイン後の状態となって上手く動作する場合がある。

Cookieを使用してログインする

Webサイトへログインした後のCookieを保存しておき、それをpuppeteerに読み込ませることで、自動化中もログイン後と同じ状態にする。

EditThisCookieのインストール

Chromeから簡単にCookieをエクスポートするためのツールをインストールする。EditThisCookieはChrome拡張機能として提供されている。

Cookieのエクスポート

Chromeで目的のWebサイトへログインした後、EditThisCookieのアイコンをクリックして、エクスポートのアイコンをクリックする。

Cookieの内容がJSON形式でクリップボードへエクスポートされるので、テキストファイルへ貼り付けて保存する。

puppeteerでCookieを読み込む

保存したCookieのファイルを、puppeteerで読み込む。目的のサイトへ移動する前にCookieを読み込んでおくこと。また、サンプルには実装していないが、Cookieの有効期限が切れた場合も考慮しておく必要がある。

const puppeteer = require("puppeteer-core");
const config = require("config");
const fs = require("fs");

async function useCookieSample(page) {

    let content = fs.readFileSync("cookie.json");
    let cookie = JSON.parse(content);

    await page.setCookie(...cookie);

    await page.goto("https://gmailのURL", {
        "waitUntil" : "domcontentloaded"
    });
}

参考:javascript - login into gmail fails for unknown reason - Stack Overflow

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
ユーザーは見つかりませんでした