最近,抖音更新了其加密signature算法,许多爬虫开发者遇到了无法获取数据的困境,本篇文章将详细讲解如何逆向抖音新版signature。
首先,我们需要分析抖音使用的 signature 算法。抖音更新后,使用的 JS 程序进行加密,我们需要通过反编译APP获取该 JS 代码。
我们可以使用 jadx 工具进行反编译,获取抖音APP中 JS 文件:
# 反编译APK
d2j-dex2jar app-debug.apk
# 解压APK
unzip app-debug.apk
# 反编译dex文件
./d2j-dex2jar.sh classes.dex
# 获取JS脚本文件
unzip app-debug.apk assets/index.android.bundle.meta
获取到JS代码后,我们需要进行代码分析,找出signature算法部分:
var r = function(e) {
console.log('r', e);
var t = [];
for (var r = 0; r < e.length; r++) {
var n = e.charCodeAt(r);
128 > n ? t.push(n) : 2048 > n ? t.push(n >> 6 | 192, 63 & n | 128) : 55296 === (64512 & n) && r + 1 < e.length && 56320 === (64512 & e.charCodeAt(r + 1)) ? (n = 65536 + ((1023 & n) << 10) + (1023 & e.charCodeAt(++r)),
t.push(n >> 18 | 240, n >> 12 & 63 | 128, n >> 6 & 63 | 128, 63 & n | 128)) : t.push(n >> 12 | 224, n >> 6 & 63 | 128, 63 & n | 128)
}
return t
}
, i = function(e, t) {
var r = e.length
, i = [];
if (r > 0) {
var o, s = r - 1, a = 0;
while (a < s) {
o = e.charCodeAt(a++) << 16 | e.charCodeAt(a++) << 8 | e.charCodeAt(a++),
i.push(n[63 & o >> 18] + n[63 & o >> 12] + n[63 & o >> 6] + n[63 & o])
}
a === s ? (o = e.charCodeAt(a++) << 16,
i.push(n[63 & o >> 18] + n[63 & o >> 12] + "==")) : a === s - 1 && (o = e.charCodeAt(a++) << 16 | e.charCodeAt(a++) << 8,
i.push(n[63 & o >> 18] + n[63 & o >> 12] + n[63 & o >> 6] + "="))
}
return t + i.join("")
}
var e = 1540802041219
, i = e.toString().substr(0, 10)
, n = r("awemeapi.snssdk.com")
, o = r(window.did)
, s = n.concat(o, i)
, a = md5(String.fromCharCode.apply(null, s)).toString();
console.log("did-raw: ", window.did);
console.log("did-binary: ", o);
console.log("payload: ", s);
console.log("signature: ", a);
这段代码中,可以看到抖音新版signature的生成过程:
awemeapi.snssdk.com
和当前设备的 did
进行数字化处理,并连接生成一个字符串 s
以下将模拟一个Signature和抖音API请求的过程。
示例1:生成Signature
var e = 1540802041219
, i = e.toString().substr(0, 10)
, n = r("awemeapi.snssdk.com")
, o = r(window.did)
, s = n.concat(o, i)
, a = md5(String.fromCharCode.apply(null, s)).toString();
console.log("did-raw: ", window.did);
console.log("did-binary: ", o);
console.log("payload: ", s);
console.log("signature: ", a);
输出结果:
did-raw: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
did-binary: [0, 0, 4, 215, 251, 252, 3, 77, 99, 216, 249, 203, 102, 78, 121, 177, 171, 170, 12]
payload: [97, 119, 101, 109, 101, 97, 112, 105, 46, 115, 110, 115, 115, 100, 107, 46, 99, 111, 109, 0, 0, 4, 215, 251, 252, 3, 77, 99, 216, 249, 203, 102, 78, 121, 177, 171, 170, 12, 49, 53, 40, 48, 41]
signature: 4b8b436ad21912f1ae3b3f58a55a9cd4
示例二:使用生成的 Signature 请求服务器数据
请求接口:
https://aweme.snssdk.com/aweme/v1/general/search/single/?os_api=22&device_type=MI%205s&device_platform=android&ssmix=a&manifest_version_code=530&dpi=480&uuid=2401101112223334445555666677&version_code=530&app_name=aweme&version_name=5.3.0&ts=1547072357&openudid=5acd5496015ac4f5&device_id=65291909062&resolution=1080*1920&os_version=5.1.1&language=zh&count=10&query=%E8%8D%92%E8%8A%B1
其中,我们需要在请求中加入 Signature, 以及请求头 X-Gorgon和X-Khronos , 通过测试获取 %2BH%2BU6doZU3Cu2yAFUt1yKLw3QK2FvAGK1ZiVrZk0ezd2pJ5%2BW49x4ho6kZDFVVYyrg8rbQX50U%2Bx8x4zHSXMQ%3D%3D
这个值。
备注:由于获取到的 did
和 X-Khronos
不是固定值,故在实际的示例中,需要使用实际的值进行替换。
import requests
from datetime import datetime
url = 'https://aweme.snssdk.com/aweme/v1/general/search/single/?os_api=22&device_type=MI%205s&device_platform=android&ssmix=a&manifest_version_code=530&dpi=480&uuid=2401101112223334445555666677&version_code=530&app_name=aweme&version_name=5.3.0&ts=1547072357&openudid=5acd5496015ac4f5&device_id=65291909062&resolution=1080*1920&os_version=5.1.1&language=zh&count=10&query=%E8%8D%92%E8%8A%B1'
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 5.1.1; MI 5s Build/LMY47V; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Mobile Safari/537.36 snssdk=1.9.5',
'Accept-Encoding': 'gzip', 'X-SS-REQ-TICKET': '1547072355820',
'X-Khronos': str(int(datetime.now().timestamp())),
'sdk-version': '1',
'Accept-Language': 'zh-CN',
'X-Gorgon': '040400a3f7b0aea15987e31f8f61e1a7f05b5851ae5f662e3259'
'd5b19fef29da',
'X-SS-DP': '1128',
'X-SS-TC': '0',
'X-SS-RL': '720', 'Cookie': 'install_id=2401101112223334445555666677;m'
'as=008e4006b2f5fda05c843f2eef53fbf17cf2eb6b96f9f92d415b9;ttreq=1$435384d1e7546244397d774cd1d874d88abed46'
}
resp = requests.get(url, headers=headers)
content = resp.content.decode('utf-8')
print(content)
通过以上示例,我们可以了解到抖音新版signature所有的生成细节,以及在制作抖音爬虫时如何正确地请求API接口。
逆向signature是前置条件,经过以上步骤已经有了一定抖音app爬虫的基础了。然后就是最重要的爬虫设计和实现环节,其中最难点就是如何屏蔽抖音app的反爬机制。
本文链接:http://task.lmcjl.com/news/7430.html