首页
/ 零基础精通Crawlee:Node.js网页抓取实战指南

零基础精通Crawlee:Node.js网页抓取实战指南

2026-03-15 03:54:30作者:滕妙奇

你是否曾因网页抓取遇到重重困难?静态网页爬取简单但无法处理动态内容,复杂爬虫又需要处理代理、会话管理等繁琐工作。现在,Crawlee来了!作为专为Node.js设计的网页抓取和浏览器自动化库,它能帮助你快速构建可靠、高效的爬虫项目,轻松应对各种网页抓取挑战。

环境配置避坑指南

系统要求与版本检查

在开始使用Crawlee之前,确保你的开发环境满足以下要求:

node -v  # 需Node.js 16.x或更高版本
npm -v   # 建议npm 7.x以上

如果版本不满足要求,请到Node.js官网下载并安装最新LTS版本。

三种安装方式对比

安装方式 适用场景 命令 优势
CLI工具 全新项目 npx crawlee create my-crawler 自动生成完整项目结构
基础安装 静态网页爬取 npm install crawlee 轻量级,仅包含基础功能
完整安装 动态网页爬取 npm install crawlee playwright 支持浏览器渲染,功能全面

推荐使用CLI工具创建新项目,它会自动配置好目录结构和依赖项:

npx crawlee create my-crawler
cd my-crawler
npm start  # 运行示例爬虫

运行成功后,你将看到示例爬虫已经开始工作,爬取结果会保存在项目的storage目录中。

核心功能解析:解决不同网页抓取难题

静态网页抓取:快速高效的数据提取 ⚡

对于服务器端渲染的静态网页,CheerioCrawler是最佳选择。它基于Cheerio解析HTML,速度快且资源占用低:

import { CheerioCrawler } from 'crawlee';

// 创建爬虫实例
const crawler = new CheerioCrawler({
    // 每个请求的处理函数
    async requestHandler({ $, request }) {
        // 使用类似jQuery的语法提取数据
        const title = $('title').text();
        const headings = [];
        $('h1, h2, h3').each((i, el) => {
            headings.push($(el).text());
        });
        
        console.log(`成功抓取: ${title}`);
        
        // 保存数据
        await Dataset.pushData({
            url: request.url,
            title,
            headings,
            timestamp: new Date().toISOString()
        });
    }
});

// 启动爬虫
await crawler.run(['https://example.com']);

动态网页抓取:处理JavaScript渲染内容 🚀

现代网站大量使用JavaScript动态加载内容,这时需要使用PlaywrightCrawler或PuppeteerCrawler:

import { PlaywrightCrawler } from 'crawlee';

const crawler = new PlaywrightCrawler({
    // 显示浏览器窗口,方便调试
    headless: false,
    async requestHandler({ page, request }) {
        // 等待页面加载完成
        await page.waitForLoadState('networkidle');
        
        // 提取动态生成的内容
        const productTitles = await page.$$eval('.product-title', elements => 
            elements.map(el => el.textContent.trim())
        );
        
        console.log(`在${request.url}找到${productTitles.length}个产品`);
        
        // 保存数据
        await Dataset.pushData({
            url: request.url,
            products: productTitles,
            count: productTitles.length
        });
    }
});

await crawler.run(['https://example.com/products']);

智能链接发现:整站爬取自动化

Crawlee的enqueueLinks功能可以自动发现并添加新的URL,实现整站爬取:

// 在requestHandler中添加
await enqueueLinks({
    // 只抓取特定选择器的链接
    selector: 'a.product-link',
    // 过滤URL,只保留同一域名下的链接
    filter: ({ url }) => url.hostname === 'example.com',
    // 为新请求添加额外元数据
    requestTemplate: {
        userData: {
            label: 'product'
        }
    }
});

渐进式实战案例:从单页抓取到整站爬虫

基础:单页数据提取

让我们从一个简单的单页抓取开始,提取网页标题和元描述:

import { CheerioCrawler, Dataset } from 'crawlee';

// 创建爬虫
const crawler = new CheerioCrawler({
    async requestHandler({ $, request }) {
        // 提取数据
        const data = {
            url: request.url,
            title: $('title').text(),
            metaDescription: $('meta[name="description"]').attr('content') || '无描述',
            timestamp: new Date().toISOString()
        };
        
        // 输出结果
        console.log(`抓取: ${data.title}`);
        
        // 保存到数据集
        await Dataset.pushData(data);
    }
});

// 启动爬虫
await crawler.run(['https://crawlee.dev']);

运行后,查看storage/datasets/default目录下的JSON文件,你将看到抓取到的数据。

进阶:整站内容爬取

接下来,我们构建一个能够爬取整个网站的爬虫,自动发现并访问新页面:

import { PlaywrightCrawler, Dataset } from 'crawlee';

// 定义要排除的URL模式
const EXCLUDE_PATTERNS = [/logout/, /admin/, /cart/];

const crawler = new PlaywrightCrawler({
    // 浏览器配置
    headless: true,
    // 并发控制
    maxConcurrency: 2,
    // 请求处理函数
    async requestHandler({ page, enqueueLinks, request }) {
        console.log(`正在处理: ${request.url}`);
        
        // 提取页面信息
        const title = await page.title();
        const h1 = await page.$eval('h1', el => el?.textContent || '无H1标题');
        
        // 保存数据
        await Dataset.pushData({
            url: request.url,
            title,
            h1,
            depth: request.userData.depth || 0,
            timestamp: new Date().toISOString()
        });
        
        // 发现并添加新链接
        await enqueueLinks({
            selector: 'a',
            filter: ({ url }) => {
                // 排除不需要的链接
                return !EXCLUDE_PATTERNS.some(pattern => pattern.test(url.href));
            },
            requestTemplate: {
                userData: {
                    depth: (request.userData.depth || 0) + 1
                }
            },
            // 限制爬取深度
            maxDepth: 3
        });
    }
});

// 启动爬虫,从首页开始
await crawler.run(['https://example.com']);

运行后,爬虫将从起始URL开始,自动发现并爬取最多3层深度的链接,所有数据会保存在数据集中。

高级:反屏蔽策略配置

许多网站会阻止频繁的爬虫请求,Crawlee内置了强大的反屏蔽机制:

import { PlaywrightCrawler } from 'crawlee';

const crawler = new PlaywrightCrawler({
    // 启用会话池管理
    useSessionPool: true,
    sessionPoolOptions: {
        // 每个会话最多使用5次
        sessionOptions: { maxUsageCount: 5 },
        // 会话过期时间
        sessionExpirySecs: 300
    },
    // 配置代理(如果有)
    proxyConfiguration: {
        proxyUrls: [
            'http://proxy1:port',
            'http://proxy2:port'
        ]
    },
    // 请求延迟
    minConcurrency: 1,
    maxConcurrency: 3,
    // 随机延迟
    requestHandlerTimeoutSecs: 30,
    // 重试失败请求
    maxRequestRetries: 3,
    // 指数退避重试
    retryPolicy: {
        backoffStrategy: 'exponential',
        initialDelaySecs: 1
    },
    
    async requestHandler({ page, request }) {
        // 页面处理逻辑
        console.log(`使用会话${request.sessionId}访问: ${request.url}`);
        // ...
    }
});

await crawler.run(['https://target-website.com']);

Crawlee会话池工作原理

常见问题解决方案(Q&A)

Q: 爬虫运行时提示"内存不足"怎么办?

A: 可以通过以下方式解决:

  1. 降低并发数:maxConcurrency: 2
  2. 启用自动扩展:autoscaledPoolOptions: { maxConcurrency: 5 }
  3. 增加内存限制:node --max-old-space-size=4096 src/main.js

Q: 如何处理需要登录的网站?

A: 使用页面交互功能实现登录:

async requestHandler({ page }) {
    // 检查是否需要登录
    if (await page.$('#login-form')) {
        // 输入用户名密码
        await page.fill('#username', 'your-username');
        await page.fill('#password', 'your-password');
        // 提交表单
        await page.click('#submit-button');
        // 等待登录完成
        await page.waitForNavigation();
    }
    // 登录后的处理...
}

Q: 如何存储和导出抓取的数据?

A: Crawlee提供多种数据存储方式:

// 导出为CSV
await Dataset.exportToCSV('results');
// 导出为JSON
await Dataset.exportToJSON('results');
// 直接访问数据记录
const dataset = await Dataset.open();
for await (const item of dataset) {
    console.log(item);
}

抓取结果示例

扩展资源导航

官方文档与示例

  • 快速入门指南:[docs/quick-start/index.mdx]
  • 完整API参考:[packages/core/src/index.ts]
  • 示例代码库:[docs/examples/]

进阶学习路径

  1. 基础:掌握三种核心爬虫类型的使用
  2. 中级:实现反屏蔽策略和会话管理
  3. 高级:分布式爬取和云平台部署
  4. 专家:自定义爬虫逻辑和插件开发

社区资源

  • GitHub仓库:通过git clone https://gitcode.com/GitHub_Trending/cr/crawlee获取完整源码
  • 问题讨论:项目GitHub Issues页面
  • 教程合集:[docs/guides/]目录下的各类专题指南

Crawlee作为Node.js生态中强大的网页抓取工具,不仅简化了爬虫开发流程,还提供了企业级的稳定性和性能优化。无论你是需要快速获取少量数据,还是构建大规模的网页抓取系统,Crawlee都能满足你的需求。现在就动手创建你的第一个Crawlee项目,开启高效网页抓取之旅吧!

登录后查看全文
热门项目推荐
相关项目推荐