[英]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.