「Puppeteer入門ースクレイピング＋Web操作自動処理プログラミング」の動かないサンプルコード①

#「Puppeteer入門ースクレイピング＋Web操作自動処理プログラミング」の動かないサンプルコード①

「Puppeteer入門ースクレイピング＋Web操作自動処理プログラミング」を購入し、ただいま勉強中です。
これね↓
<a target="_blank" href="https://www.amazon.co.jp/gp/product/4798055204/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4798055204&linkCode=as2&tag=kokkahasan-22&linkId=0774e78e10539fa13675b503875cc1ea">Puppeteer入門 スクレイピング+Web操作自動処理プログラミング</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=kokkahasan-22&l=am2&o=9&a=4798055204" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
<a target="_blank"  href="https://www.amazon.co.jp/gp/product/4798055204/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4798055204&linkCode=as2&tag=kokkahasan-22&linkId=87381345b4c9d33a512b6582704198bd"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=4798055204&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL160_&tag=kokkahasan-22" ></a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=kokkahasan-22&l=am2&o=9&a=4798055204" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />


例として使用している秀和システムのWebサイトが、本書執筆時とは大きく変わってしまってるようで動かないサンプルコードがあるでしょう？
のちのち使えそうなコードはせっかくなので修正して残しておこうと思いました。

####まずpuppeteerについて
puppeteerはGoogle社のChrome DevTools Teamが2017年に開発しました。node.jsのライブラリとして動作します。
https://try-puppeteer.appspot.com/
に行くと、6行の簡単なデモを体験できます。

```javascript
const browser = await puppeteer.launch();

const page = await browser.newPage();
await page.goto('https://qiita.com');

console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});

await browser.close();
```

`https://qiita.com` をブラウザで開いてスクリーンショットをPNGファイルでキャプチャするコードです。
※ デモのコードは`await page.goto(https://example.com)`となっているので`await page.goto(https://qiita.com)`に書き換えました。
![Screenshot from 2019-02-08 13-51-16.png](https://qiita-image-store.s3.amazonaws.com/0/307441/d7473614-eb2e-d0de-3a1a-7897376ce97e.png)



#####7章の２，「秀和システムの新刊一覧の詳細を取得する」
このサンプルは汎用性が高いと思います。
書籍を持っていない方のために解説すると
秀和システムの新刊案内（`https://www.shuwasystem.co.jp/newbook.html`)にある新刊一覧から、それぞれの新刊をクリックしてその詳細ページを開き、そのタイトルと詳細情報をCSVに一覧にして出力する。というコードです。


秀和システムの新刊案内ページ（`https://www.shuwasystem.co.jp/newbook.html`)は今はなくなってしまって、新刊一覧はトップページ(`https://www.shuwasystem.co.jp`)に移り、タグなどもかなり変わってます。秀和システムサイトがメジャーアップデートしてしまったようです。

それにともない、以下のようにコード変更しました。

```javascript

/// 修正日（2019年2月7日）修正箇所は'///--修正--///'の行です
/// 注１：headlessはfalseにしてある。そのほうが動きが目に見えて素敵
/// 注２：当方ubuntu環境なのでCSVへの保存はUTF-8にしてある

const puppeteer = require('puppeteer');
const stringify = require('csv-stringify');
const iconv = require('iconv-lite');
const fs = require('fs');
const path = require('path');
const delay = require('delay');

const getInfoFromChildPage = async (browser, url) => {
  const childPage = await browser.newPage();
  await childPage.goto(url);
 ///--修正--/// const h1Title = await childPage.evaluate(() => document.querySelector('h1.syoseki').textContent);　＞'h1.shoseki'はなくて、h1.titleType1になってる
  const h1Title = await childPage.evaluate(() => document.querySelector('h1.titleType1').textContent);
 ///--修正--/// const result = await childPage.evaluate(() => Array.from(document.querySelectorAll('.norm td')).map(td => td.textContent));　＞.norm tdもなくて、div id='bookSample'になってる
  const result = await childPage.evaluate(() => Array.from(document.querySelectorAll('#bookSample')).map(bookSample => bookSample.textContent));
  await childPage.close();
  result.unshift(h1Title);
  return result;
};

/**
 * メインロジック.
 */
(async () => {
  // Puppeteerの起動.
  const browser = await puppeteer.launch({
    headless: false, // Headlessモードで起動するかどうか.
    slowMo: 50, // 指定のミリ秒スローモーションで実行する.
  });

  // 新しい空のページを開く.
  const page = await browser.newPage();

  // view portの設定.
  await page.setViewport({ width: 1200, height: 800 });

  // 一覧ページである 新刊案内 ページを開く.
  ///--修正--///await page.goto('http://www.shuwasystem.co.jp/newbook.html'); >このURLはもうない
  await page.goto('http://www.shuwasystem.co.jp');


  // 新刊案内の各ページへのリンク先を取得.
///--修正--///const results = await page.evaluate(() => Array.from(document.querySelectorAll('#sinkan dt a')).map(a => a.href));　＞#sinkanはもうない。
///--修正--///　トップページに#main_column > div.listType1 > ul > li:nth-child(1) > div.tool_tip > div > a というセレクタで新刊がブロックで並んでいる
  const results = await page.evaluate(() => Array.from(document.querySelectorAll('div.tool_tip > div > a')).map(a => a.href));

  // それぞれの新刊の詳細情報ページの情報を取得する.

  const csvData = []; // CSVに保存するための情報を保持する.
  for (const result of results) {
    await delay(1000); // スクレイピングする際にはアクセス間隔を1秒あける.
    // console.log(result);
    const texts = await getInfoFromChildPage(browser, result);
    csvData.push(texts);
  }

  // この実装だと同時多発的なアクセスとなり、相手先のサーバーに負荷がかかりすぎるため推奨しない.
  // const csvData = await Promise.all(results.map(m => getInfoFromChildPage(browser, m)));

  // ここからはCSVに出力するためだけの処理.
  // csvDataを文字列化する.
  stringify(csvData, (error, csvString) => {
    // ファイルシステムに対してファイル名を指定し、ファイルストリームを生成する.
    const writableStream = fs.createWriteStream(path.join(__dirname, '秀和システム新刊案内.csv'));
    // csvStringをShift_JISで書き出す.
    writableStream.write(iconv.encode(csvString, 'UTF-8'));
  });

  // ブラウザの終了.
  await browser.close();
})();
```

あまり修正箇所は多くないが、初心者や、経験者でも久しぶりに見て動かないと「ああ〜ん:weary:」てなると思うのでよろしければ使ってください。

基礎編にも秀和システムサイトを利用したコードが少しありましたが流し読みでしたので確認してません。ご要望あれば修正します。

まだ途中ですが、うしろのほうをパラパラめくるとテスト駆動開発のフレームワークの実装などもあって面白そう。
本の見た目や入門というタイトルにしてはなかなか守備範囲が広い本です。


[「Puppeteer入門ースクレイピング＋Web操作自動処理プログラミング」の動かないサンプルコード②](https://qiita.com/atomyah/items/51b157f493142a7d1f09)