Puppeteerを使ってスクレイピングする時に個人的にはまったポイントのメモ


概要

Puppeteerを使用してヘッドレスブラウザとしてウェブスクレイピングを行う時に、個人的に詰まった点のメモです。

前提

Mac OS v10.15.2(19C57)
VSCode 1.41.1
node v12.14.1
Puppeteer 2.1.0

その1 コンソール出力ができない

問題

page.evaluateを使うことで、ページ読み込み後にブラウザ内で任意のスクリプトを実行してHTMLの解析などが可能ですが、デバッグ用にconsoleを仕込んでも何も表示されません。


  // 初期化処理
  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  const page = await browser.newPage();

  // 指定のURLのページを開く
  await page.goto('https://hoge.hoge.hoge');

  // ブラウザ内でスクリプトを実行
  const result = await page.evaluate(() => {
    // ここでコンソールを出力しても何も表示されない
    console.log('eval start');
    // do something
  });

解決策

pageに対して、consoleイベントを予め登録し、イベント呼び出し処理内でconsoleで書き込みを行います。
page.evaluate内でconsoleを実行するとこのイベントが発火されてconsole出力がされるようになります。


  const page = await browser.newPage();
  // コンソールイベントを登録
  page.on('console', msg => {
    for (let i = 0; i < msg._args.length; ++i)
      console.log(`${i}: ${msg._args[i]}`);
  });
  // 指定のURLのページを開く
  await page.goto('https://hoge.hoge.hoge');

  // ブラウザ内でスクリプトを実行
  const result = await page.evaluate(() => {
    console.log('eval start');
    // do something
  });

その2 querySelectorAllで取り出した結果が空のオブジェクトになる

問題

page.evaluate内でquerySelectorを使ってHTML要素を出力しようとするが、正しく値が取れない。


    const result = await page.evaluate(() => {
      const dataList = [];
      // hogeクラスタグ配下のaタグを全て取得
      const nodeList = document.querySelectorAll('.hoge > a');
      // 内部のhtmlを出力
      nodeList.forEach(_node => {
        dataList.push(_node.innerText);
      });
      return dataList;
    });

    // 出力は空文字になる ["", "", ""]
    console.log(result);

解決策

querySelectorAllで取り出した値は配列になっていない為、Array.fromで配列に変換した後に列挙を行う。


    const result = await page.evaluate(() => {
      const dataList = [];
      // Array.fromで配列に変換
      const nodeList = Array.from(document.querySelectorAll('.hoge > a'));
      // 内部のhtmlを出力
      nodeList.forEach(_node => {
        dataList.push(_node.innerText);
      });
      return dataList;
    });

    console.log(result);

最後に

個人的にPuppeteer使用中にはまった点を書きました。
Puppeteer自体は直感的で便利なのですが、思いがけないところではまって時間を使ってしまいしました。
(マニュアル等をしっかり読まず使えしまう事の弊害かもしれませんが。)