我使用Node.js为一个简单的网络刮刀编写代码,并在线教程收集BuzzFeed测验的信息。它适用于主页面(https://www.buzzfeed.com/quizzes),但当我尝试在任何其他页面上使用它(即https://www.buzzfeed.com/quizzes?page=4)时,我得不到任何结果。我不确定是什么问题?这是我的代码:
var request = require('request');
var cheerio = require('cheerio');
var fs = require('fs');
var options = {
method: 'GET',
uri: 'https://www.buzzfeed.com/quizzes',
qs: {
page: 4
}
}
request(options, function(error, response, html) {
if(!error && response.statusCode == 200) {
var $ = cheerio.load(html);
$('div.card.js-feed-item').each(function( index ) {
var title = $(this).find('h2').text().trim();
var link = $(this).find('a.link-gray').attr('href');
var image = $(this).find('a.link-gray > div.js-progressive-image').attr('data-background-src');
fs.appendFileSync('buzzfeed.txt', title + '\n' + link + '\n' + image + '\n\n');
});
}});
基本上,如果我注释掉这个:
qs: {
page: 4
}
它工作正常。我使用qs错了吗?
答案 0 :(得分:0)
查看页面所做的请求,实际上你可以废弃这个URL:“https://www.buzzfeed.com/quizzes?render_template=0”,它会给你一个带有2个字段的json:cards(信息数组)和nextPage(类似于/ quizzes? render_template = 0& page = 2),您可以使用我认为相同的数据。
答案 1 :(得分:0)
看起来BuzzFeed服务器想要发送回压缩响应。如果您查看documentation for the request
module,可以找到以下选项:
gzip
- 如果true
,请添加Accept-Encoding
标头以请求来自服务器的压缩内容编码(如果尚未存在)并解码响应中支持的内容编码。
因此,在您的情况下,只需将gzip: true
添加到options
对象即可。但要注意,根据页面依赖JS显示其内容的程度,HTML可能不是您所期望的。
我是如何解决这个问题的?基本上,如果你检查返回的response
对象(在if
语句之外),你可以获得一些非常有用的信息。
例如,我们可以通过使用qs
(或response.request.url
)查看请求网址并查看(通过response.request.href
或调试程序)来检查console.log
选项是否有效它正确地形成了查询字符串(?page=4
),因此不是问题。
进一步挖掘我们可以看到response.statusCode
是500
而response.body
(或html
参数)是{"message": "INTERNAL_ERROR"}
。这似乎表明了服务器错误"但是我们可以在我们的浏览器中访问该页面,所以实际上服务器似乎并不喜欢我们出于某种原因形成我们的请求
有时这些值得查看response.headers
,我们可以在content-type
是application/json
(显然不是您想要的)。但更有趣的是,有一个vary
标题,其中一个值为Accept-Encoding
- 这基本上是说"如果您使用不同的Accept-Encoding标头再次发出此请求,您将获得不同的反应"。 Accept-Encoding几乎总是用于指定您可以处理的压缩类型,其中gzip是服务器最常支持的,因此Node请求模块提供了gzip
选项。如果您打开浏览器devtools的网络标签并浏览到该网址,则可以看到正在设置相同的标头(在Chrome中,通过&#34过滤请求;文档"以便更轻松地找到它)。
编辑:您的原始代码现在似乎对我有用,所以也许这毕竟是服务器问题。