如何使用nodejs发送批量获取请求?
How to send bulk get requests using nodejs?
我用nodejs写了一个网络爬虫,发送get请求大概300个urls。
这是主循环:
for (let i = 1; i <= 300; i++) {
let page= `https://xxxxxxxxx/forum-103-${i}.html`
await getPage(page,(arr)=>{
console.log(`page ${i}`)
})
}
这里是函数 getPage(url,callback):
export default async function getPage(url, callback) {
await https.get(url, (res) => {
let html = ""
res.on("data", data => {
html += data
})
res.on("end", () => {
const $ = cheerio.load(html)
let obj = {}
let arr = []
obj = $("#threadlisttableid tbody")
for (let i in obj) {
if (obj[i].attribs?.id?.substr(0, 6) === 'normal') {
arr.push(`https://xxxxxxx/${obj[i].attribs.id.substr(6).split("_").join("-")}-1-1.html`)
}
}
callback(arr)
console.log("success!")
})
})
.on('error', (e) => {
console.log(`Got error: ${e.message}`);
})
}
我使用 cheerio 分析 HTML 并将我需要的所有信息放入名为 'arr' 的变量中。
程序在运行后正常运行一段时间后会报错,比如:
...
success!
page 121
success!
page 113
success!
page 115
success!
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
我有两个问题:
1.What是错误的原因?是因为我发送了太多的获取请求吗?如何限制请求频率?
2.As可以看到,页面访问顺序乱了,怎么控制?
我尝试过使用其他模块发送get请求(比如axios),但是没有成功。
As you can see, The order in which the pages are accessed is chaotic,how to control them?
await
是没有意义的,除非你在右边放一个 promise。 http.get
不做承诺。
你可以 wrap it in a promise but it would be easier to use an API which supports then natively such as node-fetch, axios, or Node.js's native fetch。 (在我看来,所有 API 都比 http.get 更易于使用,一般而言也不只是在流量控制方面)。
What is the reason for the error?
不清楚。
Is it because I am sending too many get requests?
这是一个可能的假设。
How can I limit the request frequency?
一旦您的 for
循环使用 promises 以便请求以串行方式发送而不是并行发送,您可以在每个请求之间插入一个 sleep。
由于错误使用 await
,循环没有等待上一个请求,因此同时触发了 http 请求。适当控制循环会限制请求频率。
for (let i = 1; i <= 300; i++) {
let page= `https://xxxxxxxxx/forum-103-${i}.html`
var arr = await getPage(page);
// use arr in the way you want
console.log(`page ${i}`);
}
export default async function getPage(url) {
// Declare a new promise, wait for the promise to resolve and return its value.
return await new Promise((reso, rej) => {
https.get(url, (res) => {
let html = ""
res.on("data", data => {
html += data
})
res.on("end", () => {
const $ = cheerio.load(html)
let obj = {}
let arr = []
obj = $("#threadlisttableid tbody")
for (let i in obj) {
if (obj[i].attribs?.id?.substr(0, 6) === 'normal') {
arr.push(`https://xxxxxxx/${obj[i].attribs.id.substr(6).split("_").join("-")}-1-1.html`)
}
}
reso(arr) // Resolve with arr
console.log("success!")
})
})
.on('error', (e) => {
console.log(`Got error: ${e.message}`);
throw e;
})
})
}
我用nodejs写了一个网络爬虫,发送get请求大概300个urls。 这是主循环:
for (let i = 1; i <= 300; i++) {
let page= `https://xxxxxxxxx/forum-103-${i}.html`
await getPage(page,(arr)=>{
console.log(`page ${i}`)
})
}
这里是函数 getPage(url,callback):
export default async function getPage(url, callback) {
await https.get(url, (res) => {
let html = ""
res.on("data", data => {
html += data
})
res.on("end", () => {
const $ = cheerio.load(html)
let obj = {}
let arr = []
obj = $("#threadlisttableid tbody")
for (let i in obj) {
if (obj[i].attribs?.id?.substr(0, 6) === 'normal') {
arr.push(`https://xxxxxxx/${obj[i].attribs.id.substr(6).split("_").join("-")}-1-1.html`)
}
}
callback(arr)
console.log("success!")
})
})
.on('error', (e) => {
console.log(`Got error: ${e.message}`);
})
}
我使用 cheerio 分析 HTML 并将我需要的所有信息放入名为 'arr' 的变量中。 程序在运行后正常运行一段时间后会报错,比如:
...
success!
page 121
success!
page 113
success!
page 115
success!
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
Got error: connect ETIMEDOUT 172.67.139.206:443
我有两个问题:
1.What是错误的原因?是因为我发送了太多的获取请求吗?如何限制请求频率?
2.As可以看到,页面访问顺序乱了,怎么控制?
我尝试过使用其他模块发送get请求(比如axios),但是没有成功。
As you can see, The order in which the pages are accessed is chaotic,how to control them?
await
是没有意义的,除非你在右边放一个 promise。 http.get
不做承诺。
你可以 wrap it in a promise but it would be easier to use an API which supports then natively such as node-fetch, axios, or Node.js's native fetch。 (在我看来,所有 API 都比 http.get 更易于使用,一般而言也不只是在流量控制方面)。
What is the reason for the error?
不清楚。
Is it because I am sending too many get requests?
这是一个可能的假设。
How can I limit the request frequency?
一旦您的 for
循环使用 promises 以便请求以串行方式发送而不是并行发送,您可以在每个请求之间插入一个 sleep。
由于错误使用 await
,循环没有等待上一个请求,因此同时触发了 http 请求。适当控制循环会限制请求频率。
for (let i = 1; i <= 300; i++) {
let page= `https://xxxxxxxxx/forum-103-${i}.html`
var arr = await getPage(page);
// use arr in the way you want
console.log(`page ${i}`);
}
export default async function getPage(url) {
// Declare a new promise, wait for the promise to resolve and return its value.
return await new Promise((reso, rej) => {
https.get(url, (res) => {
let html = ""
res.on("data", data => {
html += data
})
res.on("end", () => {
const $ = cheerio.load(html)
let obj = {}
let arr = []
obj = $("#threadlisttableid tbody")
for (let i in obj) {
if (obj[i].attribs?.id?.substr(0, 6) === 'normal') {
arr.push(`https://xxxxxxx/${obj[i].attribs.id.substr(6).split("_").join("-")}-1-1.html`)
}
}
reso(arr) // Resolve with arr
console.log("success!")
})
})
.on('error', (e) => {
console.log(`Got error: ${e.message}`);
throw e;
})
})
}