Python爬虫—破解JS加密的Cookie

来源:Python中文社区 做者:Jerry Jerry,Python中文社区专栏做者。 前言 在GitHub上维护了一个代理池的项目,代理来源是抓取一些免费的代理发布网站。上午有个小哥告诉我说有个代理抓取接口不能用了,返回状态521。抱着帮人解决问题的心态去跑了一遍代码。发现果然是这样。 经过Fiddler抓包比较,基本能够肯定是JavaScript生成加密Cookie致使原来的请求返回521。 发现问题 打开Fiddler软件,用浏览器打开目标站点 。能够发现浏览器对这个页面加载了两次,第一次返回521,第二次才正常返回数据。不少没有写过网站或是爬虫经验不足的童鞋,可能就会以为奇怪为何会这样?为何浏览器可能正常返回数据而代码却不行? 仔细观察两次返回的结果能够发现: 一、第二次请求比第一次请求的Cookie内容多了个这个 _ydclearance=0c316df6ea04c5281b421aa8-5570-47ae-9768-2510d9fe9107-1490254971 二、第一次返回的内容一些复杂看不懂的JS代码,第二次返回的就是正确的内容。 其实这是网站反爬虫的经常使用手段。大体过程是这样的:首次请求数据时,服务端返回动态的混淆加密过的JS,而这段JS的做用是给Cookie添加新的内容用于服务端验证,此时返回的状态码是521。浏览器带上新的Cookie再次请求,服务端验证Cookie经过返回数据(这也是为嘛代码不能返回数据的缘由)。 解决问题 其实我第一次遇到这样的问题是,一开始想的就是既然你是用JS生成的Cookie, 那么我也能够将JS函数翻译成Python运行。可是最后仍是发现我太傻太天真,由于如今的JS都流行混淆加密,原始的JS这样的:看到这样的JS代码,我只能说原谅我JS能力差,还原不了。。。 可是前端经验丰富的童鞋立刻就能想到还有种方法可解,那就是利用浏览器的JS代码调试功能。这样一切就迎刃而解,新建一个html文件,将第一次返回的html原文复制进去,保存用浏览器打开,在eval以前打上断点,看到这样的输出: 能够看到这个变量po为 document.cookie='_ydclearance=0c316df6ea04c5281b421aa8-5570-47ae-9768-2510d9fe9107-1490254971; expires=Thu, 23-Mar-17 07:42:51 GMT; domain=.kuaidaili.com; path=/'; window.document.location=document.URL,下面还有个 eval("qo=eval;qo(po);")。 JS里面的eval和Python的差很少,第二句的意思就是将eval方法赋给qo。而后去eval字符串po。而字符串po的前半段的意思是给浏览器添加Cooklie,后半段window.document.location=document.URL是刷新当前页面。 这也印证了我上面的说法,首次请求没有Cookie,服务端回返回一段生成Cookie并自动刷新的JS代码。浏览器拿到代码可以成功执行,带着新的Cookie再次请求获取数据。而Python拿到这段代码就只能停留在第一步。 那么如何才能使Python也能执行这段JS呢,答案是PyV8。V8是Chromium中内嵌的javascript引擎,号称跑的最快。PyV8是用Python在V8的外部API包装了一个python壳,这样即可以使python能够直接与javascript操做。PyV8的安装你们能够自行百度。 代码 分析完成,下面切入正题撸代码。 首先是正常请求网页,返回带加密的JS函数的html:请点击此处输入图片描述因为返回的是html,并不单纯的JS函数,因此须要用正则提取JS函数的参数的参数。 还有一点须要注意,在JS函数中并无返回cookie,而是直接将cookie set到浏览器,因此咱们须要将eval("qo=eval;qo(po);")替换成return po这样就能成功返回po中的内容。 这样返回的cookie是字符串格式,可是用requests.get()须要字典形式,因此将其转换成字典: 最后带上解析出来的Cookie再次访问网页,成功获取数据: