Nodejs 采集的时候遇到socket hang up了
Nodejs 采集的时候遇到socket hang up了
正在学习express框架做个简单的小网站,临时数据想从网站上抓,所以就用needle 和cheerio做采集,每次采集的颗粒是https://ruby-china.org/topics?page=<page_index>。每一页有15条数据。采集的是[title,content, url, tag, author, author_thumb]. 处于简单考虑把index做成数组。然后forEach. 起初开始一次抓5页,没问题,10页也没问题,后来直接跳到一次抓30页,然后问题就出现了,socet hang up。这个socket hang up是怎么来的?log了一下hang out时的url,浏览器是可以浏览的啊。做采集应该考虑些啥东东,貌似前几天抓糗白一次都是35页,而且都是20条数据。也没出现过问题啊。前辈给指点指点呗。谢了先。。。。
Node.js 采集时遇到 socket hang up
你在使用 Node.js 进行网页数据采集时遇到了 socket hang up
的错误。这个问题通常发生在长时间运行的请求或服务器没有正确响应的情况下。让我们一起来看看可能的原因以及如何解决。
原因分析
socket hang up
错误通常是由于网络连接中断或服务器响应超时导致的。这可能是由于以下几个原因:
- 请求超时:服务器可能因为请求处理时间过长而关闭了连接。
- 并发请求过多:一次性发起太多请求可能会导致服务器或客户端资源耗尽。
- 服务器限制:某些服务器对请求频率有限制,频繁请求可能会被封禁。
解决方案
- 增加超时时间:你可以通过配置请求库来增加请求的超时时间。
- 限制并发请求:使用队列或异步处理来控制并发请求的数量。
- 重试机制:对于失败的请求,可以实现重试机制。
示例代码
以下是一个使用 needle
和 cheerio
进行数据采集的示例代码,包括超时设置和并发控制。
const needle = require('needle');
const cheerio = require('cheerio');
const axios = require('axios');
const url = 'https://ruby-china.org/topics?page=';
async function fetchData(page) {
try {
const response = await axios.get(url + page, {
timeout: 10000 // 设置超时时间为10秒
});
const $ = cheerio.load(response.data);
// 提取数据
const items = [];
$('.topic').each((index, element) => {
const title = $(element).find('.title').text();
const content = $(element).find('.content').text();
const url = $(element).find('.title a').attr('href');
const tag = $(element).find('.tag').text();
const author = $(element).find('.author').text();
const authorThumb = $(element).find('.author-thumb img').attr('src');
items.push({
title,
content,
url,
tag,
author,
authorThumb
});
});
return items;
} catch (error) {
console.error(`Error fetching data from page ${page}:`, error.message);
throw error;
}
}
async function main() {
const pages = [1, 2, 3, 4, 5]; // 你可以根据需要调整页面范围
let allData = [];
for (const page of pages) {
const data = await fetchData(page);
allData = allData.concat(data);
}
console.log(allData);
}
main().catch(console.error);
关键点解释
- 超时设置:通过
axios.get
方法的timeout
参数设置请求超时时间。 - 并发控制:通过
for
循环逐个处理每个页面,避免同时发起大量请求。 - 错误处理:使用
try...catch
捕获并处理请求失败的情况。
希望这些信息能帮助你解决问题!
之前遇到过socket hang up的问题,记得大概是有地方没有res.end()导致的,不晓得会不会对你有帮助
socket hang up 这个错误是非常神秘的。
有一次我调试到了 socket 模块里面去,然后发现是 nodejs 标准库有问题,但是我没有调试出来。我那问题是超时导致的。
那是网站的防抓取生效了吧,限制了最大连接数,连接进入某个队列不处理了
我也遇到了这个问题,我是一个node server里有API,可以往数据库里写数据。 然后另外写了一个脚本去CALL API,for循环连着call了1000次,就报错 socket hang up了……然后网上找了很久也没找到解决方法,请问这个到底是什么问题呢
同一楼回复,我有次发现用mongodb忘记关闭连接了。。。
控制下并发速度
socket hang up
错误通常表示客户端与服务器之间的连接在请求完成之前被断开。这可能是由于网络问题、服务器超时设置、或请求过于频繁导致服务器拒绝进一步的连接。
解释
当你一次性请求大量页面(如一次抓取30页),可能会因为以下原因导致 socket hang up
:
- 服务器限制:服务器可能限制了短时间内连续的请求次数。
- 超时时间:如果请求耗时过长,超过了默认的超时时间,也会触发该错误。
- 资源限制:频繁的请求可能会导致本地资源(如文件描述符)耗尽。
解决方法
你可以通过以下方式来优化你的采集脚本:
-
增加超时时间: 通过设置更大的超时时间来防止因为请求耗时过长而引发的错误。
-
限制并发请求: 使用
async/await
结合Promise.all
或者使用队列机制来控制同时发起的请求数量。 -
添加重试机制: 当请求失败时,可以自动重试以应对临时的网络波动。
-
限制请求频率: 在请求之间添加延时,避免对服务器造成过大压力。
示例代码
const needle = require('needle');
const cheerio = require('cheerio');
const async = require('async');
const urls = [];
for (let i = 1; i <= 30; i++) {
urls.push(`https://ruby-china.org/topics?page=${i}`);
}
async.eachLimit(urls, 5, async (url) => {
try {
const response = await needle('get', url, { timeout: 10000 });
if (response.statusCode === 200) {
const $ = cheerio.load(response.body);
// 解析数据
const title = $('div.title').text();
const content = $('div.content').text();
const author = $('div.author').text();
const author_thumb = $('img.author-thumb').attr('src');
const tag = $('span.tag').text();
console.log({ title, content, url, tag, author, author_thumb });
} else {
console.error(`Failed to fetch ${url}: Status code ${response.statusCode}`);
}
} catch (error) {
console.error(`Error fetching ${url}:`, error.message);
}
}, (err) => {
if (err) {
console.error('Processing failed:', err.message);
} else {
console.log('All pages processed successfully.');
}
});
在这个例子中,我们使用了 async.eachLimit
来限制并发请求的数量为5,同时设置了10秒的请求超时时间,并加入了简单的错误处理逻辑。这样可以有效地减少 socket hang up
的发生。