Puppeteer로 비동기 스크래핑

스크린샷을 찍을 때는 수상한 거동을 하고 있었으므로 주의가 필요할 것 같다.fullPage: true 하지 않으면 응답이 없는 것이 있어 계속 처리가 끝나지 않았다.

코드



test.js
const puppeteer = require('puppeteer');

// Unhandled promise rejection
process.on('unhandledRejection', (error) => {
  console.error(error);
  process.exit(1);
});

const articleUrlList = [
  'https://qiita.com/horikeso/items/0bf9a78454b8124a6dfa',
  'https://qiita.com/horikeso/items/f87d3e703828aa13e2ff',
  'https://qiita.com/horikeso/items/ec34a8e3d6731a94f5f9',
  'https://qiita.com/horikeso/items/bb255eede8a051dfa785',
];

(async () => {
  try {
    const browser = await puppeteer.launch({
      args: [
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--lang=ja,en-US;q=0.9,en;q=0.8',
        '--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
      ]
    });
    let index = 0;
    promiseList = [];
    articleUrlList.forEach(targetUrl => {
      promiseList.push((async (index) => {
        const page = await browser.newPage();
        page.setDefaultNavigationTimeout(30000);// default 3000 milliseconds, pass 0 to disable timeout
        const response = await page.goto(targetUrl);
        await page.waitFor(1000);// 1秒待つ

        if (response.status() !== 200) {
          return [];
        }

        console.log(index);
        const fileName = index + '.png';
        await page.screenshot({path: fileName, fullPage: true});

        const result = await page.evaluate(() => {
          return [document.querySelector('meta[property="og:title"]').getAttribute('content')];
        });

        await page.close();

        return result;
      })(index));
      index++;
    });

    let articleTitleList = [];
    await Promise.all(promiseList).then(valueList => {
      valueList.forEach(value => {
        articleTitleList = articleTitleList.concat(value);
      });
    }).catch(reject => {
      throw reject;
    });

    console.log(articleTitleList);

    await browser.close();

  } catch (error) {
    throw error;
  }
})().catch((error) => {
  console.log(error);
  process.exit(1);
});

주의사항


MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 Symbol(Connection.Events.Disconnected) listeners added. Use emitter.setMaxListeners() to increase limit

같은 오류가 발생하면
아래에서 MaxListeners 의 상한을 올리거나(서버 스펙에 문제가 없는 경우 나름대로 메모리를 사용하기 때문에)Lodash 이나 Underscore 의 chunk 로 분할 실행하거나 하여 Promise 의 동시 실행수를 줄일 필요가 있을 것 같습니다.
require('events').EventEmitter.defaultMaxListeners = 15;// default 10, Promise等 同時実行制限

goto가 돌아 오지 않는 페이지가 있습니다.

여러가지 페이지를 취득하는 경우는 총당으로 부딪히는 방법이라도 좋을지도 모릅니다.

잘 잡히지 않는 것이 있는 경우는 차례로 해 간다.
timeout은 요조정
const optionList = [
    {waitUntil: 'load'},
    {waitUntil: 'domcontentloaded'},
    {waitUntil: 'networkidle0'},
    {waitUntil: 'networkidle2'}
];

let response = null;
for (let optionIndex = 0; optionIndex < optionList.length; optionIndex++) {
    if (response) {
        break;
    }
    response = await page.goto(targetUrl, optionList[optionIndex]).catch(error => {
        if (optionIndex === optionList.length - 1) {
            throw error;
        }
    });
}

if (response.status() !== 200) {
    continue;
}

실행 결과


node test.js
3
0
2
1
[ 'CentOS7でPuppeteerを使う - Qiita',
  'Puppeteerのevaluateに引数 - Qiita',
  'Puppeteerでステータスコード - Qiita',
  '非同期処理を含むループを同期処理 - Qiita' ]

index가 순서가 아니기 때문에 비동기로 되어 있을 것.

생성된 SS



긴...

0.png





1.png





2.png





3.png



좋은 웹페이지 즐겨찾기