簡體   English   中英

抓取嵌套頁面 puppeteer

[英]Scrape nested page puppeteer

我想知道如何抓取嵌套頁面中的數據。 這是我嘗試構建但無法使其工作的示例。 這個想法是 go 到https://dev.to/ ,單擊問題並獲取其標題。 然后 go 返回並重做下一個問題的過程。

const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto("https://dev.to/");

  try {
    const selectors = await page.$$(".crayons-story > a");

    for (const post of selectors) {
      await Promise.all([
        page.waitForNavigation(),
        post.click(),
        page.goBack(),
      ]);
    }
  } catch (error) {
    console.log(error);
  } finally {
    browser.close();
  }
})();

運行此代碼時,出現錯誤:節點不可見或不是 HTMLElement

編輯:代碼缺少一個抓住標題的部分,但足以達到目的。

發生的事情是打開頁面時網站不會自動擁有該節點。 但是,puppeteer 會在進入該頁面后立即獲取網頁內容。 您需要的是延遲,以便網站能夠使用它的“腳本”標簽並注入故事。

要等待,請使用以下命令:

await page.waitForSelector(".crayons-story > a")

這確保 puppeteer 等待該選擇器變得可見,然后開始抓取內容。

所以你的最終代碼應該是這樣的:

const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto("https://dev.to/");
  
  await page.waitForSelector(".crayons-story > a")
  try {
    const selectors = await page.$$(".crayons-story > a");

    for (const post of selectors) {
      await Promise.all([
        page.waitForNavigation(),
        post.click(".crayons-story > a"),
        page.goBack(),
      ]);
    }
  } catch (error) {
    console.log(error);
  } finally {
    browser.close();
  }
})();

我在這里面臨的問題與這個非常相似。 Puppeteer 執行上下文被破壞,很可能是因為導航

我能想出的最佳解決方案是避免使用 page.goBack() 而是使用 page.goto() 這樣引用就不會丟失。

解決方案 1:(這個使用 MAP 並且以異步方式解決刮擦,比下面這個快得多):

const puppeteer = require("puppeteer");

const SELECTOR_POSTS_LINK = ".article--post__title > a";
const SELECTOR_POST_TITLE = ".article-header--title";

async function scrape() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto("https://www.smashingmagazine.com/articles/");

  try {
    const links = await page.$$eval(SELECTOR_POSTS_LINK, (links) => links.map((link) => link.href));

    const resolver = async (link) => {
      await page.goto(link);
      const title = await page.$eval(SELECTOR_POST_TITLE, (el) => el.textContent);

      return { title };
    };

    const promises = await links.map((link) => resolver(link));
    const articles = await Promise.all(promises);

    console.log(articles);
  } catch (error) {
    console.log(error);
  } finally {
    browser.close();
  }
}

scrape();

解決方案2:(使用 for 所以它是同步的,然后比以前慢得多):

const puppeteer = require("puppeteer");

const SELECTOR_POSTS_LINK = ".article--post__title > a";
const SELECTOR_POST_TITLE = ".article-header--title";

async function scrape() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto("https://www.smashingmagazine.com/articles/");

  try {
    const links = await page.$$eval(SELECTOR_POSTS_LINK, (links) => links.map((link) => link.href));

    const articles = [];
    for (const link of links) {
      await page.goto(link);
      const title = await page.$eval(SELECTOR_POST_TITLE, (el) => el.textContent);
      articles.push({ title });
    }
    console.log(articles);
  } catch (error) {
    console.log(error);
  } finally {
    browser.close();
  }
}

scrape();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM