You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Crawlee的异步爬虫存在用户数据交叉污染问题求助

问题描述

使用Crawlee的PlaywrightCrawler编写多用户爬虫程序,支持用户上传网站链接并爬取该链接下的所有内部链接,但并发运行多个用户的爬取任务时,不同用户的爬取数据会出现共享,爬取链路发生混合。

问题根源
  1. 全局Dataset共享:Crawlee默认的Dataset是全局单例对象,多个Crawler实例调用context.push_data()时,所有数据会写入同一个全局Dataset,导致不同用户的爬取数据混杂。
  2. 队列隔离隐患:虽然每个PlaywrightCrawler默认会创建独立的内存RequestQueue,但未显式配置的情况下,复杂场景中可能出现意外的队列共享问题。
解决方案

为每个用户的爬取任务配置完全独立的资源,彻底隔离不同用户的爬取链路和数据:

  • 为每个用户创建唯一命名的Dataset,确保数据单独存储。
  • 显式创建专属的RequestQueue,避免不同用户的爬取请求队列混合。
  • 保留局部的crawled_data列表,确保每个用户的爬取结果单独归集。
修改后的完整代码
import asyncio
from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext
from crawlee import EnqueueStrategy, Dataset, RequestQueue

async def run_crawler(username, urls) -> list:
    # 为每个用户创建独立的请求队列和数据集
    request_queue = await RequestQueue.open(f'queue-{username}')
    dataset = await Dataset.open(f'dataset-{username}')

    crawler = PlaywrightCrawler(
        max_requests_per_crawl=10,
        retry_on_blocked=True,
        max_request_retries=5,
        request_queue=request_queue,
        dataset=dataset,
    )

    crawled_data = []

    @crawler.router.default_handler
    async def request_handler(context: PlaywrightCrawlingContext) -> None:
        context.log.info(f'Processing {context.request.url} ...')

        # 提取页面文本内容
        try:
            text_content = await context.page.evaluate("document.querySelector('main').innerText")
        except:
            text_content = await context.page.evaluate("document.body.innerText")

        data = {
            'username': username,
            'url': context.request.url,
            'title': await context.page.title(),
            "context": text_content,
        }
        
        # 将数据推送到当前用户的专属数据集
        await context.push_data(data)
        crawled_data.append(data)

        # 仅将当前域名的内部链接加入当前用户的请求队列
        await context.enqueue_links(
            strategy=EnqueueStrategy.SAME_DOMAIN,
        )

    await crawler.run(urls)
    # 导出当前用户的专属数据集到本地文件
    await dataset.export_to_json(f'data/{username}_results.json')

    return crawled_data


async def run_multiple_crawlers(user_requests):
    tasks = [run_crawler(username, urls) for username, urls in user_requests]
    # 并发执行所有用户的爬取任务
    results = await asyncio.gather(*tasks)
    return results

# 示例:多用户爬取请求列表
user_requests = [
    ('user1', ['https://github.com']),  # 修正原代码中URL的标点错误
    ('user2', ['https://stackoverflow.com']),
]

asyncio.run(run_multiple_crawlers(user_requests))
关键修改点说明
  • 独立请求队列:通过RequestQueue.open(f'queue-{username}')为每个用户创建唯一标识的请求队列,彻底隔离不同用户的爬取链路。
  • 专属数据集:用Dataset.open(f'dataset-{username}')创建用户专属数据集,确保push_data()操作仅写入当前用户的爬取数据,避免全局共享。
  • URL错误修正:修正原示例中https://github,com的标点错误,改为正确的https://github.com。

内容的提问来源于stack exchange,提问作者Yusif Abasov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:32:15