如何解析多个页面?
How do I parse multiple pages?
我一直在尝试将站点 table 数据解析到 json 文件中,如果我逐页解析,我可以做到这一点,但看到有 415 页会稍等片刻。
我已经看到并阅读了很多关于这个主题的 Whosebug 问题,但我似乎无法修改我的脚本以便它;
- 抓取每个页面并提取每页具有项目 ID 的 50 个项目
- 以速率受限的方式这样做,这样我就不会对服务器产生负面影响
- 脚本会等待所有请求完成,这样我就可以将每个项目 + 项目 ID 写入 JSON 文件。
我相信你应该能够使用请求承诺和 promise.all 来做到这一点,但我无法弄清楚。
数据的实际抓取很好我只是无法编写代码,抓取页面,然后在请求之间延迟或暂停转到下一个 URL。
下面的代码是我得到的最接近的代码,但我多次得到相同的结果,我无法降低请求率。
页面示例 URLS:
- http://test.com/itemlist/1
- http://test.com/itemlist/2
http://test.com/itemlist/3 等(最多 415)
for (var i = 1; i <= noPages; i++) {
urls.push({url: itemURL + i});
console.log(itemURL + i);
}
Promise.map(urls, function(obj) {
return rp(obj).then(function(body) {
var $ = cheerio.load(body);
//Some calculations again...
rows = $('table tbody tr');
$(rows).each(function(index, row) {
var children = $(row).children();
var itemName = children.eq(1).text().trim();
var itemID = children.eq(2).text().trim();
var itemObj = {
"id" : itemID,
"name" : itemName
};
itemArray.push(itemObj);
});
return itemArray;
});
},{concurrency : 1}).then(function(results) {
console.log(results);
for (var i = 0; i < results.length; i++) {
// access the result's body via results[i]
//console.log(results[i]);
}
}, function(err) {
// handle all your errors here
console.log(err);
});
抱歉可能误解 node.js 及其模块,我并没有真正使用该语言,但我需要抓取一些数据,我真的不喜欢 python。
因为您需要请求 运行 只能一个接一个 Promise.all() 无济于事。
递归承诺(我不确定它是否正确命名)会。
function fetchAllPages(list) {
if (!list || !list.length) return Promise. resolve(); // trivial exit
var urlToFetch = list.pop();
return fetchPage(urlToFetch).
then(<wrapper that returns Promise will be resolved after delay >).
then(function() {
return fetchAllPages(list); // recursion!
});
}
这段代码仍然缺少错误处理。
我也相信 async/await:
会变得更加清晰
for(let url of urls) {
await fetchAndProcess(url);
await <wrapper around setTimeout>;
}
但您需要找到/编写自己的 fetch()
和 setTimeout()
实现,它们是 async
在@skyboyer 建议使用递归承诺后,我被引导到一个名为 Sequential execution of Promises using reduce()
的 GitHub Gist
首先我创建了我的 URLS 数组
for (var i = 1; i <= noPages; i++) {
//example urls[0] = "http://test.com/1"
//example urls[1] = "http://test.com/2"
urls.push(itemURL + i);
console.log(itemURL + i);
}
然后
var sequencePromise = urls.reduce(function(promise, url) {
return promise.then(function(results) {
//fetchIDsFromURL async function (it returns a promise in this case)
//when the promise resolves I have my page data
return fetchIDsFromURL(url)
.then(promiseWithDelay(9000))
.then(itemArr => {
results.push(itemArr);
//calling return inside the .then method will make sure the data you want is passed onto the next
return results;
});
});
}, Promise.resolve([]));
// async
function fetchIDsFromURL(url)
{
return new Promise(function(resolve, reject){
request(url, function(err,res, body){
//console.log(body);
var $ = cheerio.load(body);
rows = $('table tbody tr');
$(rows).each(function(index, row) {
var children = $(row).children();
var itemName = children.eq(1).text().trim();
var itemID = children.eq(2).text().trim();
var itemObj = {
"id" : itemID,
"name" : itemName
};
//push the 50 per page scraped items into an array and resolve with
//the array to send the data back from the promise
itemArray.push(itemObj);
});
resolve(itemArray);
});
});
}
//returns a promise that resolves after the timeout
function promiseWithDelay(ms)
{
let timeout = new Promise(function(resolve, reject){
setTimeout(function()
{
clearTimeout(timeout);
resolve();
}, ms);
});
return timeout;
}
然后最后在 promise 序列上调用 .then,我遇到的唯一问题是在结果中返回多个数组,每个数组中的数据相同,所以由于每个数组中的所有数据都相同,我只采用第一个包含我所有已解析的带有 ID 的项目,然后我将其写入 JSON 文件。
sequencePromise.then(function(results){
var lastResult = results.length;
console.log(results[0]);
writeToFile(results[0]);
});
我一直在尝试将站点 table 数据解析到 json 文件中,如果我逐页解析,我可以做到这一点,但看到有 415 页会稍等片刻。
我已经看到并阅读了很多关于这个主题的 Whosebug 问题,但我似乎无法修改我的脚本以便它;
- 抓取每个页面并提取每页具有项目 ID 的 50 个项目
- 以速率受限的方式这样做,这样我就不会对服务器产生负面影响
- 脚本会等待所有请求完成,这样我就可以将每个项目 + 项目 ID 写入 JSON 文件。
我相信你应该能够使用请求承诺和 promise.all 来做到这一点,但我无法弄清楚。
数据的实际抓取很好我只是无法编写代码,抓取页面,然后在请求之间延迟或暂停转到下一个 URL。 下面的代码是我得到的最接近的代码,但我多次得到相同的结果,我无法降低请求率。
页面示例 URLS:
- http://test.com/itemlist/1
- http://test.com/itemlist/2
http://test.com/itemlist/3 等(最多 415)
for (var i = 1; i <= noPages; i++) { urls.push({url: itemURL + i}); console.log(itemURL + i); } Promise.map(urls, function(obj) { return rp(obj).then(function(body) { var $ = cheerio.load(body); //Some calculations again... rows = $('table tbody tr'); $(rows).each(function(index, row) { var children = $(row).children(); var itemName = children.eq(1).text().trim(); var itemID = children.eq(2).text().trim(); var itemObj = { "id" : itemID, "name" : itemName }; itemArray.push(itemObj); }); return itemArray; }); },{concurrency : 1}).then(function(results) { console.log(results); for (var i = 0; i < results.length; i++) { // access the result's body via results[i] //console.log(results[i]); } }, function(err) { // handle all your errors here console.log(err); });
抱歉可能误解 node.js 及其模块,我并没有真正使用该语言,但我需要抓取一些数据,我真的不喜欢 python。
因为您需要请求 运行 只能一个接一个 Promise.all() 无济于事。 递归承诺(我不确定它是否正确命名)会。
function fetchAllPages(list) {
if (!list || !list.length) return Promise. resolve(); // trivial exit
var urlToFetch = list.pop();
return fetchPage(urlToFetch).
then(<wrapper that returns Promise will be resolved after delay >).
then(function() {
return fetchAllPages(list); // recursion!
});
}
这段代码仍然缺少错误处理。 我也相信 async/await:
会变得更加清晰for(let url of urls) {
await fetchAndProcess(url);
await <wrapper around setTimeout>;
}
但您需要找到/编写自己的 fetch()
和 setTimeout()
实现,它们是 async
在@skyboyer 建议使用递归承诺后,我被引导到一个名为 Sequential execution of Promises using reduce()
的 GitHub Gist首先我创建了我的 URLS 数组
for (var i = 1; i <= noPages; i++) {
//example urls[0] = "http://test.com/1"
//example urls[1] = "http://test.com/2"
urls.push(itemURL + i);
console.log(itemURL + i);
}
然后
var sequencePromise = urls.reduce(function(promise, url) {
return promise.then(function(results) {
//fetchIDsFromURL async function (it returns a promise in this case)
//when the promise resolves I have my page data
return fetchIDsFromURL(url)
.then(promiseWithDelay(9000))
.then(itemArr => {
results.push(itemArr);
//calling return inside the .then method will make sure the data you want is passed onto the next
return results;
});
});
}, Promise.resolve([]));
// async
function fetchIDsFromURL(url)
{
return new Promise(function(resolve, reject){
request(url, function(err,res, body){
//console.log(body);
var $ = cheerio.load(body);
rows = $('table tbody tr');
$(rows).each(function(index, row) {
var children = $(row).children();
var itemName = children.eq(1).text().trim();
var itemID = children.eq(2).text().trim();
var itemObj = {
"id" : itemID,
"name" : itemName
};
//push the 50 per page scraped items into an array and resolve with
//the array to send the data back from the promise
itemArray.push(itemObj);
});
resolve(itemArray);
});
});
}
//returns a promise that resolves after the timeout
function promiseWithDelay(ms)
{
let timeout = new Promise(function(resolve, reject){
setTimeout(function()
{
clearTimeout(timeout);
resolve();
}, ms);
});
return timeout;
}
然后最后在 promise 序列上调用 .then,我遇到的唯一问题是在结果中返回多个数组,每个数组中的数据相同,所以由于每个数组中的所有数据都相同,我只采用第一个包含我所有已解析的带有 ID 的项目,然后我将其写入 JSON 文件。
sequencePromise.then(function(results){
var lastResult = results.length;
console.log(results[0]);
writeToFile(results[0]);
});