gpt4 book ai didi

node.js - 使用 Node.js 和请求进行网页抓取

转载 作者:太空宇宙 更新时间:2023-11-04 01:50:53 28 4
gpt4 key购买 nike

我想做 this site 的网页抓取。我已经看到 API 可用,但是正如 duraid 在我的 previous question 中所建议的那样,不建议使用它们。

所以我尝试使用 Node.jsPhantom.jsPhantom 。但用户Vaviloff pointed out to me headless 浏览器不是必需的,因为使用搜索请求的 URL 就足够了。

因此我改变了策略,尝试不使用 Phantom 而是使用正常的请求:

var cheerio = require('cheerio');
var request = require('request-promise');

var options = {
uri: 'http://data.un.org/Handlers/DataHandler.ashx?Service=query&Anchor=variableID%3a12&Applied=crID%3a8&crID%3a40;timeID%3a79&DataMartId=PopDiv&UserQuery=population&c=2,4,6,7&s=_crEngNameOrderBy:asc,_timeEngNameOrderBy:desc,_varEngNameOrderBy:asc&RequestId=302',
transform: function(body) {
return cheerio.load(body);
}
};

methods.download = async function(req, res) {
request(options)
.then(function($) {
console.log('\n\nTHEN: ', $);
})
.catch(function(err) {
console.log('Error', err.stack());
});
}

如果我运行这段代码,我会得到:

THEN:  function (selector, context, r, opts) {
if (!(this instanceof initialize)) {
return new initialize(selector, context, r, opts);
}
opts = _.defaults(opts || {}, options);
return Cheerio.call(this, selector, context, r || root, opts);
}

在这种情况下,我还有其他问题。

  1. 我不知道如何构建网址。在上面的示例中,我选择阿尔巴尼亚 (crID% 3a8) 和奥地利 (crID% 3a40) 以及 2015 年作为年份 (timeID% 3a79)。然而,如果我访问刚刚建立的链接,我会得到 2100 年至 2095 年阿尔巴尼亚的数据。
  2. 我不知道如何选择年份、如何选择变体或如何更改页面。

我对以下信息感兴趣:

var countries = {
'Albania': 'crID%3a8',
'Austria': 'crID%3a40',
'Belgium': 'crID%3a56',
'Bulgaria': 'crID%3a100',
'Croatia': 'crID%3a191',
'Cyprus': 'crID%3a196',
'Denmark': 'crID%3a208',
'Estonia': 'crID%3a233',
'Finland': 'crID%3a246',
'France': 'crID%3a250',
'Germany': 'crID%3a276',
'Greece': 'crID%3a300',
'Iceland': 'crID%3a352',
'Ireland': 'crID%3a372',
'Italy': 'crID%3a380',
'Latvia': 'crID%3a428',
'Netherlands': 'crID%3a528',
'Norway': 'crID%3a578',
'Poland': 'crID%3a616',
'Portugal': 'crID%3a620',
'Romania': 'crID%3a642',
'Slovakia': 'crID%3a703',
'Slovenia': 'crID%3a705',
'Spain': 'crID%3a724',
'Sweden': 'crID%3a752',
'Switzerland': 'crID%3a756',
'United Kingdom': 'crID%3a826'
};
// 2018 - 1980
var years = ['timeID%3a83', 'timeID%3a82', 'timeID%3a81', 'timeID%3a79', 'timeID%3a78', 'timeID%3a77', 'timeID%3a76', 'timeID%3a75', 'timeID%3a73', 'timeID%3a72', 'timeID%3a71', 'timeID%3a70', 'timeID%3a69', 'timeID%3a67', 'timeID%3a66', 'timeID%3a65', 'timeID%3a64', 'timeID%3a63', 'timeID%3a61', 'timeID%3a60', 'timeID%3a59', 'timeID%3a58', 'timeID%3a57', 'timeID%3a55', 'timeID%3a54', 'timeID%3a53', 'timeID%3a52', 'timeID%3a51', 'timeID%3a49', 'timeID%3a48', 'timeID%3a47', 'timeID%3a46', 'timeID%3a45', 'timeID%3a43', 'timeID%3a42', 'timeID%3a41', 'timeID%3a40', 'timeID%3a39', 'timeID%3a37'];
// medium
var variants = 'varID%3a2';

仅为了完整性:选择数据后,我需要创建一个如下所示的对象:

var date = [{year: 2018,country:'阿尔巴尼亚',population:2934.363},{year:2017,country:'Albania',population:2930.187},...,{year:1980,country:'United Kingdom',population:56265.475}]

所以我创建了一个这样的函数:

methods.createJsonObjectPop = function(year, country, population) {
return {
year: year,
country: country,
population: population
};
}

任何建议都会对我有很大帮助!

<小时/>

编辑1

内容分为多个页面。我们怎样才能得到所有的数据呢?也许可以通过打开所有页面并合并数据来实现?这是显而易见的。如果X是页数,我想我必须执行不同的X请求。

网站如何知道请求的是哪个页面?我认为这要归功于网址,但我不确定(例如 http://...Page=3...)。

我想象这个伪代码:

var basicUrl = 'http://data.un.org/Handlers/DataHandler.ashx?Service=query&Anchor=variableID%3a12&Applied=crID%3a8;crID%3a40;crID%3a56;crID%3a100;crID%3a191;crID%3a196;crID%3a208;crID%3a233;crID%3a246;crID%3a250;crID%3a276;crID%3a300;crID%3a352;crID%3a372;crID%3a380;crID%3a428;crID%3a528;crID%3a578;crID%3a616;crID%3a620;crID%3a642;crID%3a703;crID%3a705;crID%3a724;crID%3a752;crID%3a756;crID%3a826;timeID%3a83;timeID%3a82;timeID%3a81;timeID%3a79;timeID%3a78;timeID%3a77;timeID%3a76;timeID%3a75;timeID%3a73;timeID%3a72;timeID%3a71;timeID%3a70;timeID%3a69;timeID%3a67;timeID%3a66;timeID%3a65;timeID%3a64;timeID%3a63;timeID%3a61;timeID%3a60;timeID%3a59;timeID%3a58;timeID%3a57;timeID%3a55;timeID%3a54;timeID%3a53;timeID%3a52;timeID%3a51;timeID%3a49;timeID%3a48;timeID%3a47;timeID%3a46;timeID%3a45;timeID%3a43;timeID%3a42;timeID%3a41;timeID%3a40;timeID%3a39;timeID%3a37;varID%3a2&DataMartId=PopDiv&UserQuery=population&c=2,4,6,7&s=_crEngNameOrderBy:asc,_timeEngNameOrderBy:desc,_varEngNameOrderBy:asc&RequestId=531';
let promises = [];
let allData = [];

var options = {
uri: url,
transform: function(body) {
return cheerio.load(body);
}
};

methods.download = async function(req, res) {
for(var i = 0; i < X; i++) {
var url = basicUrl + '&Page=' + i;
let res = await request(options, url);
let data = elaborateData(res);
allData.push(data);
}
return Promise.all(promises);
}

function elaborateData(res) {
var el = document.createElement('html');
// use javascript or jQuery to get data like:
// var year = getElementByTag(...);
// var country = getElementByTag(...);
// var population = getElementByTag(...);
return createJsonObjectPop(year, country, population);
}
<小时/>

编辑2

var basicUrl = 'http://data.un.org/Handlers/DataHandler.ashx?Service=query&Anchor=variableID%3a12&Applied=crID%3a8;crID%3a40;crID%3a56;crID%3a100;crID%3a191;crID%3a196;crID%3a208;crID%3a233;crID%3a246;crID%3a250;crID%3a276;crID%3a300;crID%3a352;crID%3a372;crID%3a380;crID%3a428;crID%3a528;crID%3a578;crID%3a616;crID%3a620;crID%3a642;crID%3a703;crID%3a705;crID%3a724;crID%3a752;crID%3a756;crID%3a826;timeID%3a83;timeID%3a82;timeID%3a81;timeID%3a79;timeID%3a78;timeID%3a77;timeID%3a76;timeID%3a75;timeID%3a73;timeID%3a72;timeID%3a71;timeID%3a70;timeID%3a69;timeID%3a67;timeID%3a66;timeID%3a65;timeID%3a64;timeID%3a63;timeID%3a61;timeID%3a60;timeID%3a59;timeID%3a58;timeID%3a57;timeID%3a55;timeID%3a54;timeID%3a53;timeID%3a52;timeID%3a51;timeID%3a49;timeID%3a48;timeID%3a47;timeID%3a46;timeID%3a45;timeID%3a43;timeID%3a42;timeID%3a41;timeID%3a40;timeID%3a39;timeID%3a37;varID%3a2&DataMartId=PopDiv&UserQuery=population&c=2,4,6,7&s=_crEngNameOrderBy:asc,_timeEngNameOrderBy:desc,_varEngNameOrderBy:asc&RequestId=531';
let promises = [];
let allData = [];
var pages = 22; // data are splitting in 22 pages

methods.download = async function(req, res) {
for(var i = 0; i < pages; i++) {
var url = basicUrl + '&Page=' + i;

var options = {
uri: url,
transform: function(html) {
return cheerio.load(html);
}
};

let res = await request(options)
.then(function($) {
return $;
})
.catch(function(err) {
console.log('Error', err.stack());
});

console.log('\n\nRES:', res);
let data = elaborateData(res);
allData.push(data);
}
return Promise.all(promises);
}

function elaborateData($) {
$('.td').each(function() {
console.log($(this).text());
});
// use javascript or jQuery to get data like:
// var year = getElementByTag(...);
// var country = getElementByTag(...);
// var population = getElementByTag(...);
//return createJsonObjectPop(year, country, population);
}

如果我运行这段代码,我会得到:

RES: function (selector, context, r, opts) {
if (!(this instanceof initialize)) {
return new initialize(selector, context, r, opts);
}
opts = _.defaults(opts || {}, options);
return Cheerio.call(this, selector, context, r || root, opts);
}

编辑3

var cheerioTableparser = require('cheerio-tableparser');

methods.download = async function(req, res) {
for(var i = 0; i < 22; i++) {
var url = basicUrl + '&Page=' + i; // DOESN'T WORK

var options = {
uri: url,
transform: function(html) {
return cheerio.load(html);
}
};

let res = await request(options)
.then(function($) {
return $;
})
.catch(function(err) {
console.log('Error', err.stack());
});

//console.log('\n\nRES:', res);
let data = elaborateData(res);
allData.push(data);
}
return Promise.all(promises);
}

function elaborateData($) {
cheerioTableparser($);
var data = $('table').parsetable(true, true, true);

var countries = data[0];
var years = data[1];
var variants = data[2];
var values = data[3];
console.log('\ncountries:', countries);
console.log('\nyears:', years);
console.log('\nvariants:', variants);
console.log('\nvalues:', values);

// use javascript or jQuery to get data like:
// var year = getElementByTag(...);
// var country = getElementByTag(...);
// var population = getElementByTag(...);
//return createJsonObjectPop(year, country, population);
}

我得到:

countries: [ 'Country or Area',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Albania',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria',
'Austria' ]

years: [ 'Year(s)',
'2018',
'2017',
'2016',
'2015',
'2014',
'2013',
'2012',
'2011',
'2010',
'2009',
'2008',
'2007',
'2006',
'2005',
'2004',
'2003',
'2002',
'2001',
'2000',
'1999',
'1998',
'1997',
'1996',
'1995',
'1994',
'1993',
'1992',
'1991',
'1990',
'1989',
'1988',
'1987',
'1986',
'1985',
'1984',
'1983',
'1982',
'1981',
'1980',
'2018',
'2017',
'2016',
'2015',
'2014',
'2013',
'2012',
'2011',
'2010',
'2009',
'2008' ]

variants: [ 'Variant',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium',
'Medium' ]

values: [ 'Value',
'2934.363',
'2930.187',
'2926.348',
'2923.352',
'2920.775',
'2918.978',
'2920.039',
'2926.659',
'2940.525',
'2962.635',
'2991.651',
'3023.907',
'3054.331',
'3079.179',
'3097.747',
'3111.005',
'3119.029',
'3122.408',
'3121.970',
'3115.576',
'3103.759',
'3093.041',
'3092.228',
'3106.736',
'3140.595',
'3189.583',
'3240.587',
'3275.431',
'3281.454',
'3253.656',
'3197.067',
'3121.336',
'3041.007',
'2966.798',
'2901.592',
'2842.624',
'2788.314',
'2735.329',
'2681.239',
'8751.820',
'8735.453',
'8712.137',
'8678.657',
'8633.220',
'8577.782',
'8517.548',
'8459.864',
'8409.949',
'8370.038',
'8338.453' ]

可以,只是我只能从第一页获取数据。

最佳答案

密切关注被抓取网站提出的所有请求。

如果您将 ajax 请求的目标站点设置为 1 以外的页面,您将看到初始 URL

http://data.un.org/Handlers/DataHandler.ashx?Service=query&Anchor=variableID%3a12&Applied=crID%3a8&crID%3a40;timeID%3a79&DataMartId=PopDiv&UserQuery=population&c=2,4,6,7&s=_crEngNameOrderBy:asc,_timeEngNameOrderBy:desc,_varEngNameOrderBy:asc&RequestId=302

被替换为另一个:

http://data.un.org/Handlers/DataHandler.ashx?Service=page&Page=2&DataFilter=variableID%3a12%3btimeID%3a178%2c179&DataMartId=PopDiv&UserQuery=population&c=2,4,6,7&s=_crEngNameOrderBy:asc,_timeEngNameOrderBy:desc,_varEngNameOrderBy:asc&RequestId=361

Service=query 替换为 Service=page,它也接受页码 Page=N

您可以在所有现代浏览器中监控此类请求,尽管目前我更喜欢 Google Chrome,因为根据我的经验,它的开发工具是最快的。

因此,在 Google Chrome 中按 F12 或 CTRL +,然后单击“网络”选项卡,然后单击“XHR”过滤器。这将向您显示该站点发出的所有新的 ajax 请求。

Turn on AJAX requests monitor

关于node.js - 使用 Node.js 和请求进行网页抓取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49727577/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com