背景是由于杭州的房地产数据,由于部分时段,官网做了人机处理没爬取到数据,所以需要用其他数据源来补充一下。

数据缺失部分

china-data/hz-real-estate

image

杭房数据

找了挺久,找到了一款「杭房数据」的微信小程序,数据还比较全,也是拿的官方数据,所以,就简单做个抓取并补充数据。

image

抓取数据

起个 charles 抓包,但可以看到下述的数据是加密的,这就比较麻烦,还要看小程序的解密逻辑。

image

小程序解密逻辑

找到小程序对应的代码

参考 https://blog.csdn.net/qq_39408664/article/details/130824133 得知,微信小程序的打包后缀为 “*.wxapkg”,所以,因为是 Mac,不知道具体路径,所以直接在用户目录扫描找找相关的文件:

~ find . -name "*.wxapkg"
...
find: ./Library/Suggestions: Operation not permitted
find: ./Library/Weather: Operation not permitted
find: ./Library/Group Containers/group.com.apple.secure-control-center-preferences: Operation not permitted
./Library/Group Containers/5A4RE8SF68.com.tencent.xinWeChat/Library/Caches/xinWeChat/58d5d9406c746f0cf847b9ca34f96a2b/WeApp/LocalCache/release/wx451aea80e5b4bae8/29.wxapkg
./Library/Group Containers/5A4RE8SF68.com.tencent.xinWeChat/Library/Caches/xinWeChat/58d5d9406c746f0cf847b9ca34f96a2b/WeApp/LocalCache/release/wx7765bb88a39ee9cb/239.wxapkg
...

成功找到本地对应的小程序包后,就需要确认具体是哪个包文件,方案也很简单

# 打开当前目录
$ open "./Library/Group Containers/5A4RE8SF68.com.tencent.xinWeChat/Library/Caches/xinWeChat/58d5d9406c746f0cf847b9ca34f96a2b/WeApp/LocalCache/release/"

# 1、删除所有小程序包
# 2、在微信中,重新开启对应的小程序
# 3、新创建的文件,就是当前要的小程序包

如下图所示:

image

反编译

其实没有网上 windows 反编译那么麻烦,我们不需要目录结构这些,只需要看对应的加密、解密逻辑即可,所以我们直接用 vscode 打开即可,搜索对应的关键词。

image

并把对应的 define 模块复制格式化出来:

define(
  'A2DD5C571C1F6DDFC4BB345019095B64.js',
  function (
    require,
    module,
    exports,
    window,
    document,
    frames,
    self,
    location,
    navigator,
    localStorage,
    history,
    Caches,
    screen,
    alert,
    confirm,
    prompt,
    XMLHttpRequest,
    WebSocket,
    Reporter,
    webkit,
    WeixinJSCore
  ) {
    'use strict'
    var e = require('@babel/runtime/helpers/interopRequireDefault.js').default
    Object.defineProperty(exports, '__esModule', { value: !0 }),
      (exports.default = void 0)
    var t = e(require('miniprogram_npm/crypto-js/index.js')),
      r = e(require('miniprogram_npm/dayjs/index.js')),
      a = {
        watermarkText: '杭房数据',
        resUrl: 'https://res.hangfang-data.com',
        baseUrl: 'https://api.hangfang-data.com',
        refreshSetting: {
          shake: !1,
          height: 70,
          text: { color: '#969799', shadow: 5 }
        },
        loadMoreSetting: {
          color: '#969799',
          shake: !1,
          status: 'loading',
          more: { text: '上拉加载更多', color: '#969799' },
          loading: { text: '加载中···', color: '#969799' },
          noMore: { text: '-- 没有更多了 --', color: '#969799' }
        },
        systemInfo: function () {
          var e = wx.getSystemInfoSync()
          return {
            height: (750 * e.windowHeight) / e.windowWidth,
            brand: e.brand,
            model: e.model,
            system: e.system,
            version: e.version,
            platform: e.platform
          }
        },
        aesDecrypt: function (e) {
          var a = (0, r.default)().add(-4, 'hour').format('YYYYMMDD')
          a = t.default.MD5(a).toString()
          var o = (0, r.default)().add(-4, 'hour').format('YYYYMMDD')
          ;(o = (o = t.default.MD5(o).toString()).substring(8, 24)),
            (a = t.default.enc.Utf8.parse(a)),
            (o = t.default.enc.Utf8.parse(o))
          var d = t.default.AES.decrypt(e, a, {
            iv: o,
            mode: t.default.mode.CBC,
            padding: t.default.pad.Pkcs7
          })
          return JSON.parse(d.toString(t.default.enc.Utf8))
        }
      }
    exports.default = a
  }
)

总体结构比较清晰,也比较简单,就是使用当前时间作为秘钥来做解密。

核心解密逻辑

import dayjs from 'dayjs'
import crypto from 'crypto-js'

function dec (e) {
  var a = dayjs().add(-4, 'hour').format('YYYYMMDD')
  a = crypto.MD5(a).toString()
  var o = dayjs().add(-4, 'hour').format('YYYYMMDD')
  ;(o = (o = crypto.MD5(o).toString()).substring(8, 24)),
    (a = crypto.enc.Utf8.parse(a)),
    (o = crypto.enc.Utf8.parse(o))
  var d = crypto.AES.decrypt(e, a, {
    iv: o,
    mode: crypto.mode.CBC,
    padding: crypto.pad.Pkcs7
  })
  return JSON.parse(d.toString(crypto.enc.Utf8))
}

小程序解密数据样例

选取一个小数据量的接口

image

做相关的解密操作:

image

小结

从这次小程序的数据爬取中,比较有意思的解密部分的逻辑,有比较大的参考意义,可以作为后续简单的加密操作。

但同时也可以看到,由于 JS 本身就是脚本语言,所以整体的程序安全性是有待加强的。