在 Node/Express 中使用 Request.js 和 Cheerio.js 返回空数组
Posted
技术标签:
【中文标题】在 Node/Express 中使用 Request.js 和 Cheerio.js 返回空数组【英文标题】:Using Request.js and Cheerio.js in Node/Express return empty array 【发布时间】:2017-05-05 03:44:30 【问题描述】:我正在 Express 中使用 Request.js 和 Cheerio.js 构建一个简单的抓取工具。现在我只是在寻找网站的标题。我将列表放在一个数组中,而不是一个一个地抓取一个网站。我解析它们,然后使用 Cheerio.js 找到网站的标题。当我控制台记录标题时,它们会很好,但我想最终在 html 页面上显示它们。请注意,我对编程很陌生,所以如果您能提供详细的反馈,那将非常有帮助(以下是我一直在处理的代码)。提前致谢!
function parseSites(urls)
var parsedSites = [];
urls.forEach(function(site)
request(site, function(err, res, body)
if(err)
console.log(err);
else
var $ = cheerio.load(body);
parsedSites.push($('title').text());
);
);
return parsedSites;
【问题讨论】:
【参考方案1】:首先您需要了解异步代码和同步代码之间的区别。让我们看一个例子:
function testFor()
for(let i=0;i<5;++i)
console.log(i);
-
console.log('start:');
testFor();
console.log('end:');
// Here you get the expected output because this code is synchronous.
//output:
start:
0
1
2
3
4
end:
-
console.log('start:');
setTimeout(testFor,1000);
console.log('end:');
// Here you don't get your expected output because setTimeout is asynchronous .
//output:
start:
end:
0
1
2
3
4
-
首先是console.log('start:');叫做。
然后设置超时(testFor,1000); (但它是异步的并且调用
将在 1 秒后执行)。
console.log('end:');
被调用。
最后 1 秒后,testFor() 被执行,它
打印 0 1 2 3 4
下一点就是你的代码有错误!
function parseSites(urls)
var parsedSites = [];
urls.forEach(function(site)
request(site, function(err, res, body)
if(err)
console.log(err);
else
var $ = cheerio.load(body);
parsedSites.push($('title').text());
// ! THIS bracket should be removed
);
);
return parsedSites;
所以你的问题是,forEach 循环中的“请求”是一个异步函数,一旦有来自网页的响应,它将调用回调函数“function(err, res, body)”。
我的解决方案:
'use strict'
const cheerio = require('cheerio');
const request = require('request');
const async = require('async');
const urls = ['http://***.com/','http://hackaday.com/','https://www.raspberrypi.org/','https://cheerio.js.org/'];
//SOLUTION 1: do what you need to do when all calls are done using recursion
let i=0;
let parsedSites = [];
parseSites(urls[i],parsedSites);
function finalCall(sites)
console.log(sites);
function parseSites(site,parsedSites)
++i;
request(site, function(err, res, body)
if(err)
console.log(err);
else
let $ = cheerio.load(body);
let title = $('title').text();
console.log(title);
parsedSites.push(title);
if(i<urls.length)
parseSites(urls[i],parsedSites);// recursive call;
else
finalCall(parsedSites);// when all sites are done.
);
//return parsedSites;// cant return! we are in async calls!
//SOLUTION 2: do what you need to do when all calls are done using 'async'
parseSites(urls);
function finalCall(sites)
console.log(sites);
function parseSites(urls)
let parsedSites = [];
async.each(urls,function parseSite(site, callback)
request(site, function (err, res, body)
if (err)
callback(err);
else
let $ = cheerio.load(body);
parsedSites.push($('title').text());
callback();
)
,function (err)
if(err) console.log(err);
else finalCall(parsedSites);
);
Async github page
Async example
【讨论】:
非常感谢您的详细反馈。一直在玩 async.js,但仍在尝试掌握异步代码。这是超级超级有用!【参考方案2】:请参考下面的代码以获得有效的实现
var request = require('request-promise')
var cheerio = require("cheerio")
function parseSites(urls, callback)
var parsedSites = [];
var promiseList = urls.map(getPage)
Promise.all(promiseList).then(function (data)
callback(data.map(parse))
)
return parsedSites;
function getPage(url)
return request.get(url)
function parse(body)
console.log("parsing body")
var $ = cheerio.load(body);
return $('title').text()
parseSites(['https://www.google.com','https://www.facebook.com'],function(data)
console.log(data)
)
【讨论】:
非常感谢您的反馈。目前正在学习有关帮助处理异步代码的承诺!以上是关于在 Node/Express 中使用 Request.js 和 Cheerio.js 返回空数组的主要内容,如果未能解决你的问题,请参考以下文章
AWS Cognito 可以在 EB 上的 Node/Express/React 应用程序中使用吗?
如何在 Node/Express 中使用 CAC 对用户进行身份验证
Reactjs Stripe 支付不适用于 Node/Express
在 Node/Express 中使用 Request.js 和 Cheerio.js 返回空数组