NestJS实现新闻爬虫时出现getaddrinfo ENOTFOUND错误如何解决?
报错排查与解决步骤
getaddrinfo ENOTFOUND 错误本质是运行服务的机器无法把目标域名解析为对应IP地址,按优先级排查即可:
1. 基础网络连通性排查
- 登录部署NestJS的服务器,执行
ping livennov.ru,如果请求超时说明服务器网络限制无法访问目标站点 - 执行
nslookup livennov.ru测试DNS解析是否正常,如果没有返回对应IP,可更换公共DNS(114.114.114.114/8.8.8.8)后重试 - 检查服务器出口防火墙、安全组规则,是否禁止访问境外站点,若有封禁规则可配置HTTP代理解决访问限制
2. 代码问题修复
你提供的代码本身存在多个会触发未捕获Promise异常的逻辑漏洞,修复后的完整代码如下:
import { Injectable } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { InjectRepository } from '@nestjs/typeorm'; import { TypeOrmCrudService } from '@nestjsx/crud-typeorm'; import { News } from './entity/news.entity'; import axios from 'axios'; import * as cheerio from 'cheerio'; @Injectable() export class NewsService extends TypeOrmCrudService<News> { constructor(@InjectRepository(News) private readonly newsRepository) { super(newsRepository); } async fillNewsArray(): Promise<News[]> { const newsArray: News[] = []; // 初始化数组避免push报错 // 封装请求方法加超时和异常捕获 const getHTML = async (url) => { try { const { data } = await axios.get(url, { timeout: 10000 }); return cheerio.load(data); } catch (err) { console.error(`请求${url}失败:`, err.message); throw err; } }; try { const selector = await getHTML('https://livennov.ru/news/?PAGEN_2=1'); const elements = selector('div.b-section-item__body').toArray(); // 替换each+async的错误写法,用串行循环控制请求频率避免被封IP for (const element of elements) { const object = new News(); // 初始化实体类避免属性赋值报错 const title = selector(element).find('h3.b-section-item__title').text().trim(); const date = selector(element).find('div.b-meta-item').text().trim(); const relativeUrl = selector(element).find('a').attr('href'); if (!relativeUrl) continue; // 跳过无效数据 const url = `https://livennov.ru${relativeUrl}`; const descSelector = await getHTML(url); descSelector('h2').remove(); const imgRelativePath = descSelector('.content-full-width').find('img').attr('data-src'); const imgUrl = imgRelativePath ? `https://livennov.ru${imgRelativePath}` : ''; const descr = descSelector('div.b-news-detail-body').text().trim(); object.headline = title; object.description = descr; object.imageUrl = imgUrl; object.originalUrl = url; object.dateTime = date; object.type = 'sports'; newsArray.push(object); // 请求间隔1秒避免触发反爬 await new Promise(resolve => setTimeout(resolve, 1000)); } // 批量入库 await this.newsRepository.save(newsArray); return newsArray; } catch (err) { console.error('爬虫执行失败:', err.message); throw err; } } // 调整为10分钟爬一次,10秒请求频率过高容易被封IP @Cron(CronExpression.EVERY_10_MINUTES) async handleCron() { // 捕获定时任务异常避免进程崩溃 await this.fillNewsArray().catch(err => console.error('定时任务执行失败:', err)); } }
3. 特殊场景兜底
如果确认网络正常但仍存在解析失败问题,可给axios配置代理参数:
await axios.get(url, { timeout: 10000, proxy: { host: '代理IP地址', port: 代理端口 } })
Node版本低于18的环境可额外安装dnscache依赖开启全局DNS缓存,减少重复解析失败概率。
内容的提问来源于stack exchange,提问作者brothergod1
相关产品推荐
相关产品推荐

