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

如何通过Scrapy Middlewares阻止重复请求已爬取过的页面?

实现思路与代码示例

要实现在发送请求前阻止已爬取URL的请求,你需要使用Scrapy的Downloader Middleware,并在process_request方法中处理——这个方法会在请求发送前触发,正好匹配你的需求。

步骤1:存储已爬取URL

建议用一个文本文件(比如visited_urls.txt)记录所有已爬取的赛事URL,每行一个URL。如果你的CSV里已经存储了赛事URL,也可以从CSV中提取并初始化这个列表。

步骤2:编写Downloader Middleware

在项目的middlewares.py中添加以下代码:

from scrapy.exceptions import IgnoreRequest
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse

def normalize_url(url):
    """标准化URL,避免因参数顺序不同误判为新URL"""
    parsed = urlparse(url)
    query_params = parse_qs(parsed.query)
    # 按参数名排序,生成统一格式的查询字符串
    sorted_query = urlencode(sorted(query_params.items()), doseq=True)
    return urlunparse(parsed._replace(query=sorted_query))

class FilterVisitedURLsMiddleware:
    def __init__(self):
        # 初始化已爬URL集合(用set提升查找效率)
        self.visited_urls = set()
        # 从文件加载已爬URL
        try:
            with open('visited_urls.txt', 'r', encoding='utf-8') as f:
                for line in f:
                    url = line.strip()
                    if url:
                        self.visited_urls.add(normalize_url(url))
        except FileNotFoundError:
            # 首次运行文件不存在,跳过加载
            pass

    def process_request(self, request, spider):
        # 标准化当前请求的URL
        normalized_req_url = normalize_url(request.url)
        # 检查是否已爬取,是则忽略请求
        if normalized_req_url in self.visited_urls:
            raise IgnoreRequest(f"跳过已爬URL: {request.url}")
        # 未爬取则继续处理
        return None

    def process_response(self, request, response, spider):
        # 请求成功后,将标准化后的URL写入文件
        normalized_req_url = normalize_url(request.url)
        if normalized_req_url not in self.visited_urls:
            self.visited_urls.add(normalized_req_url)
            with open('visited_urls.txt', 'a', encoding='utf-8') as f:
                f.write(normalized_req_url + '\n')
        return response

步骤3:启用中间件

在项目的settings.py中配置DOWNLOADER_MIDDLEWARES,添加你编写的中间件:

DOWNLOADER_MIDDLEWARES = {
    # 替换成你的项目名,比如my_spider.middlewares...
    'your_project_name.middlewares.FilterVisitedURLsMiddleware': 543,
    # 保留其他默认中间件配置(如果有)
}

优先级数字越小,中间件越先执行。设置为543是为了让它在大部分默认中间件之后、下载操作之前执行。

注意事项

  • 如果要从CSV提取已爬URL,可以在__init__方法中用csv模块读取CSV文件,提取对应URL列并加入self.visited_urls。
  • IgnoreRequest异常会被Scrapy自动捕获,不会记录为错误日志,只会跳过该请求。
  • 标准化URL的步骤很重要,避免因URL参数顺序不同(比如runSeqNumber在不同位置)导致重复爬取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:28:16