如何构建新闻爬虫:逐步指南
Lead Scraping Automation Engineer
TL;DR:
- 新闻爬虫由两个循环组成:发现,然后获取。 从一个版块的首页提取文章链接,然后访问每个链接并提取标题和正文——保持这两个阶段分开,以便每个阶段都可以单独重新运行、调度和扩展。
- 发现是一个链接过滤问题。 首页主要是导航;文章链接匹配一个可识别的URL格式(
/news/articles/…,以id结尾的slug)。筛选这些链接,而不是抓取每个锚点。 - 提取意味着可读的核心,而不是整个DOM。 阅读
h1和文章段落;跳过导航、相关链接和广告条。段落计数和文本长度可以立即告诉你抓取是否真的得到了故事。 - 新闻网站进行地理路由和速率限制。 固定
proxyCountry并调节爬虫的速度,以便版块扫不至于在中途触发反机器人限制。 - 它运行在Scrapeless Scraping Browser上,使用普通的Puppeteer。 云浏览器渲染基于JS构建的首页并提供住宅出口;你的爬虫代码是普通的导航和提取。
- 免费开始。 新的Scrapeless账户包含免费Scraping Browser运行时——请在app.scrapeless.com注册。
介绍:新闻爬虫实际做什么
新闻爬虫将一个版块的首页转化为一个结构化文章流。它有两个不同的工作。首先,发现:读取首页(或一个版块,或一个网站地图)并收集指向实际故事的链接。其次,获取:访问每个故事并提取标题和可读正文,去掉导航和广告元素。
保持这两个阶段分开是整个技巧。发现每次扫一次,成本低;获取每篇文章执行一次,这里才是真正的工作——也是速率限制风险所在。将它们分开让你可以首先收集一个干净的链接列表,然后以可控的节奏获取,再单独获取一篇文章,而不需重新爬取首页。
本指南在Node上构建爬虫,使用Scrapeless Scraping Browser——一个连接到Puppeteer的反检测云浏览器,过一个标准端点。以下的发现和提取步骤都是针对实时新闻源进行的。仅限公共内容。
你能用它做什么
- 扫一个版块(世界、商业、科技)以获取当天的新文章。
- 提取干净的文章主体——标题加段落——进行分析或阅读流程。
- 用可读文本而不是原始HTML喂养汇总器或RAG存储。
- 通过定期重新运行发现来跟踪特定领域,并只获取新链接。
- 跨来源,将同一个爬虫指向多个媒体。
为什么选择Scrapeless Scraping Browser
Scrapeless Scraping Browser是一个可定制的、反检测的云浏览器,专为网络爬虫和AI代理设计。对于新闻爬虫而言,它带来了:
- 云端JS渲染——现代首页使用JavaScript构建链接列表;云浏览器执行它,因此链接存在。
- 195多个国家的住宅代理——将出口固定到网站服务的地区,避免版块扫触发速率限制。
- 反检测指纹识别——爬虫表现得像真实的浏览器,因此文章页面在长时间运行中保持渲染。
- 标准Puppeteer连接——
Puppeteer.connect()返回一个普通的Browser;发现和提取都是普通的Puppeteer。 - 会话持久性——在整个扫描过程中保持一个会话活跃。
在app.scrapeless.com的免费计划上获取您的API密钥。
前提条件
- Node.js 18或更高版本
- 一个Scrapeless账户和API密钥——请在app.scrapeless.com注册
- 对Puppeteer的基本了解
安装
bash
npm install @scrapeless-ai/sdk puppeteer-core
bash
export SCRAPELESS_API_KEY="your_api_token_here"
第一步 — 连接
javascript
import { Puppeteer } from '@scrapeless-ai/sdk';
const browser = await Puppeteer.connect({
apiKey: process.env.SCRAPELESS_API_KEY,
sessionName: 'news-crawler',
proxyCountry: 'US',
sessionTTL: 300,
});
const page = await browser.newPage();
第二维 — 发现文章链接
加载首页并收集看起来像文章的链接。合适的选择器依赖于网站,但原则在各处都相同:将锚点筛选到指向故事的链接。这里是一个新闻源的首页,获取前几个标题链接:
javascript
await page.goto('https://text.npr.org/', {
waitUntil: 'domcontentloaded',
timeout: 40000,
});
const links = await page.evaluate(() =>
[...document.querySelectorAll('ul li a')]
.map((a) => ({ title: a.textContent.trim(), href: a.href }))
.filter((l) => l.title),
);
zh
console.log(links.length, '链接 —', links[0]);
// 5 链接 — { 标题: '...', href: 'https://text.npr.org/<article-id>' }
对于大多数网站,您需要将过滤器收紧到 URL 形状——例如,路径匹配 /news/articles/ 或以长数字 ID 结尾的链接——以排除导航和部分链接:
javascript
const articleLinks = await page.evaluate(() =>
[...document.querySelectorAll('a[href]')]
.filter((a) => /\/news\/(articles\/|[a-z]+-\d{6,})/.test(a.getAttribute('href') || ''))
.map((a) => a.href),
);
第 3 步 - 获取并提取每篇文章
现在访问每个链接并提取 可读核心——h1 和正文段落。段落数和文本长度是您获取故事而不是重定向或付费墙摘要的快速完整性检查:
javascript
async function fetchArticle(page, url) {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 40000 });
return page.evaluate(() => ({
title: document.querySelector('h1')?.textContent?.trim(),
paragraphs: document.querySelectorAll('p').length,
text: [...document.querySelectorAll('p')].map((p) => p.textContent).join('\n\n'),
}));
}
const article = await fetchArticle(page, links[0].href);
console.log(article.title, '—', article.paragraphs, '段落');
// "美国和伊朗宣布达成结束战争、重新开放霍尔木兹海峡的协议" — 40 段落
该实时运行返回了一篇 40 段的文章(约 5500 个字符的正文文本),来源于标题链接——标题和全文,没有导航元素。
在免费计划中获取您的 API 密钥:app.scrapeless.com
第 4 步 - 组装爬虫
将两个阶段结合起来:一次发现,然后按控制的速度获取每个链接。保持一个 seen 集,以便计划的重新运行只获取新故事:
javascript
const seen = new Set();
const articles = [];
for (const url of articleLinks) {
if (seen.has(url)) continue;
seen.add(url);
try {
articles.push({ url, ...(await fetchArticle(page, url)) });
} catch {
// 跳过无法呈现的文章;继续扫描
}
await new Promise((r) => setTimeout(r, 1000)); // 控制爬虫速度
}
await browser.close();
console.log(articles.length, '文章');
您会得到的结果
每篇文章都是一个平面记录——标题加上可读正文:
json
{
"url": "https://text.npr.org/nx-s1-5858590",
"title": "美国和伊朗宣布达成结束战争、重新开放霍尔木兹海峡的协议",
"paragraphs": 40,
"text": "..."
}
// 说明性示例——标题 + 段落计数是真实捕获;正文文本已省略。
一些诚实的观察:
- 根据网站收紧发现过滤器。 松散的锚定抓取会引入导航和标签;匹配文章 URL 形状。
- 验证获取。 几乎为零的段落计数通常意味着重定向、付费墙或同意墙——在信任记录之前进行检查。
- 在扫描中去重。 首页重新列出相同的故事;针对 URL 进行关键。
- 控制速度。 在抓取之间的延迟和固定的
proxyCountry可以防止部分扫描触发速率限制。
结论:发现、获取、重复
新闻爬虫是两个干净的阶段——从首页发现文章链接,然后获取和提取每个故事的标题和正文。保持它们分开使爬虫能够控制速度、继续运行和易于调度。使用 Scrapeless Scraping Browser 运行,可以呈现基于 JS 的首页,并提供居民出口,防止扫描受到速率限制。关于爬虫的多页面部分,请参阅 分页指南;Scraping Browser 产品页面 和 文档 覆盖了完整的 SDK 表面。收紧发现过滤器,验证每次获取,在扫描中去重,并控制爬虫速度。
准备构建您的 AI 驱动的数据管道吗?
加入我们的社区以申请免费计划,并与构建新闻和内容管道的开发人员进行交流:Discord · Telegram。
在 app.scrapeless.com 注册以获取免费的 Scraping Browser 运行时,并将上述模式适应您工作流程所需的媒体和部分。有关规模的 定价。
FAQ
问:爬取新闻网站合法吗?
收集公开可见的内容通常是允许的,但版权和每个网站的服务条款决定了您可以存储和再发布的内容。爬取公共页面,遵循机器人排除规则和服务条款,并根据您的使用案例咨询法律顾问。
问:我如何从导航中分离文章链接?
根据网站的文章 URL 形式过滤锚点——一个 /news/articles/ 路径或以长 ID 结尾的标识符——而不是抓取页面上的每一个链接。
问:我如何知道文章实际上被获取?
检查段落数量和文本长度。近零的计数表示重定向、付费墙或同意墙,而不是故事。
问:我需要代理吗?
对于持续的抓取,需要——将 proxyCountry 固定为该媒体服务的区域,并调整爬取速度,以免触及速率限制。
问:我如何安排一个周期,只获取新故事?
保持一个持久的 seen URL 集合;在您的时间间隔重新运行发现,仅获取您尚未记录的链接。
问:我可以在没有 AI 代理的情况下运行这个吗?
可以。这仅仅是对 Scrapeless 会话的普通 Puppeteer 处理——不需要代理。
在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。



