借助浏览器插件hook一个 知乎网页端 焦点加密算法 做成签名服务器
以下内容仅用于技术交换和提高 如有侵权 私信我 我会立即删除最近在找工作,写写文章记载点能力吧,要否则就真是菜鸟了,我劝以后的萌新也 没事儿研究时写写记载一下 都是吹牛的资源.
前些年在抖音做短视频小说 SD AI绘画 语音合成了 虽然全系列做成了一个统一软件可以比现在市场很多类似的优秀,但是无奈举债多,没有能力再创业了,所以分享一下内容给后来朋友们,后续可能会分享一下抖音剪映语音辨认的接口流程,和抖音豆包AI 全链路API,白嫖算力,看各人热情吧,原业务是抓取知乎的盐故事及时上新内容, 来为做小说创作的朋友们提供一个小说热度帅选的功能.主要维度有两个一个是点赞 一个是评论量,很简单抓取汗青和秒更上新便是.
写了个GUI 界面貌寝勿喷 但是功能实用,这里主要是为了先容知乎的算法的.下面进入正题
https://i-blog.csdnimg.cn/direct/1f0366a192cb4b4e89fc8218507cb3f7.png
抓取之前先先容下大概思路和用到的工具操作流程
知乎的app 很多内容照旧直接使用的web 只是知乎在app中自界说了浏览器头,辨认浏览器让一些内容显示和屏蔽
知乎的web 隐蔽了很多app 的内容但是却暴漏了他们的一些算法缺陷,让我们可以借助web加密来和通过app的api
下面我们将在手机端抓包知乎 使用的工具 有HttpCanary ,VMOS Pro 和 知乎APP
HttpCanary 俗称小黄鸟是手机端的抓包工具,有的时间比pc上的软件好用,情况证书安装 何使用啥的自己去搜吧,
VMOS Pro 是虚拟机可以模仿一个完备的手机系统 这里模仿我们需要留意选择模仿安卓7.1的 64位 这个虚拟机还支持root 一键安装xposed 再加上Frida 什么的爽的不要
为什么要这么做呢就是高版本安卓系统修改加强了ssl 体系认证 导致三方证书无法方便正常使用 ,
如果直接在原机器安装后抓包 抓包工具是无发抓取到知乎任何数据的,
上面这套下来基本市场9成的app都可以抓到了(之前我测试微信竟然可以),但是某些大厂照旧抓不到的 比如抖音 他自己重写了底层网络内容在so里 包罗一些ssl证书认证的内容,可以绕开虚拟机直接和外部通讯.纵然你外部有抓包工具也抓不到,
所以说知乎技术有待提高. 另外再次声明一下 我抓取的知乎数据访问不高哈,不会对服务器造成影响,只是模仿人类正常访问 然后搜集信息用于热度分析,别给我发律师函
看我标题为是那么要借助浏览器插件hook呢,原因很简单,
代码成本低和逆向成本相对低,
操作成本低(有时间测试和测试逆向过成 我们可以动态修改代码 刷新一下就直接进入浏览器情况了,如果用其他方式替换js可能需要借助抓包工具,或者自己写转发抓包拦截工具,比力麻烦)
只需要一个焦点插装就把问题解决了,插件自己 其实也可以直接举行数据处理和网络请求 但是为了节流资源就只有一个浏览器了.不过确实也可以这么做,根据具体场景自己选吧
还有就是为了测试这个方案的可行性,原因是知乎核默算法中包罗很多浏览器情况的信息,所以这是综合选择的结果,所以提取hook他的算法做成服务器,
这样也还可以使加密解耦合 为更大范围的抓取做服务支持如果算法有变 我们都不用改爬虫源代码只要改加密服务器就可以了,不过知乎更新并不是很勤快,用了1年多了这个方法,而且这个方法貌似防爬机制都触发的概率比力低,
来上两章手机截图吧 不一步步演示了
https://i-blog.csdnimg.cn/direct/63d71aa3ad9241548d1fbb74158f2086.png
下边这张图就是 抓包到的数据了 我圈出的api 就是我们目标的api 我筛选的是一些点赞 评论和简洁的信息 其他自己
分析吧,我只是做信息集会,
https://i-blog.csdnimg.cn/direct/a98912dbf4e84694aacc36bd7e2a5fff.png#pic_center
点进去 切换到请求那一栏 所有请求信息都能看到了 多抓几次你会发现真正需要的和变化参数没几个
https://i-blog.csdnimg.cn/direct/1e1a7810373546abab3297050d6c9fb7.png
第一眼肯定是懵逼,多试几次会,然后再结合分享去的web端网页比如 https://www.zhihu.com/xen/market/remix/paid_column/1824095654672261120
1824095654672261120末了一串是小说集 的id
你会发现请求头直接 6个参数就可以了
baseurl = "https://api.zhihu.com/pluton/products/" + ids + "/paid_column/section?offset=" + str( offset) + "&limit=100&order_by=global_idx"
headers = {
"X-Requested-With": "Fetch",
# "X-Zse-96": "2.0_MbKocVal+L2oCq1+4AgxlJU7kBqZd==1/ES8UyXtgHtxbdF1=iCTvBPo3cXLwsEc",
"x-zse-96": "2.0_" + black_code,
"x-zse-93": os_vr,# 不可修改
# user-agent 不重要 可以随意发送命令
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"accept": "*/*",
"cookie": cookie
}
x-zse-96 其中 black_code 是加密值 前边2.0固定版本 我上图是版的显示是1.0 而网页时2.0
x-zse-93 的 os_vr 是情况的版本 这里由于跟的web版本不一样我们选择从浏览器那边动态获取
cookie 是web情况初始化后的辨认信息,不是重点 也从浏览器情况获取就可以了
醒醒啦 主要任务来了
第一步 分析知乎的页面找到算法验证的关键点
在浏览器器调试源码里 找到 vendors.2d292cce3f0653fa0e5e.js
然后搜索 __g._encrypt 结果会出来两个 至于怎么找 不在本次教程范围内 新手可以看我一上篇
能搜索出来两个结果 这里我们只用到第一个 断点刷新一下你们就知道了,这是对上边代码中 baseurl 举行加密的算法
知乎此处比力弱了的点是把这种 关键点api 的值输入和输出 直接暴露了,虽然也是闭包存在,但是我们直接改这里代码就可以修改玉成局可用的算法,其实可以学学抖音 再加密肴杂一次 就不好找了 他这种应该vue编译出来直接上线了那种 毫无防护手段 作为大厂 照旧很不测的写个小工具源代码都能逆向出来
https://i-blog.csdnimg.cn/direct/b8df6a6982ee4913a27a20718874a3eb.png
我们修改方案
function(d){window._encrypt=__g._encrypt;return __g._encrypt(encodeURIComponent(d))})
这样 就把加密算法 提取出来了 时间成本极低 然后 我们就可以用 window._encrypt全局方法做文章了
第二步 写一个浏览器插件 在知乎提取出关键js 放进去 修改指定关键行 然后替换
https://i-blog.csdnimg.cn/direct/c65cab2f5faa4b7db138d97853ebfc18.png
新建文件夹 zhihuchajian 这个文件夹地址 一会儿 浏览器 需要用到
然后按照上述目次创建文件布局
下面我给出文件内容
hoook_manager.js
chrome.webRequest.onBeforeRequest.addListener(
// onBeforeRequest 可见 是再浏览器请求前替换
function(details) {
const url = details.url;
if (url === 'https://static.zhihu.com/xen/productDetailsApps~albumColumnAndMagazine/vendors.2d292cce3f0653fa0e5e.js') {
console.log("vendors.2d292cce3f0653fa0e5e.js")
return {redirectUrl: chrome.extension.getURL("hook_js/vendors.2d292cce3f0653fa0e5e.js")}; //hook.js是你要替换的js脚本
}
return {cancel: false}
},
{urls: ["<all_urls>"], types: ["script"]},
["blocking"] //类型blocking为拦截,
);
manifest.json
{
"name": "知乎HooK",
"version": "1.1",
"manifest_version": 2,
"description": "插件描述.",
"permissions": [
"activeTab",
"storage",
"storage",
"contextMenus",
"notifications",
"tabs",
"webRequest",
"webRequestBlocking",
"https://static.zhihu.com/*",
"https://www.zhihu.com/*"
],
"host_permissions": [
"http://127.0.0.1/*"
],
"browser_action": {
"default_title": "Get Page HTML"
},
"background": {
"scripts": [
"hoook_manager.js"
],
"persistent": true
},
"web_accessible_resources": [
"hook_js/vendors.2d292cce3f0653fa0e5e.js"
]
}
vendors.2d292cce3f0653fa0e5e.js 这个太大 不粘帖了,自己去改吧 .这个方法把我们插件放在编辑器里 修改js 到达了动态修改页面js 的目的 爽的不要不要的 比追栈服从高不少
第三步 启动 web 启动浏览器远程 debuger 模式 并且加载插件
这个浏览器地址是默认安装的位置 留意修改你名字 这是一个 命令行 在桌面新建一个bat 复制进去修改 生存 再启动
C:\Users\你得主机名字\AppData\Local\Google\Chrome\Application\chrome.exe --remote-debugging-port=9222 --user-data-dir="C:selenumAutomationProfile"--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" --load-extension=D:/txt_to_video/zhihu/zhihu_app_api/zhihuchajian
–remote-debugging-port 指定浏览器开发端口 9222
–user-data-dir 指定浏览器情况存储的路径 设置这个可以把一个浏览器当作多个浏览器来用
–user-agent 自界说浏览器头
–load-extension 指定自己的浏览器插件路径
上述操作完成基本就你可以看到 自己的插件了
https://i-blog.csdnimg.cn/direct/facd4cf7fefd40bbb5f6b27ef17efe4d.png
再去访问 知乎网址 https://www.zhihu.com/xen/market/remix/paid_column/1824095654672261120
调试期内 查察源码 就看到
https://i-blog.csdnimg.cn/direct/c9c6cbe05bfc48359bd5e9bf1499dbd8.png
我们的代码见效了,舒畅的玩耍吧, 记得我们的bat 要一直启动不能关闭
第四步 利用python web框 架 暴露一个简单服务,买通浏览器 实验js 完成我们算法认证
其实到这步已经没啥意思了 不过该写还要写 烂作者凑字儿 哈哈 我就贴代码了 看解释吧
主要使用 selenium ,如果selenium 情况和驱动缺失 自行下载安装 学习不做教程
import os
from selenium.webdriver import ChromeOptions
from selenium import webdriver
from flask import Flask
app = Flask(__name__)
chrome_options = ChromeOptions()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
browser = webdriver.Chrome(options=chrome_options)
browser.get("https://www.zhihu.com")
script = """
console.log("#防止爬虫代码 ,最好在 浏览器环境中 使用油猴插件方法 全局在加载前加载此段代码")
Object.defineProperty(navigator,"webdriver",{get:() => false,});
"""
#运行Javascript
browser.execute_script(script)
browser.get("https://www.zhihu.com/xen/market/remix/paid_column/1518918494300667904")
browser.execute_script(script)
monidianji="""
// 选择具有特定class的div元素
var element = document.querySelector('.CatalogModule-allSection-ctqBJ');
// 检查元素是否存在
if (element) {
// 创建一个新的点击事件
var clickEvent = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
// 触发点击事件
element.dispatchEvent(clickEvent);
} else {
console.log('没有找到具有指定class的元素');
}
"""
browser.execute_script(monidianji)
@app.route("/")
def hello_world():
"""Example Hello World route."""
api = """
/get_code/<light_code> return black_code
/get_cookie return current cookie
/get_header return headers
"""
return api
@app.route('/get_cookie', methods=['GET'])
def get_cookie():
javascript_code = """
return JSON.stringify({'cookie': document.cookie})
"""
try:
result = browser.execute_script(javascript_code)
if result:
tata = {
'data': result
}
return tata
else:
return "{'error':'浏览器端出现异常或者环境没有初始化'}"
except Exception as e:
print(e)
return f"{'error':'浏览器端出现异常或者环境没有初始化'}"
@app.route('/get_header', methods=['GET'])
def get_header():
javascript_code = """
var ttsa=new RegExp("d_c0=([^;]+)").exec(document.cookie)
return JSON.stringify({'xUDId':JSON.parse(document.getElementById("resolved").value).appContext.xUDId,'authId':JSON.parse(document.getElementById("resolved").value).appContext.authId,'otherId':ttsa,'cookie':document.cookie,'userAgent':navigator.userAgent})
"""
try:
result = browser.execute_script(javascript_code)
if result:
tata={
'data': result
}
return tata
else:
return "{'error':'浏览器端出现异常或者环境没有初始化'}"
except Exception as e:
print(e)
return "{'error':'浏览器端出现异常或者环境没有初始化'}"
@app.route('/get_code/<light_code>', methods=['GET'])
def get_data(light_code):
javascript_code = """
// JavaScript代码示例
//alert('Hello World!');
if(undefined!=window._encrypt){
var tt=window._encrypt(encodeURIComponent('"""
ttff = """'))
console.log(tt)
return tt
}else{
console.log('环境window._encrypt没有设置')
console.log('定义为代码 return __g._encrypt(encodeURIComponent(d))')
console.log('return __g._encrypt(encodeURIComponent(d))')
console.log('window._encrypt=__g._encrypt')
// 选择具有特定class的div元素
var element = document.querySelector('.CatalogModule-allSection-ctqBJ');
// 检查元素是否存在
if (element) {
// 创建一个新的点击事件
var clickEvent = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
// 触发点击事件
element.dispatchEvent(clickEvent);
} else {
console.log('没有找到具有指定class的元素');
}
}
"""
# zhihu = ZhiHu()
# code = zhihu.get_pinglun("1716821153832767488")
if light_code==None or light_code=='':
return "{'error':'light_code参数异常浏览器端出现异常或者环境没有初始化'}"
javascript_code = javascript_code + light_code + ttff
try:
result = browser.execute_script(javascript_code)
if result:
tata={
'data': result
}
return tata
else:
return "{'error':'浏览器端出现异常或者环境没有初始化'}"
except Exception as e:
print(e)
return "{'error':'浏览器端出现异常或者环境没有初始化'}"
if __name__ == "__main__":
print( 'return __g._encrypt(encodeURIComponent(d))')
print('window._encrypt=__g._encrypt')
# app.run(port=8080)
app.run(debug=False, host="0.0.0.0", port=int(os.environ.get("PORT", 7355)))
# app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
# web框架 使用请参考 https://blog.csdn.net/weixin_38037405/article/details/127149032
#app.run(host='0.0.0.0', port=80, debug=True)
# browser.quit()
以上代码弄完还不能正常运行 不过大的操作情况 已经就位 为了给知乎留点面子不写了
但是给各人一点提示
def get_data(light_code):
这个方法我们接收的 light_code 是有固定算法需要计算的不需要浏览器情况 ,不过我提供的关键点 你们向上追栈是可以找到的
流程是 大概就是这几个参数 说到这里自己去搜这几个关键参数就应该找到了 这些一起计算一个明码值 再传给浏览器加密依赖一些浏览器动态信息加密给出暗码 ,再通通过浏览器头发送get 请求,这里就完成了逆向 可以舒畅爬了
# os_vr = “101_3_3.1”
# story_id = “1716821153832767488”
# url_api = f"/pluton/products/{story_id}/paid_column/section"
# authId = “7481a31d25d73bfc1edf9240df687cf9”
这样我们就可以自己动态修改请求 也可以 还不去关注浏览器内登录信息了 暴露的服务还可以解耦给其他 分布式服务使用 就是一个快乐
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]