
在进行网页抓取时,尤其面对像tripadvisor这类动态加载内容的网站,传统的http请求方式往往难以奏效。这些网站大量使用javascript来渲染页面内容,导致通过查看页面源代码无法直接获取所需数据。此时,像puppeteer这样的无头浏览器工具就显得尤为重要。
Puppeteer是一个Node.js库,它提供了一组高级API来控制Chrome或Chromium。通过Puppeteer,我们可以模拟用户在浏览器中的操作,例如打开页面、点击元素、填写表单,并等待JavaScript执行完毕,从而获取到完全渲染后的页面内容。这使得抓取动态网站变得可行。
在Puppeteer中,准确地定位页面元素是成功抓取数据的关键。这通常通过CSS选择器来完成。许多初学者在尝试抓取数据时,常常会遇到选择器错误,导致无法获取到预期的元素或数据。这可能是由于以下原因:
例如,针对TripAdvisor景点列表页,要抓取列表项的标题,原始的选择器可能不够精确。以下是几种更健壮的选择器示例:
修正标题选择器的方法:
假设我们希望抓取TripAdvisor景点列表中的标题。我们可以通过检查页面结构,找到更稳定、更具描述性的CSS选择器。
使用article作为基础容器并精确定位内部链接:
const places = await page.evaluate(() =>
Array.from(document.querySelectorAll('article'), (e) => ({
title: e.querySelector('.VLKGO a:not([class])').innerText
}))
);这里,我们首先找到每个article元素(通常代表一个独立的列表项),然后在每个article内部,通过.VLKGO a:not([class])来定位到标题链接。.VLKGO是一个包含标题的父容器,a:not([class])则确保我们选择的是没有额外类名的链接,这通常是标题链接的特征,避免选中其他辅助链接。
直接定位标题文本的父元素:
let places = await page.$$eval('article .VLKGO span > div', el =>
el.map(x => x.textContent)
);这种方法利用$$eval在浏览器环境中执行JavaScript,直接选择所有匹配article .VLKGO span > div的元素,并提取它们的textContent。span > div进一步缩小了范围,确保我们直接获取到标题文本。
这些修正后的选择器,通过更具体或更稳定的元素结构来定位,大大提高了抓取的成功率。
仅抓取标题通常不足以满足需求。在实际应用中,我们可能需要提取更多信息,例如链接、图片、描述、价格和作者等。为了实现这一点,我们可以结合使用page.$$和element.$eval。
下面是一个完整的Puppeteer脚本,演示如何从TripAdvisor页面抓取包括标题、链接、图片、描述、价格和作者在内的多项数据:
const puppeteer = require("puppeteer");
let browser; // 声明浏览器实例变量,以便在finally块中关闭
(async () => {
browser = await puppeteer.launch({ headless: true }); // 建议生产环境设置为true
const page = await browser.newPage();
let url = 'https://www.tripadvisor.com/Attractions-g297476-Activities-c42-Cartagena_Cartagena_District_Bolivar_Department.html';
// 导航到目标URL,并等待页面加载完成和关键元素出现
await page.goto(url, { waitUntil: 'load', timeout: 30000 }); // 增加超时时间
await page.waitForSelector('main', { timeout: 10000 }); // 等待主要内容区域加载
// 获取所有代表一个景点的article元素
let places = await page.$$('article');
let data = [];
for (let place of places) {
try {
// 提取标题和链接
let header = await place.$eval('.VLKGO a:not([class])', el => {
// 清理标题前的序号(如 "1. ")
const name = el.textContent.split('.').pop().trim();
const link = el.getAttribute('href');
return { name, link };
});
// 提取图片URL
let image = await place.$eval('picture > img[srcset]', el => el.getAttribute('srcset'));
// 从srcset中获取最大尺寸的图片URL
image = image.split(',').pop().replace(/2x/gi, '').trim();
// 提取描述
let desc = await place.$eval('a:not([class]) > div > span', el => el.textContent.trim());
// 提取作者信息
let by = await place.$eval('.VLKGO div > div > div > a', el => {
const name = el.textContent.replace('By ', '').trim();
const link = el.getAttribute('href');
return { name, link };
});
// 提取价格(如果存在)
let price = null;
let priceTxt = null;
try {
const priceEl = await place.$('[data-automation=cardPrice]');
if (priceEl) {
price = await priceEl.evaluate(el => el.textContent);
}
} catch (error) {
// 价格元素可能不存在,忽略错误
}
try {
const priceTxtEl = await place.$('div:nth-child(1) > div:nth-child(3):not([class])');
if (priceTxtEl) {
priceTxt = await priceTxtEl.evaluate(el => el.textContent);
}
} catch (error) {
// 价格文本元素可能不存在,忽略错误
}
data.push({
name: header.name,
link: header.link,
desc: desc,
image: image,
price: price,
priceTxt: priceTxt,
by: by
});
} catch (error) {
console.error("在处理某个景点时发生错误:", error.message);
// 可以选择跳过当前景点或记录错误信息
}
}
console.log(data);
await browser.close();
})().catch(err => console.error("抓取过程中发生未捕获错误:", err))
.finally(() => {
if (browser) {
browser.close(); // 确保在任何情况下都关闭浏览器
}
});puppeteer.launch({ headless: true }):
page.goto(url, { waitUntil: 'load', timeout: 30000 }):
page.waitForSelector('main', { timeout: 10000 }):
page.$$('article') 与 place.$eval():
数据清洗与处理:
错误处理:
通过本教程,您应该已经掌握了使用Puppeteer抓取TripAdvisor旅游景点数据的基本方法和进阶技巧。从选择器的精确定位到复杂数据的结构化提取,再到错误处理和最佳实践,这些都是构建健壮、高效网页爬虫的关键要素。记住,深入理解目标网站的DOM结构,并灵活运用Puppeteer提供的API,是成功进行网页抓取的基石。
以上就是使用Puppeteer抓取TripAdvisor旅游景点数据:从基础到高级实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号