「Puppeteer 입문 스크래핑+Web 조작 자동 처리 프로그래밍」이 움직이지 않는 샘플 코드③

「Puppeteer 입문 스크래핑+Web 조작 자동 처리 프로그래밍」이 움직이지 않는 샘플 코드③



「Puppeteer 입문 스크래핑+Web 조작 자동 처리 프로그래밍」을 구입해, 지금 공부중입니다.
이것 ↓
Puppeteer 입문 스크래핑 + 웹 조작 자동 처리 프로그래밍
움직이지 않는 몇 가지 샘플 코드가 있습니다. 나중에 사용할 수있는 코드는 모처럼이므로 수정하고 남겨두려고 생각했습니다. 우선 puppeteer에 대해 「Puppeteer 입문 스크래핑+Web 조작 자동 처리 프로그래밍」이 움직이지 않는 샘플 코드① 의 「먼저 puppeteer에 대해」 항목을 봐 주세요.

7장의 6, “블로그 이미지 저장하기”

이것은 「Puppeteer 입문 스크래핑+Web 조작 자동 처리 프로그래밍」의 움직이지 않는 샘플 코드② 과 같습니다. do { 처리 } while(true) 안에 await Promise.all([ 처리 ]); 이 있고 그 안에 page.click 가 있다. 그 때문인가? 루프 도중에 정지합니다.

해결 방법도 마찬가지입니다.

const next에, 셀렉터 오브젝트 '(a[rel="next"])'를 대입하는 것이 아니라, 그 href 속성(링크처 URL)을 대입.

const next = await page.evaluate(() => document.querySelector('a[rel="next"]')));
const next = await page.evaluate(() => document.querySelector('a[rel="next"]').href);

그리고 Promise.all에서 page.click() 대신 page.goto()를 사용합니다.
입니다.
따라서 수정 부분은 단 두 곳입니다.
/// 修正日(2019年2月11日)修正箇所は'///--修正--///'の行です

const puppeteer = require('puppeteer');
const path = require('path');
const request = require('request');
const { promisify } = require('util');
const fs = require('fs');
const delay = require('delay');

/**
 * ファイルのダウンロードを行う.
 * @param {string} url - ダウンロードするファイルのURL
 */
const downloadFile = async (url) => {
  // ダウンロードファイル名の確定.
  const filename = url.split('/').pop();
  // ファイルの取得.
  const res = await promisify(request)({ method: 'GET', uri: url, encoding: null });
  // 成功(200)したかどうか?
  if (res.statusCode === 200) {
    // 成功していればjsと同じフォルダーにファイル出力
    await promisify(fs.writeFile)(path.join(__dirname, filename), res.body, 'binary');
  } else {
    // 失敗した場合はエラー処理.
    throw new Error(`${res.statusCode} ダウンロードエラー`);
  }
};

/**
 * メインロジック.
 */
(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,
  });

  // ページの遷移.
  console.log('----------------------------------------goto');
  await page.goto('http://ryoichi0102.hatenablog.com/');

await delay(1000); // スクレイピングする際にはアクセス間隔を1秒あける.

  // 先頭の記事のurlを取得し、そのurlへ遷移.
  console.log('----------------------------------------goto');
  const firstPage = await page.evaluate(() => document.querySelector('#main article:nth-child(1) h1.entry-title a').href);
  // const firstPage = 'http://ryoichi0102.hatenablog.com/entry/2018/12/28/101519';
  await page.goto(firstPage);

await delay(1000); // スクレイピングする際にはアクセス間隔を1秒あける.

  // 各記事に対してのそれぞれの処理.
  do {
    console.log('----------------------------------------do');

    const imageUrls = await page.evaluate(() => Array.from(document.querySelectorAll('img.hatena-fotolife')).map(img => img.src));
    for (url of imageUrls) {
      console.log(`Downloading... ${url}`);
      await downloadFile(url);
    }

    console.log('----------------------------------------eval next');
    // 最後の記事までたどると次へボタンは表示されないので、その場合はループを抜ける.
    ///---修正---/// const next = await page.evaluate(() => document.querySelector('a[rel="next"]'));
    const next = await page.evaluate(() => document.querySelector('a[rel="next"]').href);
    console.log('--------------------------------------nextのhrefは、' + next);  

    if (next === null) {
      break;
    }

    // process.on('unhandledRejection', console.dir); // Promise内の捕捉されなかった例外について表示する

    // 次のページを読み込む.
    console.log('----------------------------------------next');

    await Promise.all([
        console.log('----------------------------------------inside Promise.all'),  
        page.waitForNavigation({ waitUntil: 'load' }),
        ///---修正---/// page.goto('a[rel="next"]'),
        page.goto(next),
    ]);


    await delay(1000); // スクレイピングする際にはアクセス間隔を1秒あける.
  } while (true);

  // ブラウザの終了.
  console.log('----------------------------------------close');
  await browser.close();
})();

좋은 웹페이지 즐겨찾기