【Python网络爬虫整理记录 D:01】——JS混淆加密

内容为学习小帅b的Python教学整理而来

帅B老仙,法力无边ღ( ´・ᴗ・` )比心

简介

学会爬取静态页面的数据后,下面固然是学习爬取动态页面的数据。javascript

  • 什么是动态页面呢?java

    有时候咱们再用requests抓取页面的时候,获得的结果可能和在浏览器中看到的不同:在浏览器中能够看到正常显示的页面数据,但在使用requests获得的结果中却没有。这是由于requests获取的都是原始的HTML文档,而浏览器中的页面则是通过JavaScript处理数据后生成的结果,这些数据的来源有多种,多是经过Ajax加载的,多是包含在HTML文档中的,也多是通过JavaScript和特定算法计算后生成的。python

本篇整理记录爬取其中经过JavaScript混淆加密来渲染的页面web

案例网站 有道翻译:http://fanyi.youdao.com/算法

发现问题

  • 按照一般构建爬虫的方法
  1. 打开chrome开发者工具,刷新页面,分析页面
    在这里插入图片描述chrome

    输入‘萌新’点击翻译后,右边的XHR栏中,出现一条类型为xhr的数据请求,点击查看后。
    POST请求地址为:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
    再看一下请求带过去的参数是哪些?json

    在这里插入图片描述

    OK!!!其中 i 这个参数就是咱们须要翻译的内容。那么直接复制请求头以及所需参数来构建requests请求。浏览器

  2. 构建requests请求cookie

    headers = {
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cookie": "OUTFOX_SEARCH_USER_ID=-1576851776@10.169.0.84; JSESSIONID="
                  "aaaBxpJhsD9bZgfYbsJax; OUTFOX_SEARCH_USER_ID_NCOO=2138649720.2208343;"
                  " ___rl__test__cookies=1581141334922",
        "Referer": "http://fanyi.youdao.com/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                      "(KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
    }
    url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
    form_data = {
        "i": '萌新',
        "from": "AUTO",
        "to": "AUTO",
        "smartresult": "dict",
        "client": "fanyideskweb",
        "salt": '15811630953552',
        "sign": '95f6b7ff43ba04c257097dabd115645e',
        "ts": '1581163095355',
        "bv": 'd6c3cd962e29b66abe48fcb8f4dd7f7d',
        "doctype": "json",
        "version": "2.1",
        "keyfrom": "fanyi.web",
        "action": "FY_BY_CLICKBUTTION"
    }
    
    response = requests.post(url=url, headers=headers, data=form_data)
    print(response.text)

    运行后结果:app

    在这里插入图片描述

    程序返回了一个错误码!

分析问题

  • 当咱们尝试翻译不一样的内容后,咱们发现参数 salt 、sign、ts、bv是会变化的。那么就该思考变化的参数是怎么来的呢?

    在这里插入图片描述
    在这里插入图片描述

  • 发现js文件

    此时发现这个数据请求它指向 fanyi.min.js:1 这个js文件,咱们点击这个js文件

    在这里插入图片描述

    出现这个界面,一堆的JavaScript代码,看也看不懂,咱们点击左下角的{}让它展开。

    在这里插入图片描述

  • 使用chrome的打断点功能

    方框处添加以前数据请求的POST地址:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
    而后,从新点击翻译按钮,断点成功屏幕会变为一半为灰色。 发现,行号从新定位在了7570行,展开右边 Call Stack,点击其中的
    t.translate发现有咱们须要的参数。

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 继续深刻

    将鼠标放入generateSaltSign上面,出现了如图所示的连接,点击跳转至8363行。

    在这里插入图片描述

  • 此时咱们就找到了须要的参数salt、sign、ts、bv的源头。

    鼠标点击8363行,出现蓝色的标记即为打上一个断点。而后点击上方图中所示按钮再点击一下翻译按钮

    在这里插入图片描述
    在这里插入图片描述

    经过上面的操做,咱们找出了4个参数的源头,正是经过上图中的JavaScript代码来计算出来的。下面就用python来构造这4个参数

解决问题

  • 参数:ts(JavaScript代码中是这样的:r = “” + (new Date).getTime())
def get_ts():
    ts = str(time.time() * 1000)
    return ts
  • 参数:bv(JavaScript代码中是这样的:t = n.md5(navigator.appVersion))
def get_bv():
    appVersion = "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
    m = hashlib.md5()
    m.update(appVersion.encode("utf-8"))
    bv = m.hexdigest()
    return bv
  • 参数:salt(JavaScript代码中是这样的:i = r + parseInt(10 * Math.random(), 10))
def get_salt():
    salt = str(time.time() * 1000) + str(random.random() * 10)
    return salt
  • 参数:sign(JavaScript代码中是这样的:n.md5(“fanyideskweb” + e + i + “n%A-rKaT5fb[Gy?;N5@Tj”))
def get_sign(myinput):
    a = "fanyideskweb"
    b = myinput
    c = get_salt()
    d = "n%A-rKaT5fb[Gy?;N5@Tj"
    str_data = a + b + c + d

    m = hashlib.md5()
    m.update(str_data.encode("utf-8"))
    sign = m.hexdigest()
    return sign
  • 完整代码:
import requests
import time
import json
import hashlib
import random


def get_ts():
    ts = str(time.time() * 1000)
    return ts


def get_bv():
    appVersion = "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
    m = hashlib.md5()
    m.update(appVersion.encode("utf-8"))
    bv = m.hexdigest()
    return bv


def get_salt():
    salt = str(time.time() * 1000) + str(random.random() * 10)
    return salt


def get_sign():
    a = "fanyideskweb"
    b = "萌新"
    c = get_salt()
    d = "n%A-rKaT5fb[Gy?;N5@Tj"
    str_data = a + b + c + d

    m = hashlib.md5()
    m.update(str_data.encode("utf-8"))
    sign = m.hexdigest()
    return sign


def get_request():
    headers = {
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cookie": "OUTFOX_SEARCH_USER_ID=-1576851776@10.169.0.84; JSESSIONID="
                  "aaaBxpJhsD9bZgfYbsJax; OUTFOX_SEARCH_USER_ID_NCOO=2138649720.2208343;"
                  " ___rl__test__cookies=1581141334922",
        "Referer": "http://fanyi.youdao.com/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                      "(KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
    }
    url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"
    form_data = {
        "i": '萌新',
        "from": "AUTO",
        "to": "AUTO",
        "smartresult": "dict",
        "client": "fanyideskweb",
        "salt": get_salt(),
        "sign": get_sign(),
        "ts": get_ts(),
        "bv": get_bv(),
        "doctype": "json",
        "version": "2.1",
        "keyfrom": "fanyi.web",
        "action": "FY_BY_CLICKBUTTION"
    }

    response = requests.post(url=url, headers=headers, data=form_data)
    print("翻译结果是:" + str(json.loads(response.text)['translateResult'][0][0]['tgt']))


if __name__ == '__main__':
    get_request()

扩展

既然,咱们能找到这些参数的规律,咱们能够打包成 .exe 可执行文件作成翻译软件,分享给身边的小伙伴学习交流使用!!!
参考:Python中将.py文件打包成.exe可执行文件的简单方法