网虫Spider订阅

raise NotConfigured 带不带消息,决定了它是一条 WARNING 还是零日志——而管道就是这么没的

MiddlewareManager 里那句 if e.args 决定一切:带消息的 NotConfigured 打一条 WARNING,不带的一行日志都没有。实测一个裸 raise NotConfigured 的管道——item 抓到 3 条,落库 0 条,退出码 0,日志零行。

源码剖析Scrapy工程化6 min

Codex 生成 React 组件:一句「不要引入任何第三方依赖」,把 Portal 砍掉了

一句话需求生成的模态框自带焦点陷阱、Esc 关闭与完整 aria;换上精心写的提示词反而丢了 createPortal。tsc --strict 和 jsx-a11y 两轮全过,差异只能靠读代码找出来。

工程实践Codex前端13 min

让 IP 纯净度的每一分都能被读者自己验算:四条判据、四套权重,五个分数手算全对

同类工具给一个不解释的数字。这篇把评分过程整个摊开:一个 IP 的四条判据、总分怎么来的、四个使用场景怎么从同一批判据得出 58 到 91 的不同结论——全部用线上接口返回的真实数据手算复现,一分不差。

工程实践IP 情报风控9 min

五个骗过我的假信号:测试 12 全过、脚本 0 报错、检查 0 命中,然后结论全是反的

八秒跑完九条调用、十二个用例全过、正则扫描零命中——五次「看起来正常」的结果,结论全都是反的。附上把它们捞回来的四个信号。

工程实践工程化调试17 min

只用免费数据源能把一个 IP 认到什么程度:9 个源实测,地理位置 5 个 IP 全部对不上

不配任何商业 API key,用 RDAP、Team Cymru、DNSBL、Tor 出口表这些免费源,能定出 IP 的归属、路由、类型和暴露面。但地理位置不行——两个免费地理源对五个知名 IP 给出的城市全部不一致,最远差 3865 公里。

采集与逆向IP 情报风控10 min

同一个 IP 一生只查一次:三级读取、双桶限流,和一道只拦花钱请求的人机验证

按量计费的数据源加上公开的查询入口,等于把账单交给陌生人。这套读取与守门的设计里,最关键的一条是:人机验证只拦会真实产生费用的请求,读库返回的报告一律放行——因为那些报告本身就是站点的流量入口。

工程实践IP 情报工程化9 min

自定义下载处理器炸了,Scrapy 只报「Unsupported URL scheme」——而且这辈子都不会再试一次

DownloadHandlers 把加载失败包装成 NotSupported,原始异常被塞进「不支持的协议」这句话里;失败结果还会永久缓存,一次失败之后同一个 scheme 的所有请求都直接返回缓存,构造函数再也不会被调用第二次。

源码剖析Scrapy工程化9 min

FEEDS 里写错一个字母,另一个完全正确的输出也消失了:item 抓到 3 条,文件 0 个

FEEDS 的校验在遍历循环里 raise NotConfigured,而这会让整个导出扩展被停用——不是跳过那个配错的输出,是全部。配两个输出、其中一个格式名拼错,两个都不会生成。

源码剖析Scrapy工程化6 min

settings.set() 可能什么都没做:优先级低于现值时静默丢弃,返回值还是 None

Scrapy 的 Settings 按优先级写入,低于当前优先级的写入会被直接丢掉——不抛异常、不打告警,set() 的返回值和成功时一模一样。spider 的 custom_settings 会挡住后来所有默认优先级的修改。

源码剖析Scrapy工程化6 min

Scrapy 2.17 里 start_requests() 已经没人调用了:0 个请求、0 个告警、退出码 0

升到 2.13 之后,只定义 start_requests() 的爬虫会产出 0 个请求。不报错、不告警、finish_reason 还是 finished。这是我自己在写另一篇文章时踩进去的。

源码剖析Scrapy工程化6 min

盐值随版本变动怎么办:从静态资源里自动提取

写死盐值的采集脚本会在对方发版当天全线失效。把提取动作做成运行时的一步,比每次手工重新逆向划算得多。

采集与逆向JS 逆向工程化2 min

从一个 sign 参数入手:还原某电商平台商品详情接口的签名算法

商品详情接口带一个 32 位的 sign,改动任意查询参数都会返回 403。整个过程分三步:定位生成位置、剥离混淆、脱离浏览器环境复现。

采集与逆向JS 逆向抓包3 min