数据爬取 js 分析:对加密参数进行 js分析

hresh 384 0

数据爬取 js 分析:对加密参数进行 js分析

接着上期对 post 请求中 form data 数据加密的分析,今天我们接着进行 get 请求中 加密参数的分析。

一、实例网站

本实例的网站是七麦数据中国 App Store 排行榜,继续学习使用 chome 浏览器的 devtool 工具,对 js 进行分析,首先需要找到加密位置,然后提取出 js 代码,进行设计实现同等功能,最后转换为 Python 实现,从而实现对数据的爬取。

二、页面分析

1.抓包分析

进入页面后,按 F12 打开开发者工具 devtool,点击切换到“network”标签页。通过分析网络请求我们可以发现,榜单数据是通过 Ajax 请求来获取的。返回的数据格式是明文 Json。

页面请求分析

页面请求分析

各个参数所代表的含义都较为易懂,除了 analysis。猜测是一个经过 Base64 编码后的加密参数,事实上的确如此,隔一段时间再利用相同的 analysis 提交请求时会被拒绝。

2.调试分析

要解密参数,只能去看 JS 的加密代码。经过这几天的练习,我首先尝试搜索 analysis 字段,看看有什么发现。

js代码分析调试

结果并没有什么有价值的线索,因此我们换个方向开始分析。我们需要查看是哪部分的 JS 代码发起了请求,一般的方法是点击请求列表的 Initiator 跳转到代码部分。

数据爬取 js 分析:对加密参数进行 js分析

js代码分析调试

不过我更推荐另一种方法:添加 XHR Breakpoints 拦截请求。这样有两个好处,一是可以直接观察代码上下文的变量在发出请求前的数值,二是方便直接调试。此处填入 URL 包含的关键词 analysis。

js代码分析调试

在这里我们就按照最快捷的方法进行讲解,首先我们需要了解 ”Sources“栏 Call Stack 的用处,通过选择 View→Debug Windows→Call Stack 命令打开,一层一层往上找,找到最后调用该函数的位置。

js代码分析调试

在 get 函数处打断点调试。

js代码分析调试

发现这里有请求参数,除了还未发现 analysis 参数值。进行到这里,我们没有别的思路,那就往上找,找到包含 get 函数的函数集 gXmS,并通过断点进行调试(需要先取消 get 函数处的断点,然后实际调试过程中一直到不了 gXmS 函数处的断点,在 F12 状态下,右键刷新按钮,点击清空缓存并硬性重新加载。)。

js代码分析调试

可以看到 P 字段内容为 analysis,说明我们很接近加密函数了。接着打断点进行分析。在后续的断点测试中,我们还会看到这样的显示。

在这里插入图片描述

可以看到加密数据,至此,我们找到加密函数的位置,接下来截取 js 代码,实现加密功能。

3.加密分析

将相关的代码提取出来,放入到 html 文件中,进行功能测试。

try {
      if (!k && void 0 == g[XM]) {
          var t = a[pm](f[ql])(x);
          g[XM] = -a[pm](f[ql])(H) || +new a[wa] - Wf * t
      }
      var e = +new a[wa] - (g[XM] ? g[XM] : h) - 1515125653845
        , r = w
        , m = [];
      return void 0 === n[qM] && (n[qM] = {}),
      u()(n[qM])[Qm](function(a) {
          if (a == P)
              return !S;
          n[qM][Yn](a) && m[$](n[qM][a])
      }),
      m = m[jC]()[W](w),
      m = a[pm](f[Ta])(m),
      m += R + n[Oa][xa](n[IM], w),
      m += R + e,
      m += R + S,
      r = a[pm](f[Ta])(a[pm](f[Zn])(m, b)),
      -S == n[Oa][ra](P) && (n[Oa] += (-S != n[Oa][ra](yH) ? JM : yH) + P + gl + a[hp](r)),
      n
  } catch (n) {}

上述代码是加密函数主要部分,在调试过程中发现还调用了别的函数。
数据编码部分 ,通过网上查询 js 的相关知识,得知是对数据进行 Base64 编码。

数据爬取 js 分析:对加密参数进行 js分析

js代码调试

数据加密方法 js 实现。

数据爬取 js 分析:对加密参数进行 js分析

最后,总结出该网页参数加密的基本过程:

  • 设置一个时间差变量
  • 提取查询参数值(除了 analysis)
  • 排序拼接参数值字符串并 Base64 编码
  • 拼接自定义字符串
  • 自定义加密后再 Base64 编码
  • 拼接 analysis 到 URL

需要注意的是:

js代码调试

这里的 g[XM] 值是变动的,在测试的过程中,发现不加入该值并不受影响。

将查询参数实例化,用于 html 验证。

js代码调试

base64 编码函数,是在网上查找的另外一种实现方法。

js代码调试

结果如下:

数据爬取 js 分析:对加密参数进行 js分析

三、Python 数据爬取

将上述的 js 相关代码,转换为 Python 代码实现,得到 analysis 参数内容后,拼接新的 url 用来爬取网页信息。

    def encrypt(self, a, n="00000008d78d46a"):
        '''
        加密函数,
        :param a:拼接后的数据
        :param n:加密时需要的数据,具有时间性,会有变化
        :return:加密后的字段
        '''
        s = list(a)
        n = list(n)
        nl = len(n)
        for i in range(len(s)):
            #ord()函数主要用来返回对应字符的ascii码
            #chr()主要用来表示ascii码对应的字符他的输入时数字
            s[i] = chr(ord(s[i]) ^ ord(n[i % nl]))
        return "".join(s)

    def analysis(self, url):
        '''
        实现analysis参数数据
        :param url: 三个榜单的简要url信息,形如'/rank/indexPlus/brand_id/0','/rank/indexPlus/brand_id/1','/rank/indexPlus/brand_id/2'
        :return:
        '''
        # 提取查询参数值并排序
        s = "".join(sorted([str(v) for v in self.params.values()]))
        # Base64 Encode
        s = base64.b64encode(bytes(s, encoding="ascii"))
        # 时间差
        t = str(int((time.time() * 1000) - 1515125653845))

        # 拼接自定义字符串
        s = "@#".join([s.decode(), url, t, "1"])

        # 自定义加密 & Base64 Encode
        s = base64.b64encode(bytes(self.encrypt(a=s), encoding="ascii"))
        return quote(s.decode())

    def run(self):
        '''
        爬取指定页码的APP排行信息,包括免费榜,付费榜,畅销榜
        :return:
        '''
        for page in range(1, PAGE_NUM + 1):
            self.params['page'] = page
            for i in range(3):
                url = self.url + str(i)
                analysis = self.analysis(url)
                # 拼接 URL
                url_splicing = "".join([self.base_url, url, '?analysis=', analysis, '&', urlencode(self.params)])
                print(url_splicing)

                text = self.get_html(url_splicing)
                json_data = json.loads(text)
                print(json_data)

结果如下:

数据爬取结果

详细代码请前往:https://github.com/Acorn2/SpiderCrack/tree/master/qimai

发表评论 取消回复
表情 图片 链接 代码

分享