1. 为什么你的携程爬虫突然“罢工”了?
最近好几个做数据分析的朋友跟我吐槽,说之前跑得好好的携程酒店爬虫,突然就“罢工”了,要么返回空数据,要么直接跳验证码,甚至IP还被短暂限制访问。这感觉就像你一直走的那条小路,突然被物业加了道门禁,没卡就进不去了。其实,这背后就是携程升级了它的反爬虫策略,而其中最关键的一道“门禁”,就是动态Cookies验证。
你可能觉得,Cookies不就是浏览器里存的一小段文本吗?我之前写爬虫也是直接从浏览器里复制一串Cookie,放到headers里,就能用上一整天。但现在这招不灵了。携程的Cookies变得“聪明”了,它不再是静态的、长期有效的凭证。很多关键的Cookie值(比如用来标识会话、验证身份的MKT_Pages、_RF1等)现在都有了很短的有效期,可能几分钟、甚至请求几次后就失效了。同时,这些Cookie的生成和更新逻辑,可能还和你的请求参数、时间戳甚至浏览器指纹绑定在一起。
这就导致了一个很头疼的问题:你辛辛苦苦从登录后的网页复制来的Cookie,在爬虫脚本里刚用了几分钟,携程服务器就认为这个Cookie已经“过期”或“无效”,于是给你的回应要么是一堆乱码JSON,要么就是一个友好的“请稍后再试”提示。你的爬虫看起来还在勤勤恳恳地发请求,但实际上早就被挡在数据的大门之外了,自己还浑然不觉。
所以,今天我们要聊的,不是怎么复制粘贴Cookie,而是怎么像真人浏览网页一样,动态地、自动地维护一套有效的Cookie池。这就像你不是去借别人的门禁卡,而是学会了怎么自己随时生成一张能刷开的卡。掌握了这个核心,你的爬虫在面对携程这类动态验证时,稳定性会有一个质的飞跃。接下来,我们就从原理到实战,一步步拆解这个“动态Cookie”的破解之道。
2. 深入核心:携程的动态Cookie机制探秘
要破解它,先得理解它。携程的动态Cookie机制,本质上是一种状态管理和反自动化的结合体。我们可以把它想象成一个不断更新的“会话通行证”。
2.1 Cookie的生命周期与关键成员
当你用浏览器访问携程酒店页面时,第一次请求,服务器会下发一批Cookie来“认识你”。这其中,有些Cookie是长期不变的(比如记录城市偏好的),但有些是会话级或短期验证型的。在数据接口请求(比如AjaxHotelList.aspx)中,后者尤为重要。通过浏览器开发者工具的Network面板,仔细观察连续几次翻页请求,你会发现Cookie请求头里的某些值在微妙地变化。
这些变化的Cookie,可能就是验证你是否为“真人操作”的关键。它们的更新可能依赖于:
- 上一个请求的响应:服务器可能在某个JSON响应里藏了一个新的
token,需要你提取出来,更新到下一个请求的Cookie里。 - 特定的初始化请求:在获取酒店列表前,可能需要先访问一个“种子页面”或发送一个“初始化请求”,来获取一套合法的初始Cookie。直接怼着数据接口猛刷,会因为缺少这个“初始化”步骤而被识别。
- 时间戳或加密参数:Cookie的值可能包含了经过特定算法加密的时间戳,服务器会校验这个时间是否在合理的新鲜度范围内。
2.2 从“复制粘贴”到“动态维护”的思维转变
原始文章里的代码,是把一个很长的、固定的Cookie字符串直接写死在headers里。这在过去可能管用,但现在就是“刻舟求剑”。我们的新思路是:
- 不要把Cookie当作一个静态字符串。
- 要把Cookie当作一个动态的、需要管理的字典对象。
Python的requests库自带的Session对象,就是为我们做这件事的。Session会自动保存服务器返回的Cookie,并在后续请求中自动发送,这模拟了浏览器的基本行为。但携程的挑战在于,有些Cookie的更新逻辑Session可能无法自动处理,这就需要我们手动介入,进行“精耕细作”。
2.3 实战观察:找到Cookie的更新点
理论说再多,不如动手看一眼。我们打开浏览器(以Chrome为例),进入携程酒店列表页(如https://hotels.ctrip.com/hotel/beijing1),按下F12打开开发者工具,切换到Network(网络)面板。
- 清空现有记录,然后刷新页面。你会看到加载了一堆资源(文档、JS、图片、XHR)。
- 在筛选栏输入
AjaxHotelList(数据接口)或aspx,找到核心的数据请求。 - 点击这个请求,查看
Headers选项卡下的Request Headers,找到Cookie那一长串。 - 然后,你点击网页上的“下一页”按钮,同时观察网络面板中新出现的那个数据请求。
- 再次查看它的
Cookie,并与第一个请求的Cookie进行逐项对比。是不是发现有些值变了?比如_MKT_Pages、_RF1、_RCI这类看着像令牌的字符串。 - 更重要的是,查看第一个数据请求的
Response(响应)标签,看看返回的JSON数据里,除了酒店列表,有没有包含一些新的、看起来像令牌的字段?有时候,新的Cookie值就藏在这里面,需要你提取出来,手动设置到Session的Cookie字典里,用于下一次请求。
这个过程,就是我们破解动态Cookie的“侦察兵”阶段,至关重要。它告诉我们敌人在哪里换岗,以及新的口令是什么。
3. 构建你的智能Cookie管家:Session与手动更新策略
知道了原理,我们开始搭建一套可靠的Cookie管理机制。核心工具就是requests.Session()。
3.1 使用Session对象维持会话状态
Session的好处是,它会自动处理大多数Cookie的存储和发送,让我们省去手动拼接Cookie字符串的麻烦。基础用法很简单:
import requests
# 创建一个会话对象,它就像一个小型浏览器
session = requests.Session()
# 配置一些通用的请求头,User-Agent一定要设置成常见的浏览器
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'application/json, text/javascript, */*; q=0.01',


1591

被折叠的 条评论
为什么被折叠?



