爬虫
凌晨三点,爬虫我盯着屏幕上滚动的爬虫日志,一行行HTTP 200里突然蹦出个403。爬虫就这一个数字,爬虫意味着过去四十分钟爬下来的爬虫两万条数据里,有三百多条是爬虫空的。那种感觉像钓鱼时鱼线突然断了,爬虫你知道水下有东西,爬虫但就是爬虫拽不上来。
写爬虫的爬虫人迟早都会撞上这堵墙。网站不是爬虫为你准备的,它防的爬虫就是你这种不请自来的家伙。我见过最离谱的爬虫一个站点,检测到连续请求间隔小于1.2秒就封IP,爬虫封多久?爬虫24小时。那时候我才刚开始写爬虫,用requests加个for循环就敢往上冲,结果半小时后整个办公室的网都断了——出口IP被拉黑,连正常访问都做不了。运维同事看我的眼神,我到现在都记得。
后来学乖了。time.sleep(3)成了肌肉记忆,User-Agent池子越攒越大,从Chrome到Firefox到Safari,甚至塞了几个手机端的。但光换马甲不够。有次爬一个电商网站的价格数据,明明加了随机延时,换了IP,还是被识别。折腾半天才发现问题出在请求头顺序上——Python的requests库默认按字典序排header,而真实浏览器发出来的顺序是固定的。就这个细节,让对方的WAF一眼认出我是机器人。
你说这算不算猫鼠游戏?算。但更像是在别人家院子里捡果子,你得知道哪根树枝能踩,哪根一碰就响警报。
分布式爬虫听起来唬人,其实就是多找几个人同时帮你捡。Scrapy-Redis那套东西我搭过,Redis里塞个url队列,几台机器各拿各的任务。麻烦在哪?去重。布隆过滤器能把内存压到十分之一,但误判率得自己权衡。我设的0.001,一万条里错杀十条,能接受。真正头疼的是调度——有的URL重试三次都失败,有的被其他节点拿走了但迟迟没完成,队列越堆越长。最后写了个监控脚本,每五分钟扫一次Redis,超时的任务强制回收。那段时间我做梦都是key的过期时间。
数据存下来才是自己的。MongoDB适合结构乱的,MySQL适合字段固定的,我一般先扔进MongoDB,清洗完再导关系库。清洗这步最烦,HTML标签用BeautifulSoup剥一层,正则再扫一遍,遇到JavaScript渲染的页面还得上Selenium或者Playwright。Selenium慢,但稳。Playwright快,但版本一升级API就变。去年有个项目用Playwright抓动态表格,升级到1.40后wait_for_selector的行为改了,之前能跑的全报超时。查了半天文档,原来默认等待策略从“可见”变成了“附加到DOM”。这种坑,踩一次记一辈子。
法律的事得拎清楚。robots.txt不是摆设,虽然它没有强制力,但法庭上会看。我见过有人爬招聘网站被判了不正当竞争,赔了钱还上了新闻。自己的项目里,凡是带个人信息的字段,爬下来就脱敏,手机号中间四位直接星号。这不是技术问题,是底线问题。
说回开头那个403。后来我抓包看了下,对方在响应头里塞了个加密token,每次请求必须带上上一次返回的值。典型的链式验证。解决办法也简单,用session保持会话,把token存下来,下一次请求带上去。代码改了三行,跑通了。凌晨四点,日志里再没出现403。屏幕光打在脸上,我倒了杯凉掉的咖啡,心想:又过了一关。
爬虫这东西,入门容易,写好难。它考的不是你多会写代码,是你多能琢磨人——网站怎么想的,运维怎么防的,数据怎么藏的。每一次成功抓取,都是你跟另一个工程师隔着网线的无声对话。
(责任编辑:热点)
