javascript - 使用 Apify 的 Puppetetteer Crawler 抓取网站页面
问题描述
(*) 情况 :
你好 !
我想爬谷歌酒店平台,我点击一个城市,它会给我那个城市的所有酒店。例如纽约市的结果,它将为我们提供超过 1200 家酒店,所以我想抓取有关这些酒店的所有信息。
我使用了 Apify 的 Puppeteer Crawler,在开始 urls中,我放了第一页的 url。在链接选择器中,我把选择器转到了酒店详情页面。
这就是我在Page Function中输入的内容:
async function pageFunction(context) {
const { request, log, skipLinks, page } = context;
//request.userData = list_links;
if (request.userData.label === 'START') {
log.info('Store opened!');
}
if (request.userData.label === 'DETAIL') {
const { url } = request;
log.info(`Scraping ${url}`);
await skipLinks();
const titleP = page.$eval(
'title',
(el => el.textContent)
);
const priceP = page.$eval(
'div.JGa7fd',
(el => el.getAttribute('aria-label'))
);
const ratingP = page.$eval(
'div.iDqPh.BgYkof',
(el => el.textContent)
);
const reviewsNumberP = page.$eval(
'a.eS7K5e',
(el => el.textContent)
);
const hotelStarP = page.$eval(
'div.fnmyY > span.CFH2De',
(el => el.textContent)
);
const adressP = page.$$eval(
'div.K4nuhf span.CFH2De',
(els) => els[0].textContent
);
const phoneP = page.$$eval(
'div.K4nuhf span.CFH2De',
(els) => els[2].textContent
);
const websiteP = page.$$eval(
'a.FKF6mc.TpQm9d',
(els) => els[0].getAttribute('href')
);
const [
title,
price,
rating,
reviewsNumber,
adress,
phone,
hotelStar,
website,
] = await Promise.all([
titleP,
priceP,
ratingP,
reviewsNumberP,
adressP,
phoneP,
hotelStarP,
websiteP,
]);
return {
title,
price,
rating,
reviewsNumber,
adress,
phone,
hotelStar,
website,
};
}
}
(*) 问题 :
如果您分析页面,您会发现它们不是枚举页面(第 1 页,第 2 页,第 3 页),我们只有 Next & Previous Button(即使您分析 URL,它也没有 "&page= 1/2/3" 或类似的东西,如果我们期望这个按钮(下一个按钮),我们会得到它是一个带有 role="button" 的 div 标签,并且没有任何 href 属性可供选择。
(*) 问题 :
1-如何使用 Puppeteer 抓取所有页面?如何转到下一页并刮掉它们?
2-我可以在 APify 中使用所有 puppeteer 文档,还是它们有一些限制?
3- Pure Puppeteer 和 Apify 的 Puppeteer 有什么区别?
(*) 半解:
对于问题 1,我尝试了这个解决方案,我使用 Pure Puppeteer,我转到第一页,单击下一步按钮,获取它的 url,再次转到下一页,获取它的 url,等等,直到完成 while环形 。之后,我将 url 复制粘贴到 txt 文件中,然后将其上传到启动 url。
这是我尝试过的代码源:
const puppeteer = require('puppeteer');
(async function main() {
try {
const browser = await puppeteer.launch({ headless: false });
const [page] = await browser.pages();
const url ="https://www.google.com/travel/hotels/Marrakesh?utm_campaign=sharing&utm_medium=link&utm_source=htls&hrf=CgUIzAgQACIDTUFEKhYKBwjkDxAIGBkSBwjkDxAIGBoYASABsAEAWAFoAYoBKAoSCcxMCO-rXT9AEQMTl9GnSCDAEhIJVRwqc-jwP0ARByaebVl8HsCaATESCU1hcnJha2VzaBokMHhkYWZlZThkOTYxNzllNTE6MHg1OTUwYjY1MzRmODdhZGI4ogEVCggvbS8wNTRydxIJTWFycmFrZXNoqgEbCgIIIRICCAgSAggVEgMIlAISAggvEgIIVBgBqgEHCgMIoQIYAKoBDAoDCLYBEgMIuAEYAaoBBgoCCGQYAKoBCgoCCC4SAghIGAGqAQwKAwiuARIDCLQBGAGqAQoKAghQEgIITxgBqgEMCgMIowESAwimARgBkgECIAE&rp=OAE&ap=KigKEgnMTAjvq10_QBEDE5fRp0ggwBISCVUcKnPo8D9AEQcmnm1ZfB7AMAFanwIKBQjMCBAAIgNNQUQqFgoHCOQPEAgYEhIHCOQPEAgYExgBKACwAQBYAWgBigEoChIJzEwI76tdP0ARAxOX0adIIMASEglVHCpz6PA_QBEHJp5tWXwewJoBMRIJTWFycmFrZXNoGiQweGRhZmVlOGQ5NjE3OWU1MToweDU5NTBiNjUzNGY4N2FkYjiiARUKCC9tLzA1NHJ3EglNYXJyYWtlc2iqARsKAgghEgIICBICCBUSAwiUAhICCC8SAghUGAGqAQcKAwihAhgAqgEMCgMItgESAwi4ARgBqgEGCgIIZBgAqgEKCgIILhICCEgYAaoBDAoDCK4BEgMItAEYAaoBCgoCCFASAghPGAGqAQwKAwijARIDCKYBGAGSAQIgAQ"
await page.goto(url,{
waitUntil: 'load',
// Remove the timeout
timeout: 0});
//for(i=0;i<10;i+)
console.log(url);
console.log('\n');
while(true){
await page.click('div.zbLWdb');
await page.waitFor(30*1000);
var new_link = page.url();
console.log(new_link);
console.log('\n\n');
i++;
}
} catch (err) {
console.error(err);
}
})();
我可以把这个脚本放在开始网址中吗?如何做到这一点?
解决方案
我不会为您提供成功抓取它的所有详细信息,但会给您一些提示。
a) 获得正确的名称很重要。在这种情况下,您使用的是Puppeteer Scraper。那是一个独立的演员。PuppeteerCrawler是 SDK(JS 库)中的一个类。
b) 链接选择器不会点击,它需要找到hrefs(真正的链接)。所以它不适用于这个用例。
c) 在这种情况下,我建议使用 PuppeteerCrawler 类创建一个新参与者(请参阅SDK站点中的示例)。
现在回答你的问题:
- 你可以在 Apify 中使用你的代码,它的工作原理是一样的。允许您将负载拆分为更多请求的更高级的解决方案正在用于
enqueueLinksByClickingElements
对下一页进行排队。但我不是 100% 确定它会在这个用例中正常工作。 - 它是同一个 Puppeteer 实例,所以没有限制。Apify 取决于
puppeteer
包。 - 唯一的大区别是 Apify 使在 Puppeteer 中使用经过身份验证的代理变得简单,否则,它是相同的。当然,PuppeteerCrawler 为您提供了大量功能,例如自动缩放并发、重试、代理轮换、会话等。
推荐阅读
- arrays - 尝试在 ruby 中复制然后旋转数组 - 为 nil:NilClass (NoMethodError) 获取错误未定义方法“[]”
- bash - BASH 脚本:如何替换文件路径字符串中的字符串?
- python - 我无法在 PyGame 中正确跟踪 KEYDOWN 事件
- database - 一个人如何获得在线学习 Redis 的帮助
- c++ - c ++计算数组中的单词
- c# - 使用 linq 从 2 个数据表中选择和分组数据,并在 datagridview 上显示结果
- python - 无法强制scrapy使用重定向的url进行回调
- qmake - 如何防止 make clean 删除 qmake 项目中的某个文件
- wordpress - 如何从字段键中获取值(Ninja Forms)
- request - 传递以字符 [ 开头的 JSON 请求会出现错误:使用 GET 操作的请求格式无效