用 Scrapy Pipeline 做字段级过滤最稳妥,因其专为清洗、验证、去敏设计,运行于 Item 生成后、存储前,不干扰解析逻辑与中间件机制,且支持多 Pipeline 协作与精准正则匹配。

用 Scrapy Pipeline 做字段级过滤最稳妥
Scrapy 的 Pipeline 是专为清洗、验证、去敏设计的环节,它天然在 Item 生成之后、存入数据库或文件之前运行,不会污染原始解析逻辑,也避免把过滤逻辑硬塞进 parse() 导致职责混乱。
常见错误是直接在 parse() 里用 if 'politics' in description 跳过 yield,这会导致后续中间件、统计、重试等机制失效;更糟的是,如果多个 Pipeline 需要协作(比如先去敏再翻译),顺序错乱就全乱套。
- 必须在
settings.py中启用:ITEM_PIPELINES = {'dirbot.pipelines.FilterWordsPipeline': 300},数字越小优先级越高 -
process_item方法里别直接修改item字段值(如item['description'] = item['description'].replace(...)),而应抛出DropItem或返回新Item实例,否则可能引发不可见的引用污染 - 敏感词匹配前务必统一转小写 + 去首尾空格,否则
'Politics '和'politics'就会漏判
正则替换比简单 replace 更安全
用 str.replace() 处理敏感词,看似简单,但极易误伤:比如过滤 'id',结果把 'identity'、'child' 全干掉了;而正则加词边界(r'\bid\b')能精准锚定独立单词。
实际场景中,招标信息爬虫常需过滤“中标”“废标”“围标”等词,但又不能影响“标书”“标准”“标识”——这时候不用 \b 就是埋雷。
立即学习“Python免费学习笔记(深入)”;
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 用
re.sub(r'|'.join(map(re.escape, words)), '*', text),re.escape防止敏感词含正则元字符(如'c++'、'C#')导致编译失败 - 不要用
flags=re.I简单处理大小写,而应在预处理时统一转小写,否则中文混英文场景下大小写逻辑会失控 - 性能上,100 个以内敏感词用正则没问题;超过 500 个建议换
ahocorasick,否则每次re.sub编译开销明显
日志输出必须单独加 Filter,不能靠 Pipeline 拦截
很多人以为 Pipeline 过滤了 Item,日志里就不会出现敏感内容——错了。Scrapy 默认会在 DEBUG 级别把整个 Item dump 到日志,哪怕你 Drop 掉了,dump 动作早已发生。
真实踩坑案例:某政务爬虫把身份证号字段进了 Item,Pipeline 正确 Drop,但日志文件里仍明文记录了带身份证的原始 Item 字典,审计时直接暴雷。
- 必须自定义
logging.Filter子类,在filter()方法里检查record.msg和record.args,对含'password'、'id_card'、'phone'的日志条目返回False - 这个 Filter 要显式添加到每个
Handler(StreamHandler和FileHandler都得加),缺一个就漏一个 - 别试图用
logger.debug("user: %s, pwd: %s", user, pwd)然后指望 Filter 拦住——pwd在格式化前就已进入record.args,Filter 必须扫描args元组
BeautifulSoup 解析时用 CSS 伪类提前排除干扰节点
敏感信息常藏在特定 DOM 区域里,比如“联系方式”模块、“备注”字段、“用户评论”区块。与其等全部数据进 Pipeline 再筛,不如在 parse() 阶段就用 CSS 选择器把高危区域直接剔除。
典型例子:抓医生执业信息时,“线上问诊”“视频咨询”这类条目常和实体诊所共享 .location-item 类名,若不前置过滤,后面清洗成本翻倍。
- 用
soup.select('.content:not(.comment):not(.contact)')直接跳过评论区和联系方式区,减少无效解析 - 结合
:-soup-contains()伪类,如.desc:not(:-soup-contains('身份证')),可快速排除含关键词的描述块 - 注意:
:-soup-contains()匹配的是元素自身文本(不含子元素),若敏感词在子标签里(如<span>密码</span>),得改用find_all(text=re.compile(...))回溯父节点
真正难的不是写过滤逻辑,而是判断哪一层该过滤——是网络层(请求头伪装)、解析层(CSS 排除)、管道层(字段校验),还是日志层(消息拦截)。漏掉任何一层,都可能让敏感信息从缝隙里漏出去。

















