跳到主要内容基于 Crawlee 构建类人行为爬虫框架实战 | 极客日志JavaScriptNode.jsAI大前端
基于 Crawlee 构建类人行为爬虫框架实战
综述由AI生成介绍在检索增强生成(RAG)场景下,如何利用 Crawlee 框架构建具备类人行为的爬虫系统。内容涵盖关键概念如 JS 渲染、无头浏览器及代理轮换,并通过掘金前端话题爬取案例,演示了项目初始化、配置管理、路由处理及会话持久化等核心步骤。文章进一步探讨了生产环境下的并发控制、数据存储优化及合规性问题,旨在帮助开发者高效获取高质量知识库数据,提升技术竞争力。
魔尊20 浏览 引言
随着大规模模型技术的兴起,检索增强生成(RAG)成为构建智能问答、内容生成等应用的关键技术。在 RAG 架构中,知识库内容的丰富程度和相关性直接决定了回答的准确性。而知识库数据的获取途径中,高效、稳定的网络爬虫是重要的组成部分。
对于前端开发者而言,面对动态加载、反爬机制复杂的现代 Web 应用,传统的静态网页爬虫往往力不从心。因此,掌握具备类人行为的爬虫框架技术,不仅是拓展技术视野的需要,也是在智能体时代保持竞争力的关键储备。
关键概念解析
在深入爬虫框架之前,理解以下核心概念至关重要:
1. JS 渲染(JavaScript Rendering)
现代网页大量使用 JavaScript 动态加载内容。传统的 HTTP 请求仅能获取初始 HTML,无法看到脚本执行后的 DOM 结构。爬虫必须具备执行 JavaScript 的能力,以完全渲染页面并提取数据。
2. 无头浏览器(Headless Browsers)
无头浏览器是在没有图形用户界面的环境中运行的浏览器实例。它们能够执行 JavaScript,模拟用户的点击、输入和滚动操作。常用的工具包括 Puppeteer 和 Playwright,它们基于 Chrome 或 Firefox 内核,提供了强大的网页自动化能力。
3. 等待元素渲染(Waiting for Elements to Render)
由于内容动态加载,爬虫必须等待特定元素出现后再进行提取。无头浏览器通常提供 waitForSelector 等方法,确保页面完全加载,避免抓取到空白或残缺的数据。
4. 代理服务器与 IP 轮换(Proxy Server & Rotation)
为了防止被目标网站封禁,爬虫通常通过代理服务器隐藏真实 IP。通过轮换多个代理 IP,可以模拟不同的访问来源,绕过地理限制并降低被封禁的风险。
Crawlee 框架介绍
Crawlee 是一个高效的网页爬虫和抓取工具,旨在帮助开发者快速构建可靠的爬虫系统。它兼具 HTTP 请求和无头浏览器的爬取能力,适用于各种动态和静态网页内容的抓取,支持 Node.js 和 Python 版本。
主要功能
- HTTP 和无头浏览器爬取:统一接口处理传统 HTTP 请求和现代无头浏览器(如 Playwright 和 Puppeteer),可抓取动态生成的内容。
- 持久化队列:自动管理和持久化 URL 队列,支持广度优先和深度优先策略,确保高效和可靠的抓取过程。
- 自动扩展:支持根据需求动态调整爬取规模,提高抓取效率。
- 代理轮换:内置代理轮换功能,避免 IP 被封,提高爬取的稳定性。
- 生命周期管理:提供灵活的生命周期管理,允许自定义爬虫的各个阶段。
- 错误处理和重试机制:自动处理爬取过程中遇到的错误,并进行重试,确保数据完整性。
优势分析
- 单一接口:统一的 API 简化开发过程,减少学习成本。
- JavaScript 渲染支持:通过无头浏览器渲染页面,抓取结果更完整。
- 丰富的配置选项:支持 HTTP/2、浏览器指纹等高级配置,适应不同需求。
- TypeScript 编写:利用强类型检查提高代码质量和开发效率。
- 内置解析器:集成 Cheerio 和 JSDOM 等快速 HTML 解析器。
- CLI 和 Docker 支持:方便集成和部署。
与其他框架对比:
- Scrapy:擅长传统 HTTP 爬取,但对动态内容支持较弱。
- BeautifulSoup:主要用于 HTML 解析,缺乏自动扩展和代理轮换功能。
- Selenium:可抓取动态内容,但缺少持久化队列和自动扩展,性能相对较低。
Crawlee 在这些方面提供了更高效和集成的解决方案。
实战案例:掘金前端话题爬取
本案例挑战在有限时间内完成特定平台的内容爬取与结构化存储。
1. 初始化项目
使用官方模板或手动创建项目目录。安装必要的依赖包:
npm init -y
npm install --save crawlee cheerio puppeteer
CheerioCrawler:针对普通 HTTP 爬取,速度快但不支持 JS 渲染。
PuppeteerCrawler:基于 Google 开源的 Puppeteer,控制 Chrome/Firefox。
PlaywrightCrawler:基于 Microsoft 开源的 Playwright,支持多浏览器内核。
2. 配置文件设计
为了增加灵活性,将 URL 和选择器配置独立出来。
export default [
{
label: 'juejin',
url: 'https://juejin.cn/frontend',
selector: {
detail: '.entry-list .title-row a',
title: 'h1.article-title',
author: '.author-info-box .author-name a span',
modifiedDate: '.author-info-box .meta-box time',
hit: '.author-info-box .meta-box .views-count',
readTime: '.author-info-box .meta-box .read-time',
description: '.article-header p',
content: '.article-viewer',
},
}
]
3. 路由与处理逻辑
定义入口文件 main.mjs,初始化爬虫实例并添加请求队列。
import { PuppeteerCrawler, log } from 'crawlee';
import { router } from './routes.mjs';
import config from './config.mjs';
log.setLevel(log.LEVELS.DEBUG);
const crawler = new PuppeteerCrawler({
maxConcurrency: 10,
maxRequestsPerMinute: 20,
launchContext: {
launchOptions: {
headless: true,
},
},
maxRequestsPerCrawl: 1000,
requestHandler: router,
failedRequestHandler({ request, log }) {
log.error(`Request ${request.url} failed too many times.`);
},
});
await crawler.addRequests(config.map(item => ({ url: item.url, label: item.label })));
await crawler.run();
核心路由逻辑 routes.mjs 包含列表页和详情页处理:
import { createPuppeteerRouter, Dataset } from 'crawlee';
import config from './config.mjs';
export const router = createPuppeteerRouter();
config.forEach(async item => {
const dataset = await Dataset.open(item.label);
router.addHandler(`${item.label}`, async ({ request, page, enqueueLinks, log }) => {
page.setDefaultTimeout(5000);
log.debug(`Enqueueing pagination: ${request.url}`);
const scrollToBottom = async (page) => {
let previousHeight;
let newHeight;
let reachedEnd = false;
let count = 0;
while (!reachedEnd && count < 2) {
previousHeight = await page.evaluate('document.body.scrollHeight');
await page.evaluate('window.scrollBy(0, document.body.scrollHeight)');
await new Promise(resolve => setTimeout(resolve, 3000));
newHeight = await page.evaluate('document.body.scrollHeight');
if (previousHeight === newHeight) {
reachedEnd = true;
}
count++;
}
};
await scrollToBottom(page);
await page.waitForSelector(item.selector.detail);
await enqueueLinks({
selector: item.selector.detail,
label: `${item.label}-DETAIL`,
});
});
router.addHandler(`${item.label}-DETAIL`, async ({ request, page, log }) => {
page.setDefaultTimeout(5000);
log.debug(`Extracting data: ${request.url}`);
await page.waitForSelector(item.selector.content);
const details = await page.evaluate((url, item) => {
return {
url,
title: document.querySelector(item.selector.title)?.innerText || '',
author: document.querySelector(item.selector.author)?.innerText || '',
modifiedDate: document.querySelector(item.selector.modifiedDate)?.innerText || '',
hit: document.querySelector(item.selector.hit)?.innerText || '',
readTime: document.querySelector(item.selector.readTime)?.innerText || '',
description: document.querySelector(item.selector.description)?.innerText || '',
content: document.querySelector(item.selector.content)?.innerText || '',
};
}, request.url, item);
await dataset.pushData(details);
});
});
router.addDefaultHandler(async ({ request, log }) => {
log.warn(`Unhandled request: ${request.url}`);
});
4. 启动与监控
运行命令 npm start 即可启动爬虫。控制台日志会显示请求状态、错误信息及进度。
进阶:代理与 Session 管理
在高并发场景下,IP 封禁风险显著增加。引入代理服务和会话管理是保障稳定性的关键。
代理配置
import { ProxyConfiguration } from 'crawlee';
const proxyConfiguration = new ProxyConfiguration({
proxyUrls: ['http://proxy-1.com', 'http://proxy-2.com'],
});
const crawler = new PuppeteerCrawler({
proxyConfiguration,
async requestHandler({ proxyInfo }) {
console.log('Current Proxy:', proxyInfo.proxyUrl);
},
});
会话池管理
使用 Session 池可以过滤失效代理,自动标记坏节点。
const crawler = new PuppeteerCrawler({
proxyConfiguration,
useSessionPool: true,
sessionPoolOptions: { maxPoolSize: 100 },
persistCookiesPerSession: true,
async requestHandler({ page, session }) {
const title = await page.title();
if (title === 'Blocked') {
session.retire();
} else if (title.includes('Connection Error')) {
session.markBad();
}
},
});
生产环境最佳实践
在实际落地时,除了基础功能,还需考虑以下方面以提升系统的健壮性。
1. 并发控制与限速
虽然 Crawlee 支持高并发,但过度请求容易触发反爬。建议根据目标网站的承受能力调整 maxConcurrency 和 maxRequestsPerMinute。对于敏感站点,可设置随机延迟,模拟人类阅读速度。
2. 数据存储优化
默认情况下,Crawlee 将数据存储为 JSON 文件。对于海量数据,建议接入数据库(如 MongoDB 或 PostgreSQL)。可以通过自定义 Dataset 实现数据导出,或使用 KeyValueStore 存储中间状态。
3. 异常恢复机制
爬虫运行时间可能较长,需防止进程意外退出导致任务丢失。Crawlee 的持久化队列会自动保存进度。此外,应配置外部监控告警,当失败率超过阈值时及时通知运维人员。
4. 合规性与道德规范
在爬取数据前,务必检查目标网站的 robots.txt 协议及用户服务条款。尊重版权,避免抓取个人隐私信息。合理设置请求频率,避免对目标服务器造成过大压力。
总结
本文详细介绍了如何利用 Crawlee 框架构建具备类人行为的爬虫系统。从 RAG 应用场景出发,讲解了无头浏览器、JS 渲染、代理轮换等关键技术点,并通过掘金案例演示了完整的开发流程。结合生产环境的最佳实践,开发者可以构建出高效、稳定且合规的数据采集方案,为大模型知识库的构建提供坚实的数据支撑。
相关免费在线工具
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online