【问题标题】:Unable to implement any logic to scrape content from innermost pages using puppeteer无法实现任何逻辑来使用 puppeteer 从最里面的页面中抓取内容
【发布时间】:2021-09-17 20:20:02
【问题描述】:

我创建了一个脚本,使用 puppeteer 从webpage 中抓取不同作者的链接,遍历多个页面触发点击下一页按钮。该脚本似乎以正确的方式运行。

虽然这个网站的内容是静态的,但我故意在以下脚本中使用 puppeteer 只是为了了解如何解析内页的内容。

鉴于我希望深入一层以从 pages 中刮取 description。我怎样才能做到这一点?

const puppeteer = require('puppeteer');

function run (pagesToScrape) {
    return new Promise(async (resolve, reject) => {
        try {
            if (!pagesToScrape) {
                pagesToScrape = 1;
            }
            const browser = await puppeteer.launch({headless:false});
            const [page] = await browser.pages();
            await page.goto("https://quotes.toscrape.com/");
            let currentPage = 1;
            let urls = [];
            while (currentPage <= pagesToScrape) {
                let newUrls = await page.evaluate(() => {
                    let results = [];
                    let items = document.querySelectorAll('[class="quote"]');
                    items.forEach((item) => {
                        results.push({
                            authorUrl:  'https://quotes.toscrape.com' + item.querySelector("small.author + a").getAttribute('href'),
                            title: item.querySelector("span.text").innerText
                        });
                    });
                    return results;
                });
                urls = urls.concat(newUrls);
                if (currentPage < pagesToScrape) {
                    await Promise.all([
                        await page.waitForSelector('li.next > a'),
                        await page.click('li.next > a'),
                        await page.waitForSelector('[class="quote"]')
                    ])
                }
                currentPage++;
            }
            browser.close();
            return resolve(urls);
        } catch (e) {
            return reject(e);
        }
    })
}
run(3).then(console.log).catch(console.error);

【问题讨论】:

  • 来自网站的使用条款:“禁止数据挖掘/抓取和框架。您不得使用机器人、抓取工具、爬虫、蜘蛛或任何类似的方法、流程或工具来“数据挖掘”或以其他方式从 YP 网站收集或提取数据......”我会小心发布有关抓取网站的问题,这些网站专门禁止抓取......只是说。 Stack Overflow 不会让你失望,我也不会,但这是一个公共网站。
  • 这次的网站不同了@Heretic Monkey。问题中的站点是为被抓取而创建的。谢谢。

标签: javascript node.js web-scraping puppeteer


【解决方案1】:

我会走这条路:

const puppeteer = require('puppeteer');

let browser;

(async function main() {
  browser = await puppeteer.launch({ headless: false, defaultViewport: null });

  const [pageQuotes] = await browser.pages();
  const pageAbout = await browser.newPage();
  await pageQuotes.bringToFront(); // Otherwise, click on the next page link does not work.

  const pagesToScrape = 3;

  await pageQuotes.goto('https://quotes.toscrape.com/');
  let currentPage = 1;

  const data = { quotes: {}, abouts: {} };
  const visitedAbouts = new Set();

  while (currentPage <= pagesToScrape) {
    await pageQuotes.waitForSelector('.quote');

    const { quotes, aboutURLs } = await pageQuotes.evaluate(() => ({
      quotes: Array.from(
        document.querySelectorAll('.quote'),
        quote => [quote.querySelector('small.author').innerText, quote.innerText],
      ),
      aboutURLs: Array.from(
        document.querySelectorAll('.quote small.author + a[href]'),
        quote => quote.href,
      ),
    }));

    for (const [author, quote] of quotes) {
      if (data.quotes[author] === undefined) data.quotes[author] = [];
      data.quotes[author].push(quote);
    }

    for (const aboutURL of aboutURLs) {
      if (!visitedAbouts.has(aboutURL)) {
        visitedAbouts.add(aboutURL);

        await pageAbout.goto(aboutURL);
        await pageAbout.waitForSelector('div.author-details');

        const { title, about } = await pageAbout.evaluate(() => ({
          title: document.querySelector('div.author-details h3.author-title').innerText,
          about: document.querySelector('div.author-details').innerText,
        }));

        data.abouts[title] = about;
      }
    }

    if (currentPage < pagesToScrape) {
      const nextLink = await pageQuotes.waitForSelector('li.next > a');

      await Promise.all([
        nextLink.click(),
        pageQuotes.waitForNavigation(),
      ]);
    }
    currentPage++;
  }

  console.log(JSON.stringify(data, null, '  '));
})().catch(console.error).finally(async () => { if (browser) await browser.close(); });

【讨论】:

  • 由于您为我上一篇文章提供的解决方案运行顺利,我想在提出任何问题之前先接受这个答案。我的节点版本是v13.14.0。当我运行你建议的方法时,我收到了这个错误Unexpected token '?'。我可以用适合我的版本的东西替换这行 data.quotes[author] ??= [] 吗?非常感谢。
  • @MITHU 是的,我已经用旧方法编辑了答案。
  • 这是我遇到过的最好的方法之一。所以你已经使用了两个选项卡来处理两个不同层的数据,对吧?顺便说一句,这个await browser?.close() 的替代方法是什么?你又看到了?这个标志。
  • @MITHU 对。我已经替换了browser?.close()
猜你喜欢
  • 2021-03-25
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多