以前、SeleniumとPlaywrightの比較のため両方を検証していました。せっかく使い方を覚えたので、また必要になった時にすぐに思い出せるよう下記記事に簡単に使い方をまとめました。
元々クローラーとしてpuppeteerを使っていたので、Selenium・Playwrightをまとめたのなら、puppeteerは外せないでしょということで、ここにpuppeteerの使い方を簡単にまとめてみることにしました。
ただ、SeleniumとPlaywrightを検証した結果、今はPlaywrightをメインで使っています。なので、通常使いの向けの網羅的なまとめではなく、puppeteerのお作法について簡単にまとめたものに留めておこうと思います。
インストール
npm install --save puppeteer
- ブラウザChromiumが
node_modules
にインストールされ、そのブラウザが使われる - ブラウザはpuppeteerがインストールしたものではなく、自分で用意したものも使える。その場合は、
executablePath
を設定する - ブラウザをインストールしたくない場合は
puppeteer-core
をインストールする
自分が用意したブラウザを使う
npm install --save puppetter-core
const browser = await puppeteer.launch({executablePath: <browser_path>});
サンプル
例)Googleで「test」と検索し、結果ページのソースを表示する。
import puppeteer from 'puppeteer'; (async () => { try { const browser = await puppeteer.launch({ headless: false, slowMo: 100, }); const page = await browser.newPage(); let selector; await page.goto("https://www.google.com"); selector = 'input[name="q"]'; await page.waitForSelector(selector); await page.type(selector, "test\n"); await page.waitForNavigation(); console.log(await page.content()); } catch (err) { console.error(err); } })();
puppeteerの仕組みと流れ
- ブラウザ操作の流れは、対象となる
dom
を取得し、そのdom
に対して操作の繰り返しになる。 dom
は動的に生成されることがあるので、dom
を取得しようとした時にまだ生成されていない時がある。なので、dom
取得はdom
が存在するのを確認してから行う必要がある。dom
が見つかるまで待つのがpage.waitForSelector()
dom
が見つかると、そのdom
に対してブラウザ上でJavaScriptを実行することによりdom
を操作する
例
ボタンをクリックする場合下記のようになる。
page.$eval()
は、第2引数のJavaScript関数を、ブラウザ上で実行してくれるpage.$eval()
の第1引数で指定したセレクターのdom
が、第2引数のdom
となる
let selector = 'input[type="button"]'; await page.waitForSelector(selector); await page.$eval(selector, dom=>{ dom.click() });
page
には、よくやるJavaScript操作のいくつかが関数にまとめられている。
例
上記のマウスクリックはpage.click(<selector>)
を使って下記のように書ける。
let selector = 'input[type="button"]'; await page.waitForSelector(selector); await page.click(selector);
いずれにせよ、ブラウザ操作は下記の繰り返しになる。
dom
を待つdom
を指定してJavaScriptを実行する
JavaScriptから値の取得
JavaScriptを実行した関数のreturn
で、JavaScriptから値を返すことができる。
例
dom
のinnerText
は下記のようにして取得できる。
let selector = 'div'; await page.waitForSelector(selector); const text = await page.$eval(selector, dom=> dom.innerText); console.log(text);
JavaScriptへを渡す
page.$eval()
の第3引数に値を渡すと、第2引数の関数の第2引数となって、値をJavaScriptに渡すことができる。
例
input
のvalue
は下記のようにしてセットできる。
const userName = 'ABC'; let selector = 'input[name="user"]'; await page.waitForSelector(selector); await page.$eval(selector, (dom, val)=>{ dom.value = val }, userName);
複数要素
セレクターが複数dom
にマッチする場合がある。
page.$eval()
はそのうち最初にマッチしたdom
のみがJavaScriptに渡るが、page.$$eval()
を使うと、マッチするdom
の配列がJavaScriptに渡る。
例
option
のvalue
を配列で取得する
let selector = 'select option'; await page.waitForSelector(selector); const res = await page.$$eval(selector, doms=>{ const optionVals = []; for(const dom of doms){ res.push(dom.innerText); } return optionVals; }); console.log(res);
要素
操作
page.click(<selector>)
page.type(<selector>, <value>)
- 文字列打ち込み
page.focus(<selector>)
page.$eval(<selector>,(dom, val)=>{ dom.value = val }, <val>)
<input>
のvalue
をセット
その他、dom
を操作したい時は、$eval()
を使ってJavaScriptで直接操作する。
属性
page.$eval(<selector>, dom=> dom.getAttribute(<attribute_name>))
その他、dom
から情報を取得したい時は、$eval()
を使ってJavaScriptで直接取得する。
ナビゲーション
遷移
page.goto(<url>)
page.reload()
ページロード完了を待つ
page.waitForNavigation()
page.waitForNetworkIdle()
属性
page.title()
page.url()
page.content()
- ページのhtml
感想など
他にもファイルのアップロード・ダウンロードや、target="_blank"
での新しいページ取得など、クローリングでよくあるケースもまとめようかと思っていました。
しかし、puppeteerはそういった事に対して都度機能を提供していくのではなく、ユーザーが自分でJavaScriptを書いて実装するというスタンスなので、puppeteerの使い方というよりJavaScriptの話になってしまうので今回は割愛しました。
SeleniumやPlaywrightは、要素を取得してその要素のメソッドを使って操作するという書き方なのですが、puppeteerはChrome DevTools Protocol
の呼び出しをライブラリ化したものなので、ページのメソッドを使って、対象要素を引数で指定して操作するという書き方になります。
puppeteerは何かやろうとすると無骨なコードになることが多いのですが、それは、SeleniumやPlaywrightはブラウザ作業の自動化が目的のライブラリなのに対し、puppeteerはブラウザとの通信が目的のライブラリと目的の違いに起因しています。