爬虫prc技术----小红书爬取解决xs

知识星球:知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具知识星球是创作者连接铁杆粉丝,实现知识变现的工具。任何从事创作或艺术的人,例如艺术家、工匠、教师、学术研究、科普等,只要能获得一千位铁杆粉丝,就足够生计无忧,自由创作。社群管理、内容沉淀、链接粉丝等就在知识星球。icon-default.png?t=O83Ahttps://articles.zsxq.com/id_5x1m9wdv3e20.html

目录

知识星球:知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具知识星球是创作者连接铁杆粉丝,实现知识变现的工具。任何从事创作或艺术的人,例如艺术家、工匠、教师、学术研究、科普等,只要能获得一千位铁杆粉丝,就足够生计无忧,自由创作。社群管理、内容沉淀、链接粉丝等就在知识星球。https://articles.zsxq.com/id_5x1m9wdv3e20.html

一,什么是websocket

二,websocket的原理

三,websocket与http的关系

四,websocket解决的问题

1.http存在的问题

2.long poll(长轮询)

3.Ajax轮询

4.websocket的改进

五 websocket实现方式

1. 客户端

2.服务端

六。案例

效果

具体代码:

RPC

1. RPC 简介

2.Sekiro-RPC

1. 使用方法

2. 测试使用

3.案例


一,什么是websocket

WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)

它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的

Websocket是一个持久化的协议

二,websocket的原理

websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信

在websocket出现之前,web交互一般是基于http协议的短连接或者长连接

websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"

三,websocket与http的关系

相同点:

都是基于tcp的,都是可靠性传输协议

都是应用层协议

不同点:

WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息

HTTP是单向的

WebSocket是需要浏览器和服务器握手进行建立连接的

而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接

联系:

WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的

总结(总体过程):

首先,客户端发起http请求,经过3次握手后,建立起TCP连接;http请求里存放WebSocket支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等;

然后,服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据;

最后,客户端收到连接成功的消息后,开始借助于TCP传输信道进行全双工通信。

四,websocket解决的问题

1.http存在的问题

http是一种无状态协议,每当一次会话完成后,服务端都不知道下一次的客户端是谁,需要每次知道对方是谁,才进行相应的响应,因此本身对于实时通讯就是一种极大的障碍

http协议采用一次请求,一次响应,每次请求和响应就携带有大量的header头,对于实时通讯来说,解析请求头也是需要一定的时间,因此,效率也更低下

最重要的是,需要客户端主动发,服务端被动发,也就是一次请求,一次响应,不能实现主动发送

2.long poll(长轮询)

对于以上情况就出现了http解决的第一个方法——长轮询

基于http的特性,简单点说,就是客户端发起长轮询,如果服务端的数据没有发生变更,会 hold 住请求,直到服务端的数据发生变化,或者等待一定时间超时才会返回。返回后,客户端又会立即再次发起下一次长轮询

优点是解决了http不能实时更新的弊端,因为这个时间很短,发起请求即处理请求返回响应,实现了“伪·长连接”

张三取快递的例子,张三今天一定要取到快递,他就一直站在快递点,等待快递一到,立马取走

从例子上来看有个问题:

假如有好多人一起在快递站等快递,那么这个地方是否足够大,(抽象解释:需要有很高的并发,同时有很多请求等待在这里)

总的来看:

推送延迟。服务端数据发生变更后,长轮询结束,立刻返回响应给客户端。

服务端压力。长轮询的间隔期一般很长,例如 30s、60s,并且服务端 hold 住连接不会消耗太多服务端资源。

3.Ajax轮询

基于http的特性,简单点说,就是规定每隔一段时间就由客户端发起一次请求,查询有没有新消息,如果有,就返回,如果没有等待相同的时间间隔再次询问

优点是解决了http不能实时更新的弊端,因为这个时间很短,发起请求即处理请求返回响应,把这个过程放大n倍,本质上还是request = response

举个形象的例子(假设张三今天有个快递快到了,但是张三忍耐不住,就每隔十分钟给快递员或者快递站打电话,询问快递到了没,每次快递员就说还没到,等到下午张三的快递到了,but,快递员不知道哪个电话是张三的,(可不是只有张三打电话,还有李四,王五),所以只能等张三打电话,才能通知他,你的快递到了)

从例子上来看有两个问题:

假如说,张三打电话的时间间隔为10分钟,当他收到快递前最后一次打电话,快递员说没到,他刚挂掉电话,快递入库了(就是到了),那么等下一次时间到了,张三打电话知道快递到了,那么这样的通讯算不算实时通讯?很显然,不算,中间有十分钟的时间差,还不算给快递员打电话的等待时间(抽象的解释:每次request的请求时间间隔等同于十分钟,请求解析相当于等待)

假如说张三所在的小区每天要收很多快递,每个人都采取主动给快递员打电话的方式,那么快递员需要以多快的速度接到,其他人打电话占线也是问题(抽象解释:请求过多,服务端响应也会变慢)

总的来看,Ajax轮询存在的问题:

推送延迟。

服务端压力。配置一般不会发生变化,频繁的轮询会给服务端造成很大的压力。

推送延迟和服务端压力无法中和。降低轮询的间隔,延迟降低,压力增加;增加轮询的间隔,压力降低,延迟增高

4.websocket的改进

一旦WebSocket连接建立后,后续数据都以帧序列的形式传输。在客户端断开WebSocket连接或Server端中断连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实现了“真·长链接”,实时性优势明显。

五 websocket实现方式

1. 客户端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<input id="box" type="text">
<button onclick="ps()">发送</button><script>// 与服务器约定的连接 以及端口  本机的   hosts文件  localhost      www.ps.comconst websocket = new WebSocket('ws://127.0.0.1:8080/')//连接发生错误的回调方法websocket.onerror = () => {console.log("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function () {console.log("WebSocket连接成功");}//接收到消息的回调方法  接收服务器的数据websocket.onmessage = function (event) {console.log(event.data);}//连接关闭的回调方法websocket.onclose = function () {console.log("WebSocket连接关闭");}function ps() {// jquery -> val   JS -> valuevar text = document.getElementById('box').value// 客户端发信息发服务器websocket.send(text)}</script>
</body>
</html>

2.服务端

# encoding: utf-8
import asyncio
import websocketsasync def echo(websocket):# 使用WebSocket在客户端和服务器之间建立全双工双向连接后,就可以在连接打开时调用send()方法。message = 'hello world'# 发送数据await websocket.send(message)return Trueasync def recv_msg(websocket):while 1:# 接收数据recv_text = await websocket.recv()print(recv_text)async def main_logic(websocket, path):await echo(websocket)await recv_msg(websocket)start_server = websockets.serve(main_logic, '127.0.0.1', 8080)
loop = asyncio.get_event_loop()
loop.run_until_complete(start_server)
# 创建了一个连接对象之后,需要不断监听返回的数据,则调用 run_forever 方法,要保持长连接即可
loop.run_forever()

六。案例

基于此我们可以本地替换实时获取数据

案例网站:https://www.xiaohongshu.com

我们利用爬虫工具库-spidertools.cn快速构建请求

import requests
import jsonheaders = {"accept": "application/json, text/plain, */*","accept-language": "zh-CN,zh;q=0.9","cache-control": "no-cache","content-type": "application/json;charset=UTF-8","origin": "https://www.xiaohongshu.com","pragma": "no-cache","priority": "u=1, i","referer": "https://www.xiaohongshu.com/","sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "\"Windows\"","sec-fetch-dest": "empty","sec-fetch-mode": "cors","sec-fetch-site": "same-site","user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36","x-b3-traceid": "4a3e0e2edcd69a5a","x-s": "XYW_eyJzaWduU3ZuIjoiNTUiLCJzaWduVHlwZSI6IngyIiwiYXBwSWQiOiJ4aHMtcGMtd2ViIiwic2lnblZlcnNpb24iOiIxIiwicGF5bG9hZCI6ImU5ZTczMzdlOTZiNGRmMTVkYTJjNDAyNWM3ZjIzNzRmZGQxMjc1ZmE5YWEyNWVjYzJiMmVjN2MxYjBmYmRlYjFkMzc1YmJjM2Y2MzZmZGQ5MTAxYmI5NDc0NDE0OTQzOTI5YmEwYTQwOGUxYmVmZTQ4NTA2ZGNkZGY0OWFhMzE4ZTY5Mzc3NjU0ODdhOWVlMTFhYTgwNWM0NDg5NDNkNjcwMmI2OTk4NmE2OTk1Nzc1ZTM4ZTkzMTdjN2EyNWMxMjNiYzM0Y2Y4OTVkMTA0NmE3YTAyZGQzZGIwMWUwZmI0ODdmZTU4NjZhNmQ2ZDBlMjk5YTUwOWZlNWE4ZDMyZjU3ZTM1ZmFmYTY0YjY1MDViYzBmYTBmYmU5YjlkZjVlM2ExNmQ0NmM0NTkwMDY3ZDI3YjNlZGZlZDI5MDg0NGE4OWUxYTIxODc1ZjRlN2I1OTc5MTRhYmE1MjVlNGVmMThjYzBiODkyZjA3ZmEwNTg2NjIxOGYyZmQzZThhOWY2OTcyYWQ3NjcyMmQwMjM1ZTQ1MjE2MWFlZDBkZWUxODQ1In0=","x-s-common": "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","x-t": "1727942080882","x-xray-traceid": "c928afdcb6b114122d4b8c7d18662d5e"
}
cookies = {}
url = "https://edith.xiaohongshu.com/api/sns/web/v1/homefeed"
data = {"cursor_score": "","num": 47,"refresh_type": 1,"note_index": 34,"unread_begin_note_id": "","unread_end_note_id": "","unread_note_count": 0,"category": "homefeed.food_v3","search_key": "","need_num": 22,"image_formats": ["jpg","webp","avif"],"need_filter_image": False
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, cookies=cookies, data=data)print(response.text)
print(response)

据包是homefeed

其中有X-s和X-s-common进行了加密

我们查找X-s赋值位置即可,全局搜索

其中x-s和x-t是由window._webmsxyw(c, i)生成的,其中c为'/api/sns/web/v1/homefeed',t为查询参数

比如

data = {"cursor_score": "","num": 39,"refresh_type": 1,"note_index": 34,"unread_begin_note_id": "","unread_end_note_id": "","unread_note_count": 0,"category": "binggaokao_feed_recommend","search_key": "","need_num": 14,"image_formats": ["jpg","webp","avif"],"need_filter_image": false
}

那么我们直接利用websocket借用浏览器的环境处理,本地替换

效果

具体代码:

本地替换

 !(function () {if (window.flag) {} else {const websocket = new WebSocket('ws://127.0.0.1:8080')// 创建一个标记用来判断是否创建套接字window.flag = true;//连接发生错误的回调方法websocket.onerror = () => {console.log("WebSocket连接发生错误");};//连接成功建立的回调方法websocket.onopen = function () {console.log("WebSocket连接成功");}//接收到消息的回调方法  接收服务器的数据websocket.onmessage = function (event) {console.log(event.data);}//连接关闭的回调方法websocket.onclose = function () {console.log("WebSocket连接关闭");}//  接收服务端发送的信息websocket.onmessage = function (event) {
。。。。。。。。。。。。。。。。。具体见知识星球}}}())

服务端

。。。。。。。。。。。。。。。。。具体见知识星球

利用rpc获取数据

RPC

1. RPC 简介

为什么要使用RPC技术呢?我们在使用websocket时候可以发现,python在操作的时候,需要创建连接,还需要不断去接受传递数据,非常的麻烦, 那这个时候rpc技术可以帮助到我们,简单来说就是网页直接和rpc服务器进行交互,我们python可以直接调用,rpc暴露的接口,不需要关心,创建连接这一块的问题.

RPC 技术是非常复杂的,对于我们搞爬虫、逆向的来说,不需要完全了解,只需要知道这项技术如何在逆向中应用就行了。

RPC 在逆向中,简单来说就是将本地和浏览器,看做是服务端和客户端,二者之间通过 WebSocket 协议进行 RPC 通信,在浏览器中将加密函数暴露出来,在本地直接调用浏览器中对应的加密函数,从而得到加密结果,不必去在意函数具体的执行逻辑,也省去了扣代码、补环境等操作,可以省去大量的逆向调试时间。

2.Sekiro-RPC

  • 官网地址:私有API导出框架 | sekiro
1. 使用方法

1. 执行方式

  • 在本地开启服务端
  • 需要有 Java 环境,配置参考:百度安全验证
    • 下载地址:Index of java-local/jdk/8u201-b09
  • Linux & Mac:bin/sekiro.sh 双击打开服务端
  • Windows:bin/sekiro.bat 双击打开服务端

2.客户端环境

  • 地址:file.virjar.com/sekiro_web_client.js?_=123 这个地址是在前端创建客户端的时候需要用到的代码,Sekiro-RPC 把他封装在一个地址里面了

3.使用参数说明

  • 使用原理:客户端注入到浏览器环境,然后通过SekiroClient和 Sekiro服务器通信,即可直接 RPC 调用浏览器内部方法,官方提供的SekiroClient 代码样例如下:
// 生成唯一标记uuid编号
function guid() {function S4() {return (((1+Math.random())*0x10000)|0).toString(16).substring(1);}return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
// 连接服务端
var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=ws-group&clientId="+guid());
// 业务接口 
client.registerAction("登陆",function(request, resolve, reject){resolve(""+new Date());
})
 
  • group:业务类型(接口组),每个业务一个 group,group 下面可以注册多个终端(SekiroClient),同时group 可以挂载多个 Action;
  • clientId:指代设备,多个设备使用多个机器提供 API 服务,提供群控能力和负载均衡能力;
  • SekiroClient:服务提供者客户端,主要场景为手机/浏览器等。最终的 Sekiro 调用会转发到 SekiroClient。每个client 需要有一个惟一的 clientId;
  • registerAction:接口,同一个 group 下面可以有多个接口,分别做不同的功能;
  • resolve:将内容传回给服务端的方法;
  • request:服务端传过来的请求,如果请求里有多个参数,可以以键值对的方式从里面提取参数然后再做处理。

2. 测试使用

1. 前端代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
​
<script src="http://file.virjar.com/sekiro_web_client.js?_=123"></script>
<script>function guid() {function S4() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);}
​return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());}
​var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=rpc-test&clientId=" + guid());
​client.registerAction("clientTime", function (request, resolve, reject) {resolve("" + new Date());})
​
</script>
</body>
</html>

2. SK API

Sekiro 为我们提供了一些 API

  • 查看分组列表:http://127.0.0.1:5620/business-demo/groupList
  • 查看队列状态:http://127.0.0.1:5620/business-demo/clientQueue?group=rpc-test
  • 调用转发:http://127.0.0.1:5620/business-demo/invoke?group=rpc-test&action=clientTime

3.python调用代码

import requests
​
params = {"group": "rpc-test","action": "clientTime",
}
res = requests.get("http://127.0.0.1:5620/business-demo/invoke", params=params)
print(res.text)
​

3.案例

案例还是上一个

首先打开服务端

  • 确定好位置之后我们就可以替换当前文件,把我们需要的rpc的代码给注入到网页中
  • JavaScript代码
(function () {function SekiroClient(wsURL) {this.wsURL = wsURL;this.handlers = {};this.socket = {};this.base64 = false;// checkif (!wsURL) {throw new Error('wsURL can not be empty!!')}this.webSocketFactory = this.resolveWebSocketFactory();this.connect()}SekiroClient.prototype.resolveWebSocketFactory = function () {if (typeof window === 'object') {var theWebSocket = window.WebSocket ? window.WebSocket : window.MozWebSocket;return function (wsURL) {function WindowWebSocketWrapper(wsURL) {this.mSocket = new theWebSocket(wsURL);}WindowWebSocketWrapper.prototype.close = function () {this.mSocket.close();};WindowWebSocketWrapper.prototype.onmessage = function (onMessageFunction) {this.mSocket.onmessage = onMessageFunction;};WindowWebSocketWrapper.prototype.onopen = function (onOpenFunction) {this.mSocket.onopen = onOpenFunction;};WindowWebSocketWrapper.prototype.onclose = function (onCloseFunction) {this.mSocket.onclose = onCloseFunction;};WindowWebSocketWrapper.prototype.send = function (message) {this.mSocket.send(message);};return new WindowWebSocketWrapper(wsURL);}}if (typeof weex === 'object') {// this is weex env : https://weex.apache.org/zh/docs/modules/websockets.htmltry {console.log("test webSocket for weex");var ws = weex.requireModule('webSocket');console.log("find webSocket for weex:" + ws);return function (wsURL) {try {ws.close();} catch (e) {}ws.WebSocket(wsURL, '');return ws;}} catch (e) {console.log(e);//ignore}}//TODO support ReactNativeif (typeof WebSocket === 'object') {return function (wsURL) {return new theWebSocket(wsURL);}}// weex 鍜� PC鐜鐨剋ebsocket API涓嶅畬鍏ㄤ竴鑷达紝鎵€浠ュ仛浜嗘娊璞″吋瀹�throw new Error("the js environment do not support websocket");};SekiroClient.prototype.connect = function () {console.log('sekiro: begin of connect to wsURL: ' + this.wsURL);var _this = this;// 涓峜heck close锛岃// if (this.socket && this.socket.readyState === 1) {//     this.socket.close();// }try {this.socket = this.webSocketFactory(this.wsURL);} catch (e) {console.log("sekiro: create connection failed,reconnect after 2s");setTimeout(function () {_this.connect()}, 2000)}this.socket.onmessage(function (event) {_this.handleSekiroRequest(event.data)});this.socket.onopen(function (event) {console.log('sekiro: open a sekiro client connection')});this.socket.onclose(function (event) {console.log('sekiro: disconnected ,reconnection after 2s');setTimeout(function () {_this.connect()}, 2000)});};SekiroClient.prototype.handleSekiroRequest = function (requestJson) {console.log("receive sekiro request: " + requestJson);var request = JSON.parse(requestJson);var seq = request['__sekiro_seq__'];if (!request['action']) {this.sendFailed(seq, 'need request param {action}');return}var action = request['action'];if (!this.handlers[action]) {this.sendFailed(seq, 'no action handler: ' + action + ' defined');return}var theHandler = this.handlers[action];var _this = this;try {theHandler(request, function (response) {try {_this.sendSuccess(seq, response)} catch (e) {_this.sendFailed(seq, "e:" + e);}}, function (errorMessage) {_this.sendFailed(seq, errorMessage)})} catch (e) {console.log("error: " + e);_this.sendFailed(seq, ":" + e);}};SekiroClient.prototype.sendSuccess = function (seq, response) {var responseJson;if (typeof response == 'string') {try {responseJson = JSON.parse(response);} catch (e) {responseJson = {};responseJson['data'] = response;}} else if (typeof response == 'object') {responseJson = response;} else {responseJson = {};responseJson['data'] = response;}if (typeof response == 'string') {responseJson = {};responseJson['data'] = response;}if (Array.isArray(responseJson)) {responseJson = {data: responseJson,code: 0}}if (responseJson['code']) {responseJson['code'] = 0;} else if (responseJson['status']) {responseJson['status'] = 0;} else {responseJson['status'] = 0;}responseJson['__sekiro_seq__'] = seq;var responseText = JSON.stringify(responseJson);console.log("response :" + responseText);if (responseText.length < 1024 * 6) {this.socket.send(responseText);return;}if (this.base64) {responseText = this.base64Encode(responseText)}//澶ф姤鏂囪鍒嗘浼犺緭var segmentSize = 1024 * 5;var i = 0, totalFrameIndex = Math.floor(responseText.length / segmentSize) + 1;for (; i < totalFrameIndex; i++) {var frameData = JSON.stringify({__sekiro_frame_total: totalFrameIndex,__sekiro_index: i,__sekiro_seq__: seq,__sekiro_base64: this.base64,__sekiro_is_frame: true,__sekiro_content: responseText.substring(i * segmentSize, (i + 1) * segmentSize)});console.log("frame: " + frameData);this.socket.send(frameData);}};SekiroClient.prototype.sendFailed = function (seq, errorMessage) {if (typeof errorMessage != 'string') {errorMessage = JSON.stringify(errorMessage);}var responseJson = {};responseJson['message'] = errorMessage;responseJson['status'] = -1;responseJson['__sekiro_seq__'] = seq;var responseText = JSON.stringify(responseJson);console.log("sekiro: response :" + responseText);this.socket.send(responseText)};SekiroClient.prototype.registerAction = function (action, handler) {if (typeof action !== 'string') {throw new Error("an action must be string");}if (typeof handler !== 'function') {throw new Error("a handler must be function");}console.log("sekiro: register action: " + action);this.handlers[action] = handler;return this;};SekiroClient.prototype.encodeWithBase64 = function () {this.base64 = arguments && arguments.length > 0 && arguments[0];};SekiroClient.prototype.base64Encode = function (s) {if (arguments.length !== 1) {throw "SyntaxError: exactly one argument required";}s = String(s);if (s.length === 0) {return s;}function _get_chars(ch, y) {if (ch < 0x80) y.push(ch);else if (ch < 0x800) {y.push(0xc0 + ((ch >> 6) & 0x1f));y.push(0x80 + (ch & 0x3f));} else {y.push(0xe0 + ((ch >> 12) & 0xf));y.push(0x80 + ((ch >> 6) & 0x3f));y.push(0x80 + (ch & 0x3f));}}var _PADCHAR = "=",_ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",_VERSION = "1.1";//Mr. Ruan fix to 1.1 to support asian char(utf8)//s = _encode_utf8(s);var i,b10,y = [],x = [],len = s.length;i = 0;while (i < len) {_get_chars(s.charCodeAt(i), y);while (y.length >= 3) {var ch1 = y.shift();var ch2 = y.shift();var ch3 = y.shift();b10 = (ch1 << 16) | (ch2 << 8) | ch3;x.push(_ALPHA.charAt(b10 >> 18));x.push(_ALPHA.charAt((b10 >> 12) & 0x3F));x.push(_ALPHA.charAt((b10 >> 6) & 0x3f));x.push(_ALPHA.charAt(b10 & 0x3f));}i++;}switch (y.length) {case 1:var ch = y.shift();b10 = ch << 16;x.push(_ALPHA.charAt(b10 >> 18) + _ALPHA.charAt((b10 >> 12) & 0x3F) + _PADCHAR + _PADCHAR);break;case 2:var ch1 = y.shift();var ch2 = y.shift();b10 = (ch1 << 16) | (ch2 << 8);x.push(_ALPHA.charAt(b10 >> 18) + _ALPHA.charAt((b10 >> 12) & 0x3F) + _ALPHA.charAt((b10 >> 6) & 0x3f) + _PADCHAR);break;}return x.join("");};function startRpc() {if (window.flag) {} else {function guid() {function S4() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);}return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());}// 创建一个标记用来判断是否创建套接字window.flag = true;var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=rpc-test&clientId=" + guid());client.registerAction("ths", function (request, resolve, reject) {resolve(rt.update());})}}setTimeout(startRpc, 1000)
})()

别看这么长,实际要改的代码只有

 var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=rpc-xhs&clientId=" + guid());client.registerAction("xhs", function (request, resolve, reject) {var data=request['data'];// console.log(data)data=JSON.parse(data)console.log(data)var res=window._webmsxyw('/api/sns/web/v1/homefeed',data)res=JSON.stringify(res)resolve(res);

这样既开启成功了

接下来调用即可

代码

具体看知识星球

效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/445040.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JVM】如何判断对象是否可以被回收

引用计数法&#xff1a; 在对象中添加一个引用计数器&#xff0c;每当有一个地方引用它时&#xff0c;计数器值就加一&#xff1b;当引用失效时&#xff0c;计数器值就减一&#xff1b;任何时刻计数器为零的对象就是不可能再被使用的。 优点&#xff1a;实现简单&#xff0c;判…

5G NR BWP 简介

文章目录 BWP介绍BWP 分类BWP相关总结 BWP介绍 5G NR 系统带宽比4G LTE 大了很多&#xff0c;4G LTE 最大支持带宽为20MHz&#xff0c; 而5G NR 的FR1 最大支持带宽为100MH在&#xff0c; FR2 最大支持带宽为 400MH在。带宽越大&#xff0c;意味了终端功耗越多。为了减少终端的…

Nginx的正向与反向代理

一、Nginx简介 1. 什么是Nginx Nginx&#xff08;发音为“engine-x”&#xff09;是一个高性能的HTTP和反向代理服务器&#xff0c;同时也是一个IMAP/POP3/SMTP代理服务器。Nginx是由俄罗斯的Igor Sysoev&#xff08;伊戈尔赛索耶夫&#xff09;为解决C10k问题&#xff08;即…

下一代安全:融合网络和物理策略以实现最佳保护

在当今快速发展的技术环境中&#xff0c;网络和物理安全融合变得比以往任何时候都更加重要。随着物联网 (IoT) 和工业物联网 (IIoT) 的兴起&#xff0c;组织在保护数字和物理资产方面面临着独特的挑战。 本文探讨了安全融合的概念、说明其重要性的实际事件以及整合网络和物理安…

RNN心脏病预测

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 前期准备 1.数据导入 import pandas as pd from keras.optimizers import Adam from matplotlib import pyplot as plt from sklearn.model_selection import train_test_split from sklearn.p…

构建高效互通的数字桥梁:香港服务器托管指南

在当今全球化日益加深的商业环境中&#xff0c;出海企业面临着前所未有的机遇与挑战。为了确保国内外业务的顺畅运行&#xff0c;特别是在实现国内外数据高效互通、低延迟访问方面&#xff0c;选择一家合适的香港服务器机房进行托管成为了许多企业的关键决策之一。香港&#xf…

网络协议——IP协议

一、IPv4 1、IPv4&#xff1a;TCP/IP协议规定&#xff0c;IPv4地址使用32位的二进制表示&#xff0c;也就是4个字节&#xff0c;为了方便使用&#xff0c;IPv4地址被写成十进制形式&#xff0c;中间用”.”分开。 【点分十进制表示法】 2、IPv4地址分类 2.1 私有地址在互联网…

基于DSP+ARM+FPGA的电能质量分析仪的软件设计

软件设计是电能质量设备的核心内容&#xff0c;上述章节详细介绍了电能质量参数的 算法&#xff0c;并且通过仿真实验进行了验证&#xff0c;本章将结合现代电能质量监测设备需求实 现算法在实际电网中应用。根据设计的电能质量分析仪的需求分析&#xff0c;进行总体的 软件…

英特尔新旗舰 CPU 将运行更凉爽、更高效,适合 PC 游戏

英特尔终于解决了台式机 CPU 发热和耗电的问题。英特尔的新旗舰 Core Ultra 200S 系列处理器将于 10 月 24 日上市&#xff0c;该系列专注于每瓦性能&#xff0c;比之前的第 14 代芯片运行更凉爽、更高效。这些代号为 Arrow Lake S 的处理器也是英特尔首款内置 NPU&#xff08;…

【笔记】自动驾驶预测与决策规划_Part5_决策过程(上)

决策过程 0. 前言1.决策过程的引入1.1有了planning&#xff0c;为什么还需要decision-making&#xff1f;1.2 决策规划的一些思考 2.马尔可夫决策过程及其关键要素2.1 马尔可夫过程2.1.1 什么是随机过程&#xff1f;2.1.2 什么是马尔科夫性&#xff1f;2.1.3 马尔可夫决策过程 …

从commit校验失效问题探究husky原理

一、背景 之前创建的项目&#xff0c;发现代码 commit 提交的时候没有了任何校验&#xff0c;具体表现&#xff1a; 一是 feat fix 等主题格式校验没有了二是代码 lint 不通过也能提交 尝试解决这个问题&#xff0c;并深入了解husky的实现原理&#xff0c;将相关的一些知识点…

PMP--冲刺题--解题--161-170

文章目录 4.整合管理--1.制定项目章程--当各方的认知、理解、掌握的信息不一致的时候&#xff0c;相对最好的方法就是共同确认项目相关文件/计划中的具体内容&#xff08;是否项目真的存在这个交付物&#xff09;。161、 [单选] 在一个与高级经理的项目状态会议中&#xff0c;项…

动态规划-路径问题——931.下降路径最小和

1.题目解析 题目来源&#xff1a;931.下降路径最小和——力扣 测试用例 2.算法原理 1.状态表示 我们可以开辟一个dp表&#xff0c;多开辟一行两列用来存储虚拟位置&#xff0c;dp[i][j]表示从第一行到该位置的最小路径和 2.状态转移方程 由于要找到最小路径和&#xff0c;并且由…

springboot将logback替换成log4j2

一 为何要替换成log4j2 1.1 log4j2的优点 log4j2使用了两种方式记录日志&#xff1a;AsyncAppender和AsyncLogger。 1.AsyncAppender使用队列异步记录日志&#xff0c;但是一旦队列已满&#xff0c;appender线程需要等待。2.AsyncLogger是采用Disruptor&#xff0c;通过环形…

Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起)

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读AMS通过startActivity启动Activity的整个流程的整个流程的第二阶段&#xff1a;从ActivityThread启动到Activity拉起。 第一阶段文…

【Unity精品源码】打造甜蜜的三消游戏:Candy Match 3 Kit

最近总熬夜&#xff0c;肝不好&#xff0c;大家都叫我小心肝。 &#x1f4c2; Unity 开发资源汇总 | 插件 | 模型 | 源码 &#x1f493; 欢迎访问 Unity 打怪升级大本营 在游戏开发的世界中&#xff0c;三消游戏以其简单易上手、趣味性强的特点&#xff0c;一直深受玩家喜爱。…

【HTTPS】深入解析 https

我的主页&#xff1a;2的n次方_ 1. 背景介绍 在使用 http 协议的时候是不安全的&#xff0c;可能会出现运营商劫持等安全问题&#xff0c;运营商通过劫持 http 流量&#xff0c;篡改返回的网页内容&#xff0c;例如广告业务&#xff0c;可能会通过 Referer 字段 来统计是…

第十一章 缓存之更新/穿透/雪崩/击穿

目录 一、什么是缓存 二、缓存更新策略 2.1. 缓存主动更新策略 2.1.1. Cache Aside模式&#xff08;主流&#xff09;‌ 2.1.2. Read/Write Through模式‌ 2.1‌.3. Write Behind模式‌ 2.1.4. 总结 三、缓存穿透 四、缓存雪崩 五、缓存击穿 5.1. 互斥锁实现 5.1.1…

Elasticsearch学习笔记(五)Elastic stack安全配置二

一、手动配置http层SSL 通过前面的配置&#xff0c;我们为集群传输层手动配置了TLS&#xff0c;集群内部节点之间的通信使用手动配置的证书进行加密&#xff0c;但是集群与外部客户端的http层目前还是使用的自动配置&#xff0c;集群中HTTP的通信目前仍然使用自动生成的证书ht…

SQL Injection | MySQL 数据库概述

关注这个漏洞的其他相关笔记&#xff1a;SQL 注入漏洞 - 学习手册-CSDN博客 0x01&#xff1a;MySQL 数据库简介 MySQL 是一个流行的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它基于 SQL &#xff08;Structured Query Language&#xff09;进行操作。My…