游客发表
写爬虫的模拟人迟早会碰到一个坎:你写的请求被服务器拒了。返回403,蜘蛛抓或者干脆给你一个验证码页面。模拟这时候你打开浏览器,蜘蛛抓同样的模拟URL,同样的蜘蛛抓网络,页面正常显示。模拟差别在哪?蜘蛛抓请求头。
浏览器发出去的模拟请求带了一整套身份信息。User-Agent告诉服务器我用的蜘蛛抓是Chrome还是Firefox,Accept声明我能接收什么格式的模拟内容,Accept-Language表明我偏好中文还是蜘蛛抓英文,Referer说明我是模拟从哪个页面跳过来的。这些字段拼在一起,蜘蛛抓构成了一个"看起来像真人"的模拟请求画像。Python的requests库默认只发一个python-requests/2.xx的User-Agent,等于举着牌子告诉对方"我是脚本"。
我最初做数据采集时踩过这个坑。目标站点是一个地方政府的公开信息平台,页面上挂着招标公告。用requests直接抓列表页,前几次还行,跑到第二十几页突然全部返回空数据。换了个IP还是这样。后来把浏览器F12打开,把Network面板里的请求头完整复制到代码里,问题消失了。不是IP被封,是请求头暴露了身份。
模拟的核心思路就是让服务端分辨不出请求来自脚本还是浏览器。最基础的做法是伪装User-Agent。网上有大量现成的UA列表,Chrome、Safari、Edge各版本都有。随机挑一个塞进header里,能骗过相当一部分站点的初级检测。
import requests import random ua_list = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15", ] headers = { "User-Agent": random.choice(ua_list), "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", } resp = requests.get("https://example.com/list?page=3", headers=headers) 光有UA还不够。有些站点会检查Accept-Encoding,看你是否支持gzip压缩。真实浏览器都会带这个字段,脚本往往忽略。还有Connection: keep-alive,表示保持长连接,也是浏览器默认行为。把这些补齐,请求就更像真的了。
Referer字段容易被忽视,但某些站点拿它做防盗链。比如图片CDN会检查请求来源是不是自家域名,不是就直接返回403。抓这类资源时,把Referer设成目标站点的首页地址,通常就能绕过。
Cookie是另一个维度。首次访问时服务器通过Set-Cookie下发会话标识,后续请求必须带上这个Cookie才能维持登录态或通过风控。requests的Session对象能自动处理这个过程:
s = requests.Session() s.headers.update(headers) s.get("https://example.com") # 获取Cookie resp = s.get("https://example.com/data") # 自动携带Cookie 但Cookie不是万能的。遇到Cloudflare的5秒盾,或者瑞数信息的动态Cookie,单纯靠请求头模拟就不够了。这些防护方案会在页面里嵌入JavaScript,要求浏览器执行一段混淆代码,算出新的Cookie值再发请求。脚本没有JS引擎,算不出来,请求就被拦截。这种场景需要上Selenium或Playwright,用真实浏览器内核去执行页面脚本。
我一般先用requests试探。如果返回200且内容正常,说明站点没做严格检测,继续用轻量方案。如果返回403或空内容,逐步加请求头字段。还是不行就换Session维持Cookie。最后才考虑上浏览器自动化,因为那玩意儿吃内存,跑大批量任务时开销明显。
有个细节值得说:请求频率。就算请求头伪装得再好,一秒发几十个请求,服务器照样能通过访问速率识别出异常。真实用户不会那样点击。加个time.sleep(random.uniform(1, 3)),让请求间隔带点随机性,比固定间隔更难被模式识别。
模拟蜘蛛抓取这件事,本质是一场信息博弈。你尽量让自己的请求和真实浏览器一致,对方尽量找出脚本的破绽。没有一劳永逸的方案,每个站点的检测策略不同,只能针对性地调试。好在大多数公开数据站点的防护并不严格,把请求头写完整,加上合理的访问节奏,八成以上的场景都能覆盖。
友情链接