現場でWebスクレイピングする機会がありました。
pupteer を使っていくなかで詰まったことがあったので、もし同じ状況で詰まっている人がいれば、参考になるかもしれません。
今回click()
メソッドが期待する動作をしなかったので、その時の状況と解決策を書いていきます。
開発環境
- Windows10 version: 21H2
- Node.js version: v16.14.1
- Puppeteer version: 5.5.0
原因
- セレクタが間違っている
- ブラウザを開いているが、
--window-size
に問題がありクリックするボタンが表示されていない - クリックする要素が表示される前に
click()
が実行されてしまっている - なぜか
click()
が使えない ※後述します。
おそらくクリックが効かない原因のほとんどは、該当すると思います。
期待する動作にならないなら、まずはこのあたりをしっかり確認すると解決するかもしれません。
セレクタが間違っている
まず最初に確認してみましょう。
ここが間違っていると、どんなに他の原因を探っても解決しません。
クリックに限りませんが、Webスクレイピングでうまく要素を取得できない場合は、だいたいセレクタに問題があると思います。
console.log
などを仕込んで、ちゃんとボタンを指定できているか確認しましょう。
ブラウザを開いているが、--window-size
に問題がありクリックするボタンが表示されていない
今回私が詰まった原因です。
ほとんどのサイトがレスポンシブ対応しているので、Puppeteer で開いているブラウザのサイズはしっかり確認しておきましょう。
Puppeteer では、ブラウザの設定を下記の方法で設定できます。
headless: false
は、ブラウザをヘッドレスモードで実行するかどうかを設定します。
デフォルトではtrue
となっているので、ブラウザが開けているか、要素をクリックできているか、ページ遷移の状況などを確認するために、開発時にはfalse
と設定するとよいでしょう。
const browser = await puppeteer.launch({
headless: false,
ignoreHTTPSErrors: true,
args: [`--window-size=1920,1080`],
defaultViewport: {
width: 1920,
height: 1080
}
});
その他のオプションの設定は、ドキュメントを参考に設定してみてください。
Puppeteer
クリックする要素が表示される前にclick()
が実行されてしまっている
Puppeteer には、多くのwaitFor
メソッドがあります。
waitForSelector()
やwaitForTimeout()
を使って、クリックしたい要素が出現するまで、プログラムの実行を止めましょう。
期待する値がとれない場合や、期待する動作をしない場合はwaitFor
が不足している可能性もあります。
なぜかclick()
が使えない
調べたところ、Puppeteer で開いたブラウザに、要素が表示されていない場合、エラーになることがあるようです。
つまり、click()
メソッドは、開いたブラウザに、要素(ここではボタン)が表示されるまでスクロールなどをしないといけないようです。
例えば、ページネーションのボタンをクリックしたいとき、多くのサイトがページ下部に設置されていると思います。
そのため Puppeteer でブラウザを開いただけだと、ページネーションのボタンが表示されていないと判定され、「クリックする要素が見つからない」というエラーが出るのだと思います。
(私の環境だと発生しました)
ではどうすればいいのか?
私は下記の方法を使って解決しました。
// ページが表示されるまで待つ
await page.waitForSelector(ITEM_PAGE_QUERY);
// ボタン要素を取得する
const nextPageButton = await page.$(NEXT_PAGE_QUERY);
await nextPageButton .evaluate(b => b.click());
evaluate()
メソッドを使用する方法です。
stackoverflow の下記の質問がよくまとまっているので、参考にするとよいでしょう。
Puppeteer in NodeJS reports 'Error: Node is either not visible or not an HTMLElement'
まとめ
- セレクタが間違っていないか確認する
- 開いているブラウザサイズに問題がないか確認する
- クリックする要素が表示される前に実行していないか確認する
-
evaluate(b => b.click());
を使ってみる
Puppeteer クリックで詰まっている人の参考になると嬉しいです!
また、間違っている情報などありましたら、ご指摘いただけると幸いです。