热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

图文详解Python爬虫破解JS加密的Cookie步骤

前言在GitHub上维护了一个代理池的项目,代理来源是抓取一些免费的代理发布网站。上午有个小哥告诉我说有个代理抓取接口不能用了,返回状态521。抱着帮人解决问题的心态去跑了一遍代码。发现果真是这样。通过Fiddler抓包比较,基本可以确定是JavaScript生成加密Cookie导致原来的请求返回521。

前言

  在GitHub上维护了一个代理池的项目,代理来源是抓取一些免费的代理发布网站。上午有个小哥告诉我说有个代理抓取接口不能用了,返回状态521。抱着帮人解决问题的心态去跑了一遍代码。发现果真是这样。

  通过Fiddler抓包比较,基本可以确定是Javascript生成加密COOKIE导致原来的请求返回521。

发现问题

  打开Fiddler软件,用浏览器打开目标站点(http://www.kuaidaili.com/proxylist/2/) 。可以发现浏览器对这个页面加载了两次,第一次返回521,第二次才正常返回数据。很多没有写过网站或是爬虫经验不足的童鞋,可能就会觉得奇怪为什么会这样?为什么浏览器可能正常返回数据而代码却不行?

  1、第二次请求比第一次请求的COOKIE内容多了个这个_ydclearance=0c316df6ea04c5281b421aa8-5570-47ae-9768-2510d9fe9107-1490254971

  2、第一次返回的内容一些复杂看不懂的JS代码,第二次返回的就是正确的内容

  其实这是网站反爬虫的常用手段。大致过程是这样的:首次请求数据时,服务端返回动态的混淆加密过的JS,而这段JS的作用是给COOKIE添加新的内容用于服务端验证,此时返回的状态码是521。浏览器带上新的COOKIE再次请求,服务端验证COOKIE通过返回数据(这也是为嘛代码不能返回数据的原因)。

解决问题

  其实我第一次遇到这样的问题是,一开始想的就是既然你是用JS生成的COOKIE, 那么我也可以将JS函数翻译成Python运行。但是最后还是发现我太傻太天真,因为现在的JS都流行混淆加密,原始的JS这样的:

function lq(VA) {
    var qo, mo = "", no = "", oo = [0x8c, 0xcd, 0x4c, 0xf9, 0xd7, 0x4d, 0x25, 0xba, 0x3c, 0x16, 0x96, 0x44, 0x8d, 0x0b, 0x90, 0x1e, 0xa3, 0x39, 0xc9, 0x86, 0x23, 0x61, 0x2f, 0xc8, 0x30, 0xdd, 0x57, 0xec, 0x92, 0x84, 0xc4, 0x6a, 0xeb, 0x99, 0x37, 0xeb, 0x25, 0x0e, 0xbb, 0xb0, 0x95, 0x76, 0x45, 0xde, 0x80, 0x59, 0xf6, 0x9c, 0x58, 0x39, 0x12, 0xc7, 0x9c, 0x8d, 0x18, 0xe0, 0xc5, 0x77, 0x50, 0x39, 0x01, 0xed, 0x93, 0x39, 0x02, 0x7e, 0x72, 0x4f, 0x24, 0x01, 0xe9, 0x66, 0x75, 0x4e, 0x2b, 0xd8, 0x6e, 0xe2, 0xfa, 0xc7, 0xa4, 0x85, 0x4e, 0xc2, 0xa5, 0x96, 0x6b, 0x58, 0x39, 0xd2, 0x7f, 0x44, 0xe5, 0x7b, 0x48, 0x2d, 0xf6, 0xdf, 0xbc, 0x31, 0x1e, 0xf6, 0xbf, 0x84, 0x6d, 0x5e, 0x33, 0x0c, 0x97, 0x5c, 0x39, 0x26, 0xf2, 0x9b, 0x77, 0x0d, 0xd6, 0xc0, 0x46, 0x38, 0x5f, 0xf4, 0xe2, 0x9f, 0xf1, 0x7b, 0xe8, 0xbe, 0x37, 0xdf, 0xd0, 0xbd, 0xb9, 0x36, 0x2c, 0xd1, 0xc3, 0x40, 0xe7, 0xcc, 0xa9, 0x52, 0x3b, 0x20, 0x40, 0x09, 0xe1, 0xd2, 0xa3, 0x80, 0x25, 0x0a, 0xb2, 0xd8, 0xce, 0x21, 0x69, 0x3e, 0xe6, 0x80, 0xfd, 0x73, 0xab, 0x51, 0xde, 0x60, 0x15, 0x95, 0x07, 0x94, 0x6a, 0x18, 0x9d, 0x37, 0x31, 0xde, 0x64, 0xdd, 0x63, 0xe3, 0x57, 0x05, 0x82, 0xff, 0xcc, 0x75, 0x79, 0x63, 0x09, 0xe2, 0x6c, 0x21, 0x5c, 0xe0, 0x7d, 0x4a, 0xf2, 0xd8, 0x9c, 0x22, 0xa3, 0x3d, 0xba, 0xa0, 0xaf, 0x30, 0xc1, 0x47, 0xf4, 0xca, 0xee, 0x64, 0xf9, 0x7b, 0x55, 0xd5, 0xd2, 0x4c, 0xc9, 0x7f, 0x25, 0xfe, 0x48, 0xcd, 0x4b, 0xcc, 0x81, 0x1b, 0x05, 0x82, 0x38, 0x0e, 0x83, 0x19, 0xe3, 0x65, 0x3f, 0xbf, 0x16, 0x88, 0x93, 0xdd, 0x3b];
    qo = "qo=241; do{oo[qo]=(-oo[qo])&0xff; oo[qo]=(((oo[qo]>>3)|((oo[qo]<<5)&0xff))-70)&0xff;} while(--qo>=2);";
    eval(qo);
    qo = 240;
    do {
        oo[qo] = (oo[qo] - oo[qo - 1]) & 0xff;
    } while (--qo >= 3);
    qo = 1;
    for (; ;) {
        if (qo > 240) break;
        oo[qo] = ((((((oo[qo] + 2) & 0xff) + 76) & 0xff) <<1) & 0xff) | (((((oo[qo] + 2) & 0xff) + 76) & 0xff) >> 7);
        qo++;
    }
    po = "";
    for (qo = 1; qo 

  看到这样的JS代码,我只能说原谅我JS能力差,还原不了。。。

  但是前端经验丰富的童鞋马上就能想到还有种方法可解,那就是利用浏览器的JS代码调试功能。这样一切就迎刃而解,新建一个html文件,将第一次返回的html原文复制进去,保存用浏览器打开,在eval之前打上断点,看到这样的输出:

  可以看到这个变量po为document.COOKIE=&#39;_ydclearance=0c316df6ea04c5281b421aa8-5570-47ae-9768-2510d9fe9107-1490254971; expires=Thu, 23-Mar-17 07:42:51 GMT; domain=.kuaidaili.com; path=/&#39;; 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:

import re
import PyV8
import requests

TARGET_URL = "http://www.kuaidaili.com/proxylist/1/"

def getHtml(url, COOKIE=None):
    header = {
        "Host": "www.kuaidaili.com",
        &#39;Connection&#39;: &#39;keep-alive&#39;,
        &#39;Cache-Control&#39;: &#39;max-age=0&#39;,
        &#39;Upgrade-Insecure-Requests&#39;: &#39;1&#39;,
        &#39;User-Agent&#39;: &#39;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36&#39;,
        &#39;Accept&#39;: &#39;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&#39;,
        &#39;Accept-Encoding&#39;: &#39;gzip, deflate, sdch&#39;,
        &#39;Accept-Language&#39;: &#39;zh-CN,zh;q=0.8&#39;,
    }
    html = requests.get(url=url, headers=header, timeout=30, COOKIEs=COOKIE).content
    return html
# 第一次访问获取动态加密的JS
first_html = getHtml(TARGET_URL)

  由于返回的是html,并不单纯的JS函数,所以需要用正则提取JS函数的参数的参数。

# 提取其中的JS加密函数
js_func = &#39;&#39;.join(re.findall(r&#39;(function .*?)&#39;, first_html))

print &#39;get js func:\n&#39;, js_func

# 提取其中执行JS函数的参数
js_arg = &#39;&#39;.join(re.findall(r&#39;setTimeout\(\"\D+\((\d+)\)\"&#39;, first_html))

print &#39;get ja arg:\n&#39;, js_arg

  还有一点需要注意,在JS函数中并没有返回COOKIE,而是直接将COOKIE set到浏览器,所以我们需要将eval("qo=eval;qo(po);")替换成return po。这样就能成功返回po中的内容。

# -*- coding: utf-8 -*-"""
-------------------------------------------------
   File Name:     demo_1.py.py  
   Description :  Python爬虫—破解JS加密的COOKIE 快代理网站为例:http://www.kuaidaili.com/proxylist/1/
                  Document:
   Author :       JHao
   date:          2017/3/23
-------------------------------------------------
   Change Activity:
                   2017/3/23: 破解JS加密的COOKIE
-------------------------------------------------
"""__author__ = &#39;JHao&#39;import reimport PyV8import requests

TARGET_URL = "http://www.kuaidaili.com/proxylist/1/"def getHtml(url, COOKIE=None):
    header = {        "Host": "www.kuaidaili.com",        &#39;Connection&#39;: &#39;keep-alive&#39;,        &#39;Cache-Control&#39;: &#39;max-age=0&#39;,        &#39;Upgrade-Insecure-Requests&#39;: &#39;1&#39;,        &#39;User-Agent&#39;: &#39;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36&#39;,        &#39;Accept&#39;: &#39;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&#39;,        &#39;Accept-Encoding&#39;: &#39;gzip, deflate, sdch&#39;,        &#39;Accept-Language&#39;: &#39;zh-CN,zh;q=0.8&#39;,
    }
    html = requests.get(url=url, headers=header, timeout=30, COOKIEs=COOKIE).content    return htmldef executeJS(js_func_string, arg):
    ctxt = PyV8.JSContext()
    ctxt.enter()
    func = ctxt.eval("({js})".format(js=js_func_string))    return func(arg)def parseCOOKIE(string):
    string = string.replace("document.COOKIE=&#39;", "")
    clearance = string.split(&#39;;&#39;)[0]    return {clearance.split(&#39;=&#39;)[0]: clearance.split(&#39;=&#39;)[1]}# 第一次访问获取动态加密的JSfirst_html = getHtml(TARGET_URL)# first_html = """#  # """# 提取其中的JS加密函数js_func = &#39;&#39;.join(re.findall(r&#39;(function .*?)&#39;, first_html))print &#39;get js func:\n&#39;, js_func# 提取其中执行JS函数的参数js_arg = &#39;&#39;.join(re.findall(r&#39;setTimeout\(\"\D+\((\d+)\)\"&#39;, first_html))print &#39;get ja arg:\n&#39;, js_arg# 修改JS函数,使其返回COOKIE内容js_func = js_func.replace(&#39;eval("qo=eval;qo(po);")&#39;, &#39;return po&#39;)# 执行JS获取COOKIECOOKIE_str = executeJS(js_func, js_arg)# 将COOKIE转换为字典格式COOKIE = parseCOOKIE(COOKIE_str)print COOKIE# 带上COOKIE再次访问url,获取正确数据print getHtml(TARGET_URL, COOKIE)[0:500]

以上就是图文详解Python爬虫破解JS加密的COOKIE步骤的详细内容,更多请关注 第一PHP社区 其它相关文章!


推荐阅读
  • 在Notepad++中配置Markdown语法高亮及实时预览功能
    本文详细介绍了如何在Notepad++中配置Markdown语法高亮和实时预览功能,包括必要的插件安装和设置步骤。 ... [详细]
  • 本文分享了作者在使用LaTeX过程中的几点心得,涵盖了从文档编辑、代码高亮、图形绘制到3D模型展示等多个方面的内容。适合希望深入了解LaTeX高级功能的用户。 ... [详细]
  • 实现Win10与Linux服务器的SSH无密码登录
    本文介绍了如何在Windows 10环境下使用Git工具,通过配置SSH密钥对,实现与Linux服务器的无密码登录。主要步骤包括生成本地公钥、上传至服务器以及配置服务器端的信任关系。 ... [详细]
  • 本文提供了一个详尽的前端开发资源列表,涵盖了从基础入门到高级应用的各个方面,包括HTML5、CSS3、JavaScript框架及库、移动开发、API接口、工具与插件等。 ... [详细]
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 默认情况下,Git 使用 Nano 编辑器进行提交信息的编辑,但如果您更喜欢使用 Vim,可以通过简单的配置更改来实现这一变化。本文将指导您如何通过修改全局配置文件来设置 Vim 作为默认的 Git 提交编辑器。 ... [详细]
  • 本文介绍了如何通过安装 sqlacodegen 和 pymysql 来根据现有的 MySQL 数据库自动生成 ORM 的模型文件(model.py)。此方法适用于需要快速搭建项目模型层的情况。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 一、使用Microsoft.Office.Interop.Excel.DLL需要安装Office代码如下:2publicstaticboolExportExcel(S ... [详细]
  • egg实现登录鉴权(七):权限管理
    权限管理包含三部分:访问页面的权限,操作功能的权限和获取数据权限。页面权限:登录用户所属角色的可访问页面的权限功能权限:登录用户所属角色的可访问页面的操作权限数据权限:登录用户所属 ... [详细]
  • 本文介绍了用户界面(User Interface, UI)的基本概念,以及在iOS应用程序中UIView及其子类的重要性和使用方式。文章详细探讨了UIView如何作为用户交互的核心组件,以及它与其他UI控件和业务逻辑的关系。 ... [详细]
  • 本文探讨了线性表中元素的删除方法,包括顺序表和链表的不同实现策略,以及这些策略在实际应用中的性能分析。 ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • Java虚拟机及其发展历程
    Java虚拟机(JVM)是每个Java开发者日常工作中不可或缺的一部分,但其背后的运作机制却往往显得神秘莫测。本文将探讨Java及其虚拟机的发展历程,帮助读者深入了解这一关键技术。 ... [详细]
author-avatar
mobiledu2502885977
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有