🍆
Next.jsにTailwind CSSが使われててスクレイピングが困難なとき、別の入口からお邪魔します
今のところ使う予定はないけど、いつかの自分のためにメモ。
※この情報はSSRされているページにのみ有効です。クライアント側でリクエストを行っているデータについては取得されません。
const nextData = JSON.parse(document.querySelectorAll('#__NEXT_DATA__')[0].innerText);
const props = nextData.props.pageProps;
console.log(props);
これだけでpropsデータにアクセスできます。
Zennのこのページで実行してみると下記のような結果になります。
Next.jsは開発フレンドリーな反面、スクレイパーフレンドリー(?)なフレームワークでもありますね。従来のHTMLよりも楽にデータ収集できちゃう説すらあるかも?実質クソでっかいサイズのJSONファイルと捉えてもOKと言っても過言ではないですね。
ちなみに、SSGするページでは
export const config = {
unstable_runtimeJS: false
}
をしておくと、完全に静的なページとなり、__NEXT_DATA__
を消すことができるようです。
その弊害としてCSRが効かなくなり next/link などの体験周りが損なわれることになるんだとか...?🙄他にどのような弊害があるかも全く検証してないです。すみません。
Playwrightでやってみる
なお、下記のコードは下記リポジトリにて自分用に制作しているスクレイピング用途のPlaywrightを使いやすくするためのものの記述の一部です。そのため、余計な this などが含まれていますが無視してください。
// Next.jsで作られたサイトのpropsデータを取得する
getPropsNextJS() {
return new Promise(async (resolve, reject) => {
if (this.page) {
const nextDataElement = await this.page.locator("#__NEXT_DATA__");
const nextDataText = await nextDataElement.innerText();
const nextData = JSON.parse(nextDataText);
resolve(nextData.props.pageProps);
}
reject("propsデータの取得に失敗しました。Next.jsで制作されていない可能性も視野に入れてください。");
});
}
(async () => {
const props = await getPropsNextJS();
})();
別の方法として、事前に要素を画像化しておき、その画像に一致する箇所のマウス座標を取得して await page.mouse.click(x, y)
でクリックしてしまうという力技もあります。スクリーンショットを撮影し、OpenCVで座標取得完了まで0.5秒もあれば処理できます。
Nuxt.jsは?
自分の中でまだ定まっていませんが、できなくはないと思います。
おおよそこんな感じでいけるかと思います。
Discussion