🍆

Next.jsにTailwind CSSが使われててスクレイピングが困難なとき、別の入口からお邪魔します

2022/08/13に公開

今のところ使う予定はないけど、いつかの自分のためにメモ。
※この情報は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 などが含まれていますが無視してください。
https://github.com/masa5714/scraping-with-playwright

  // 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秒もあれば処理できます。

https://zenn.dev/masa5714/articles/4aaf433262427e

Nuxt.jsは?

https://zenn.dev/masa5714/scraps/7aa0ec4f9e7564

自分の中でまだ定まっていませんが、できなくはないと思います。
おおよそこんな感じでいけるかと思います。

Discussion