├── requirements.txt ├── config.json ├── README.md ├── dome.py ├── config.py └── rpc_drive.py /requirements.txt: -------------------------------------------------------------------------------- 1 | requests~=2.32.3 2 | psutil~=5.9.1 3 | DrissionPage~=4.0.4.24 4 | config~=0.5.1 5 | loguru~=0.6.0 6 | Flask~=2.2.2 -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "ON_OFF": true, 3 | "USER_DATA_PATH": "chrome_data", 4 | "BROWSER_PATH": "C:/Program Files/Google/Chrome/Application/chrome.exe", 5 | "URL": "https://****.com", 6 | "COOKIES": {} 7 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js_rpc_drive 2 | js逆向通杀免补环境工具(操作简单) 3 | 支持高并发 毫秒级响应 4 | 环境安装: 5 | pip install -r requirements.txt 6 | config.json 配置详解: 7 | ON_OFF 是否无头 8 | USER_DATA_PATH 浏览器临时缓存地址(可以不动) 9 | BROWSER_PATH 浏览器安装路径 10 | URL 网站地址 11 | COOKIES 网站cookies(不需要填{}即可) 12 | 扣的js文件放入jsdata文件 运行rpc_drive 即可 13 | 调用详情见 dome文件 14 | bug联系qq 15 | -------------------------------------------------------------------------------- /dome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*-coding:utf-8-*- 3 | # date: 2024-01-25 16:13 4 | # data:qq3163450460 5 | # (0,1,8,"{params}","{data}","{ua}") 6 | import requests 7 | from threading import Thread 8 | import time 9 | 10 | 11 | def run(): 12 | data = { 13 | '1_str': 'params', 14 | '2_str': 'data', 15 | '3_str': 'ua' 16 | } 17 | # 传输类型 str dict int float 18 | url = 'http://127.0.0.1:8082/eval_js/get_a_b' 19 | res = requests.get(url=url, params=data) 20 | print(res.url) 21 | print(res.text) 22 | 23 | 24 | # 'http://127.0.0.1:8082/eval_js/profileData' 25 | 26 | def thread_run(): 27 | t = time.time() 28 | a = [] 29 | for i in range(100): 30 | dd = Thread(target=run) 31 | a.append(dd) 32 | dd.start() 33 | # break 34 | 35 | for i in a: 36 | i.join() 37 | 38 | print('耗时:', time.time() - t) 39 | 40 | 41 | if __name__ == '__main__': 42 | run() 43 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*-coding:utf-8-*- 3 | # date: 2024-01-25 15:01 4 | # data:qq3163450460 5 | import json 6 | import os 7 | import shutil 8 | from urllib.parse import urlparse 9 | 10 | file = os.path.dirname(__file__) 11 | 12 | 13 | def get_js_paths(): 14 | global file 15 | cmd_path = file + '/jsdata/' 16 | paths = os.listdir(cmd_path) 17 | js_paths = list() 18 | for path in paths: 19 | if path.endswith('.js'): 20 | js_paths.append(cmd_path + path) 21 | return js_paths 22 | 23 | 24 | def remove_file(folder): 25 | if not os.path.exists(folder): 26 | return 27 | try: 28 | shutil.rmtree(folder) 29 | except OSError as e: 30 | print(e) 31 | 32 | 33 | with open(f'{file}/config.json', 'r', encoding='utf-8-sig') as p: 34 | CONFIG = json.loads(p.read()) 35 | 36 | ON_OFF = CONFIG['ON_OFF'] # 是否无头 True无头 37 | ... 38 | USER_DATA_PATH = f'{file}/{CONFIG["USER_DATA_PATH"]}' # 浏览器缓存地址 39 | remove_file(USER_DATA_PATH) # 每次启动删除缓存文件夹 40 | ... 41 | BROWSER_PATH = CONFIG['BROWSER_PATH'] # 浏览器地址 42 | ... 43 | URL = CONFIG['URL'] # 需要打开的网站 44 | ... 45 | COOKIES = CONFIG["COOKIES"] # {'name1': 'value1', 'name2': 'value2'} 46 | if COOKIES: 47 | host = urlparse(url=URL).hostname 48 | COOKIES['domain'] = host 49 | ... 50 | 51 | PORT = 8082 # flask 端口 52 | KEY = 'xddmmm' # 在线刷新js的key 53 | # http://127.0.0.1:8082/ini_js?key=xddmmm 54 | 55 | JS_PATHS = get_js_paths() # 获取全部js文件名称 56 | print(JS_PATHS) 57 | 58 | # 传输类型 str dict int float 59 | -------------------------------------------------------------------------------- /rpc_drive.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*-coding:utf-8-*- 3 | # date: 2024-01-25 15:01 4 | # data: qq3163450460 5 | import json 6 | import time 7 | import os 8 | import subprocess 9 | import psutil 10 | from DrissionPage import ChromiumPage, ChromiumOptions 11 | from config import URL, JS_PATHS, PORT, KEY, BROWSER_PATH, COOKIES, ON_OFF,USER_DATA_PATH 12 | from loguru import logger 13 | from flask import Flask, request 14 | 15 | """ 16 | """ 17 | # logger.remove(handler_id=None) # 禁用控制台日志输出 18 | # 配置 19 | if not os.path.exists('logs'): 20 | os.makedirs('logs') 21 | logger.add("logs/rpc_drive.log", # log文件地址 22 | level="DEBUG", # log记录最低级别 23 | rotation="00:00", # 将日志记录以大小、时间等方式进行分割或划分 24 | retention="3 days", # 文件保留时间 25 | compression="zip", # 文件压缩格式 26 | backtrace=True, 27 | # rotation="1 MB" # 滚动大日志文件 28 | ) 29 | 30 | 31 | def kill_port(port): 32 | port_pid = {} 33 | for i in psutil.net_connections(): 34 | pid = i.pid 35 | port_ = i.laddr.port 36 | port_pid[port_] = pid 37 | # 关闭占用端口的pid 38 | if port_pid.get(int(port)): 39 | find_kill = 'taskkill -f -pid %s' % port_pid[int(port)] 40 | subprocess.Popen(find_kill) 41 | logger.info(f'端口关闭成功:{port}') 42 | 43 | 44 | class ChromeDrive: 45 | def __init__(self): 46 | self.start = True 47 | self.addr_or_opts = PORT + 1 48 | self.page = self.init_page() 49 | self.execute_js() 50 | 51 | def get_co(self): 52 | co = ChromiumOptions() 53 | co.set_paths(browser_path=BROWSER_PATH, user_data_path=USER_DATA_PATH) 54 | co.set_local_port(self.addr_or_opts) 55 | co.headless(on_off=ON_OFF) 56 | return co 57 | 58 | def init_page(self): 59 | # self.addr_or_opts += 1 60 | co = self.get_co() 61 | page = ChromiumPage(addr_or_opts=co, timeout=15) 62 | if COOKIES: 63 | page.set.cookies(cookies=COOKIES) 64 | page.get(URL) 65 | return page 66 | 67 | def int_chrome(self): 68 | if self.start is False: 69 | logger.error('浏览器已经在重启了') 70 | return '' 71 | self.start = False 72 | logger.info('浏览器异常开始重启....') 73 | kill_port(self.addr_or_opts) 74 | self.page.quit() 75 | time.sleep(1) 76 | self.page = self.init_page() 77 | time.sleep(1) 78 | logger.info('浏览器重启完成') 79 | self.execute_js() 80 | self.start = True 81 | 82 | def run_js_loaded(self, js_code): 83 | """ 84 | 执行js 85 | :param js_code: 86 | :return: 87 | """ 88 | try: 89 | self.page.run_js_loaded(script=js_code, as_expr=True, timeout=30) 90 | return True 91 | except Exception as e: 92 | if '与页面的连接已断开' in str(e): 93 | self.int_chrome() 94 | logger.error(e) 95 | return False 96 | 97 | def execute_js(self): 98 | """ 99 | 执行文件夹所有js 100 | :return: 101 | """ 102 | # paths = JS_PATHS() 103 | for js_path in JS_PATHS: 104 | with open(js_path, 'r', encoding='utf-8') as p: 105 | res = self.run_js_loaded(p.read()) 106 | if res: 107 | logger.debug(f'文件执行成功 ({js_path})') 108 | else: 109 | logger.error(f'js文件执行失败 ({js_path})') 110 | logger.info('全部js执行完成') 111 | 112 | def eval_js(self, js_code): 113 | """ 114 | 执行js 获取返回结果 115 | :param js_code: 116 | :return: 117 | """ 118 | try: 119 | res = self.page.run_js(script=js_code, as_expr=True, timeout=30) 120 | return json.dumps({'code': 0, 'data': res, 'msg': '操作成功'}, ensure_ascii=False) 121 | except Exception as e: 122 | if '与页面的连接已断开' in str(e): 123 | self.int_chrome() 124 | else: 125 | self.execute_js() 126 | logger.error(e) 127 | return json.dumps({'code': -1, 'msg': str(e), 'data': {}}, ensure_ascii=False) 128 | 129 | 130 | app = Flask(__name__) 131 | 132 | chrome_drive = ChromeDrive() 133 | 134 | 135 | def dic_to_tuple(dic: dict): 136 | dic_list = sorted(dic, key=lambda x: x.split('_')[0]) 137 | res = () 138 | for key in dic_list: 139 | value = dic[key] 140 | type_ = key.split('_')[-1] 141 | if type_ == 'dict': 142 | value = json.loads(value) 143 | elif type_ == 'int': 144 | value = int(value) 145 | elif type_ == 'float': 146 | value = float(value) 147 | res += (value,) 148 | return res 149 | 150 | 151 | @app.route('/eval_js/', methods=['POST', 'GET']) 152 | def start(fun_name): 153 | if '.' in fun_name or chrome_drive.start is False: 154 | return json.dumps({'code': -1, 'msg': '异常连接', 'data': {}}, ensure_ascii=False), 500 155 | params = request.values.to_dict() 156 | str_params = dic_to_tuple(params) 157 | js_code = f"window.{fun_name}{str(str_params)}" 158 | logger.info(js_code) 159 | res = chrome_drive.eval_js(js_code=js_code) 160 | return res 161 | 162 | 163 | @app.route('/ini_js', methods=['GET']) 164 | def ini_js(): 165 | key = request.values.get('key', None) 166 | if key == KEY: 167 | chrome_drive.init_page() 168 | chrome_drive.execute_js() 169 | return json.dumps({'code': 0, 'msg': '操作成功', 'data': JS_PATHS}, ensure_ascii=False) 170 | else: 171 | return json.dumps({'code': -1, 'msg': '密钥错误 刷新失败', 'data': {}}, ensure_ascii=False) 172 | 173 | 174 | @app.errorhandler(Exception) 175 | def error(e): 176 | return json.dumps({'code': -1, 'msg': str(e)}, ensure_ascii=False) 177 | 178 | 179 | # 传输类型 str dict int float 180 | # http://127.0.0.1:8082/ini_js?key=xddmmm 181 | if __name__ == '__main__': 182 | # ChromeDrive() 183 | app.run('0.0.0.0', port=PORT) 184 | --------------------------------------------------------------------------------