Puppeteerで非同期スクレイピング

スクリーンショットをとるときは怪しい挙動をしていたので注意が必要そう。
`fullPage: true`にしないと応答がないものがあってずっと処理が終わらなかった。

# コード

```js: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`の同時実行数を減らす必要がありそうです。

```js
require('events').EventEmitter.defaultMaxListeners = 15;// default 10, Promise等 同時実行制限
```

**gotoが返ってこないページがある**

いろんなページを取得する場合は総当たりでぶつける方法でも良いかもしれません。

うまく取れないものがある場合は順番にやっていく。
timeoutは要調整

```js
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

![0.png](https://qiita-image-store.s3.amazonaws.com/0/156195/dc7f3ba8-52aa-6bfc-436c-0bcb64e06fc6.png)

## 1.png

![1.png](https://qiita-image-store.s3.amazonaws.com/0/156195/b305ed5e-dec2-17df-60a4-d309f20e7497.png)

## 2.png

![2.png](https://qiita-image-store.s3.amazonaws.com/0/156195/97070122-b143-333f-04da-48c4e92e7bff.png)

## 3.png

![3.png](https://qiita-image-store.s3.amazonaws.com/0/156195/ed7d7937-692f-e0e6-cd2b-122b395a5ff2.png)