基于 Crawlee 构建类人行为爬虫框架实战
本文介绍在检索增强生成(RAG)场景下,如何利用 Crawlee 框架构建具备类人行为的爬虫系统。内容涵盖关键概念如 JS 渲染、无头浏览器及代理轮换,并通过掘金前端话题爬取案例,演示了项目初始化、配置管理、路由处理及会话持久化等核心步骤。文章进一步探讨了生产环境下的并发控制、数据存储优化及合规性问题,旨在帮助开发者高效获取高质量知识库数据,提升技术竞争力。

本文介绍在检索增强生成(RAG)场景下,如何利用 Crawlee 框架构建具备类人行为的爬虫系统。内容涵盖关键概念如 JS 渲染、无头浏览器及代理轮换,并通过掘金前端话题爬取案例,演示了项目初始化、配置管理、路由处理及会话持久化等核心步骤。文章进一步探讨了生产环境下的并发控制、数据存储优化及合规性问题,旨在帮助开发者高效获取高质量知识库数据,提升技术竞争力。

随着大规模模型技术的兴起,检索增强生成(RAG)成为构建智能问答、内容生成等应用的关键技术。在 RAG 架构中,知识库内容的丰富程度和相关性直接决定了回答的准确性。而知识库数据的获取途径中,高效、稳定的网络爬虫是重要的组成部分。
对于前端开发者而言,面对动态加载、反爬机制复杂的现代 Web 应用,传统的静态网页爬虫往往力不从心。因此,掌握具备类人行为的爬虫框架技术,不仅是拓展技术视野的需要,也是在智能体时代保持竞争力的关键储备。
在深入爬虫框架之前,理解以下核心概念至关重要:
现代网页大量使用 JavaScript 动态加载内容。传统的 HTTP 请求仅能获取初始 HTML,无法看到脚本执行后的 DOM 结构。爬虫必须具备执行 JavaScript 的能力,以完全渲染页面并提取数据。
无头浏览器是在没有图形用户界面的环境中运行的浏览器实例。它们能够执行 JavaScript,模拟用户的点击、输入和滚动操作。常用的工具包括 Puppeteer 和 Playwright,它们基于 Chrome 或 Firefox 内核,提供了强大的网页自动化能力。
由于内容动态加载,爬虫必须等待特定元素出现后再进行提取。无头浏览器通常提供 waitForSelector 等方法,确保页面完全加载,避免抓取到空白或残缺的数据。
为了防止被目标网站封禁,爬虫通常通过代理服务器隐藏真实 IP。通过轮换多个代理 IP,可以模拟不同的访问来源,绕过地理限制并降低被封禁的风险。
Crawlee 是一个高效的网页爬虫和抓取工具,旨在帮助开发者快速构建可靠的爬虫系统。它兼具 HTTP 请求和无头浏览器的爬取能力,适用于各种动态和静态网页内容的抓取,支持 Node.js 和 Python 版本。
与其他框架对比:
本案例挑战在有限时间内完成特定平台的内容爬取与结构化存储。
使用官方模板或手动创建项目目录。安装必要的依赖包:
npm init -y
npm install --save crawlee cheerio puppeteer
Crawlee 提供三个核心类供选择:
CheerioCrawler:针对普通 HTTP 爬取,速度快但不支持 JS 渲染。PuppeteerCrawler:基于 Google 开源的 Puppeteer,控制 Chrome/Firefox。PlaywrightCrawler:基于 Microsoft 开源的 Playwright,支持多浏览器内核。本例选用 PuppeteerCrawler。
为了增加灵活性,将 URL 和选择器配置独立出来。
// config.mjs
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',
},
}
]
定义入口文件 main.mjs,初始化爬虫实例并添加请求队列。
// 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 包含列表页和详情页处理:
// 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, ));
newHeight = page.();
(previousHeight === newHeight) {
reachedEnd = ;
}
count++;
}
};
(page);
page.(item..);
({
: item..,
: ,
});
});
router.(, ({ request, page, log }) => {
page.();
log.();
page.(item..);
details = page.( {
{
url,
: .(item..)?. || ,
: .(item..)?. || ,
: .(item..)?. || ,
: .(item..)?. || ,
: .(item..)?. || ,
: .(item..)?. || ,
: .(item..)?. || ,
};
}, request., item);
dataset.(details);
});
});
router.( ({ request, log }) => {
log.();
});
运行命令 npm start 即可启动爬虫。控制台日志会显示请求状态、错误信息及进度。
在高并发场景下,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();
}
},
});
在实际落地时,除了基础功能,还需考虑以下方面以提升系统的健壮性。
虽然 Crawlee 支持高并发,但过度请求容易触发反爬。建议根据目标网站的承受能力调整 maxConcurrency 和 maxRequestsPerMinute。对于敏感站点,可设置随机延迟,模拟人类阅读速度。
默认情况下,Crawlee 将数据存储为 JSON 文件。对于海量数据,建议接入数据库(如 MongoDB 或 PostgreSQL)。可以通过自定义 Dataset 实现数据导出,或使用 KeyValueStore 存储中间状态。
爬虫运行时间可能较长,需防止进程意外退出导致任务丢失。Crawlee 的持久化队列会自动保存进度。此外,应配置外部监控告警,当失败率超过阈值时及时通知运维人员。
在爬取数据前,务必检查目标网站的 robots.txt 协议及用户服务条款。尊重版权,避免抓取个人隐私信息。合理设置请求频率,避免对目标服务器造成过大压力。
本文详细介绍了如何利用 Crawlee 框架构建具备类人行为的爬虫系统。从 RAG 应用场景出发,讲解了无头浏览器、JS 渲染、代理轮换等关键技术点,并通过掘金案例演示了完整的开发流程。结合生产环境的最佳实践,开发者可以构建出高效、稳定且合规的数据采集方案,为大模型知识库的构建提供坚实的数据支撑。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online