以前、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はブラウザとの通信が目的のライブラリと目的の違いに起因しています。