node.js - 无法抓取所有数据cheerio - node.js
问题描述
js菜鸟在这里,
我正在尝试创建一个网络抓取工具来从预订网站上抓取价格数据,但我无法获得我想要的数据,至少不是每次都无法获得。
我正在测试这个特定的网址:
这是我在 20 次尝试中得到 1 次的结果:
{ prices:
[ 'Prix / nuit',
'Hébergement',
'Avis',
'Emplacement',
'Autres',
'max. 500€+',
'Bien',
'108€',
'Bien',
'112€',
'Excellent',
'98€',
'Très bien',
'122€',
'Très bien',
'164€',
'Excellent',
'156€',
'Très bien',
'97€',
'Très bien',
'160€',
'Très bien',
'155€',
' ',
'87€',
'Excellent',
'134€',
'Très bien',
'155€',
' ',
'92€',
'Excellent',
'135€',
'Très bien',
'135€',
'Excellent',
'94€',
' ',
'82€',
'Très bien',
'98€',
'Excellent',
'99€',
'Bien',
'110€',
'Bien',
'141€',
' ',
'80€',
'Très bien',
'136€',
'Excellent',
'122€',
'Excellent',
'232€',
'1',
'trivago N.V.' ] }
这是我大部分时间得到的:
{ prices:
[ 'Prix / nuit',
'Hébergement',
'Avis',
'Emplacement',
'Autres',
'max. 500€+',
'trivago N.V.' ] }
我被告知这可能与收集数据的速度有关,代码将在检索到所有数据之前结束运行
代码:
const puppeteer = require('puppeteer');
let cheerio = require('cheerio');
let jsonframe = require('jsonframe-cheerio');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port);
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
let frame;
await page.goto('https://www.trivago.fr/?aDateRange%5Barr%5D=2019-10-09&aDateRange%5Bdep%5D=2019-10-10&aPriceRange%5Bfrom%5D=0&aPriceRange%5Bto%5D=0&iRoomType=7&aRooms%5B0%5D%5Badults%5D=2&cpt2=22748%2F200&iViewType=0&bIsSeoPage=0&sortingId=1&slideoutsPageItemId=&iGeoDistanceLimit=20000&address=&addressGeoCode=&offset=0&ra=');
let bodyHTML = await page.evaluate(() => document.body.innerHTML).then(frame = {"prices": ["strong"]});
let $ = cheerio.load(bodyHTML);
jsonframe($);
var postsList = $('body').scrape(frame);
console.log(postsList);
await browser.close();
})();
解决方案
- 您正在解析的网站,Trivago,使用 AJAX 处理以下请求:
https://cdn-hs-graphql-dus.trivago.com/graphql
. 您可以使用 JSON 解析器解析响应,因此如果您不想使用 Puppeteer 解析,则应该了解它。 - 如果您不想监视这些请求(使用 chrome devtools),我建议您使用 Puppeteer。在 puppeteer 中,您可以使用 waitForSelector 方法。例如,如果您想获取一些酒店名称和价格,您可以等待选择器在 DOM 中可用,或者等待几秒钟。
- 如果你想用 jsonframe 提取一些数据,你还应该了解更多关于 CSS 选择器的知识。我更喜欢使用
[itemtype=""]
和[itemprop=""]
属性,因为此选择器可靠且查找速度快。
https://css-tricks.com/how-css-selectors-work/ - 要显示数据,您可以使用
console.log
,但如果您更喜欢使用 node.js 作为服务器,我建议您使用 express。 - 为了使您的脚本快速运行,您可以使用拦截器阻止请求中的图像。
- 在上面的代码中,您缺少cheerio 和 jsonframe 之间的链接
jsonframe($)
- 您可以使用这些代码作为示例。
(async () => {
const http = require('http');
const puppeteer = require('puppeteer');
const cheerio = require('cheerio');
const jsonframe = require('jsonframe-cheerio');
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.setDefaultNavigationTimeout(0);
page.setRequestInterception(true);
page.on('request', async request => {
if ( request.resourceType() === 'image' || request.resourceType() === 'media' ) {
request.abort();
} else {
request.continue();
}
});
const response = await page.goto('https://www.trivago.fr/?aDateRange%5Barr%5D=2019-10-09&aDateRange%5Bdep%5D=2019-10-10&aPriceRange%5Bfrom%5D=0&aPriceRange%5Bto%5D=0&iRoomType=7&aRooms%5B0%5D%5Badults%5D=2&cpt2=22748%2F200&iViewType=0&bIsSeoPage=0&sortingId=1&slideoutsPageItemId=&iGeoDistanceLimit=20000&address=&addressGeoCode=&offset=0&ra=');
const waitForAJAXComplete = await page.waitForSelector('h3[itemprop="name"]>span.item-link');
const bodyHTML = await page.content();
const exit = await browser.close();
const $ = await cheerio.load(bodyHTML);
jsonframe($)
let frame = {
hotels : {
_s : "[itemtype='https://schema.org/Hotel']",
_d : [{
"hotelname" : "h3[itemprop='name']>span.item-link",
"hotelprice": "meta[itemprop='price'] ~ em ~ strong"
}]
}
};
const displayResult = $('body').scrape(frame, { string: true } );
if (displayResult.length > 0) {
const responseCode = '200';
const server = http.createServer(function(req,res){
res.writeHead(responseCode, {'Content-Type': 'application/json; charset=utf-8'});
res.end(displayResult);
}).listen(3000);
console.log('Node Server running on localhost:3000');
} else {
console.log('Node Server cannot running, because results cannot be parsed.')
}
})();
推荐阅读
- python - Python pandas dataframe.value 返回一个具有奇怪属性的 ndarray,可以绘制但会破坏 lmfit
- javascript - 如何在对象内声明局部变量并在javascript中直接引用
- c# - 将 Json 数据绑定到 Echart
- javascript - 使用 JavaScript 在 2 个不同的数组中查找不重复项的数量?
- angular - Angular 模板驱动的自定义验证器
- css - Css 网格 - html 表单 - 我无法在垂直流中引导我的元素
- sql - 更新 SQL 查询本身死锁
- java - 如何为 TableView 创建条件 CellValueFactory?
- vim - 如何映射键“;” 在尼奥维姆
- php - 返回或回显视图有什么区别?返回视图说话的时间比回声视图长