├── Morelogin_start.py ├── README.md ├── Threads ├── morelogin_ids.xlsx └── morelogin_start_threads.py ├── adspower.py ├── change_proxies.py ├── new_browser.py ├── open.bat ├── open_browser.py ├── selenium_morelogin.py └── xverse.py /Morelogin_start.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import random 3 | import string 4 | import time 5 | import requests 6 | from DrissionPage import ChromiumPage 7 | from DrissionPage._configs.chromium_options import ChromiumOptions 8 | 9 | # 常量配置 10 | APPID = '123456' # 替换自己的 11 | SECRETKEY = 'abcdef' # 替换自己的 12 | BASEURL = 'http://127.0.0.1:40000' # 接口地址无需更改 13 | DEFAULT_ENV_ID = '18228' # 替换自己的环境ID 14 | 15 | 16 | def generate_random_string(length=6): 17 | """生成指定长度的随机字符串,由字母和数字组成。""" 18 | characters = string.ascii_letters + string.digits 19 | return ''.join(random.choice(characters) for _ in range(length)) 20 | 21 | 22 | def generate_nonce_id(): 23 | """生成唯一的 nonceId,包含当前时间戳和随机字符串。""" 24 | return str(int(time.time() * 1000)) + generate_random_string() 25 | 26 | 27 | def generate_md5_signature(nonce_id): 28 | """根据 APPID、nonceId 和 SECRETKEY 生成 MD5 哈希值。""" 29 | md5 = hashlib.md5() 30 | md5.update((APPID + nonce_id + SECRETKEY).encode('utf-8')) 31 | return md5.hexdigest() 32 | 33 | 34 | def create_request_headers(): 35 | """生成 API 请求的头部,包括身份验证信息。""" 36 | nonce_id = generate_nonce_id() 37 | md5_str = generate_md5_signature(nonce_id) 38 | return { 39 | 'X-Api-Id': APPID, 40 | 'Authorization': md5_str, 41 | 'X-Nonce-Id': nonce_id 42 | } 43 | 44 | 45 | def start_environment(env_id=DEFAULT_ENV_ID): 46 | """启动指定的 MoreLogin 环境,并返回调试端口。""" 47 | headers = create_request_headers() 48 | payload = { 49 | "envId": env_id, 50 | } 51 | try: 52 | res = requests.post(f"{BASEURL}/api/env/start", json=payload, headers=headers) 53 | res.raise_for_status() # 检查请求是否成功 54 | data = res.json() 55 | # pprint.pprint(data) 56 | return data['data']['debugPort'] 57 | except requests.RequestException as e: 58 | print(f"请求失败: {e}") 59 | return None 60 | 61 | 62 | def open_browser(debug_port, url): 63 | page = None 64 | if debug_port: 65 | try: 66 | co = ChromiumOptions().set_local_port(debug_port) 67 | page = ChromiumPage(co) 68 | print(f"浏览器[ {DEFAULT_ENV_ID} ]:接管成功") 69 | print('Morelogin注册链接(15天免费50个环境):https://www.morelogin.com/?from=AA5enIPURMdF') 70 | print('如果你使用了我的链接注册,我可以提供共享脚本或技术支持,加我微信:lumaoyangmao') 71 | except Exception as e: 72 | print(f"无法打开浏览器页面: {e}") 73 | else: 74 | print("无效的调试端口,无法启动浏览器。") 75 | 76 | # 可继续续写自动化相关代码 77 | page.get(url) 78 | 79 | 80 | if __name__ == '__main__': 81 | url = 'https://x.com/lumaoyangmao' # 目标 URL 82 | 83 | # 启动环境并获取调试端口 84 | debug_port = start_environment(DEFAULT_ENV_ID) 85 | 86 | # 打开浏览器 87 | open_browser(debug_port, url) 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DrissionPage 示例 2 | 3 | ![GitHub stars](https://img.shields.io/github/stars/your-username/your-repo-name?style=social) 4 | ![GitHub forks](https://img.shields.io/github/forks/your-username/your-repo-name?style=social) 5 | ![GitHub issues](https://img.shields.io/github/issues/your-username/your-repo-name) 6 | ![GitHub license](https://img.shields.io/github/license/your-username/your-repo-name) 7 | 8 | ## 项目简介 9 | 10 | 本项目提供了使用 DrissionPage 库自动化操作浏览器的简单示例。 11 | 12 | 指纹浏览器注册: 13 | 14 | [推荐]Morelogin注册链接(50个环境免费使用15天):https://www.morelogin.com/?from=AA5enIPURMdF 15 | 16 | ADSPOWER注册链接:https://share.adspower.net/mZS8PGvgfrcr4ik 17 | 18 | 19 | ### 安装依赖 20 | 21 | ```bash 22 | pip install drissionpage requests 23 | -------------------------------------------------------------------------------- /Threads/morelogin_ids.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coolaroc/dp-browser/593e5389eacd8d2bef22f08165cd63c38c236764/Threads/morelogin_ids.xlsx -------------------------------------------------------------------------------- /Threads/morelogin_start_threads.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import pprint 3 | import random 4 | import string 5 | import time 6 | import requests 7 | from DrissionPage import ChromiumPage 8 | from DrissionPage._configs.chromium_options import ChromiumOptions 9 | import pandas as pd 10 | from concurrent.futures import ThreadPoolExecutor 11 | from time import sleep 12 | 13 | 14 | # 常量配置 15 | APPID = '1587555449088158' # 替换自己的 16 | SECRETKEY = 'f1b60ed4819f4bdb9ff69d2f1c7eea70' # 替换自己的 17 | BASEURL = 'http://127.0.0.1:40000' # 接口地址无需更改 18 | 19 | 20 | def generate_random_string(length=6): 21 | """生成指定长度的随机字符串,由字母和数字组成。""" 22 | characters = string.ascii_letters + string.digits 23 | return ''.join(random.choice(characters) for _ in range(length)) 24 | 25 | 26 | def generate_nonce_id(): 27 | """生成唯一的 nonceId,包含当前时间戳和随机字符串。""" 28 | return str(int(time.time() * 1000)) + generate_random_string() 29 | 30 | 31 | def generate_md5_signature(nonce_id): 32 | """根据 APPID、nonceId 和 SECRETKEY 生成 MD5 哈希值。""" 33 | md5 = hashlib.md5() 34 | md5.update((APPID + nonce_id + SECRETKEY).encode('utf-8')) 35 | return md5.hexdigest() 36 | 37 | 38 | def create_request_headers(): 39 | """生成 API 请求的头部,包括身份验证信息。""" 40 | nonce_id = generate_nonce_id() 41 | md5_str = generate_md5_signature(nonce_id) 42 | return { 43 | 'X-Api-Id': APPID, 44 | 'Authorization': md5_str, 45 | 'X-Nonce-Id': nonce_id 46 | } 47 | 48 | 49 | def start_environment(env_id): 50 | """启动指定的 MoreLogin 环境,并返回调试端口。""" 51 | headers = create_request_headers() 52 | payload = { 53 | "envId": env_id, 54 | } 55 | try: 56 | res = requests.post(f"{BASEURL}/api/env/start", json=payload, headers=headers) 57 | res.raise_for_status() # 检查请求是否成功 58 | data = res.json() 59 | pprint.pprint(data) 60 | return data['data']['debugPort'] 61 | except requests.RequestException as e: 62 | print(f"请求失败: {e}") 63 | return None 64 | 65 | 66 | def open_browser(debug_port, url, evn_id): 67 | page = None 68 | if debug_port: 69 | try: 70 | co = ChromiumOptions().set_local_port(debug_port) 71 | page = ChromiumPage(co) 72 | print(f"环境ID:[ {evn_id} ]:接管成功") 73 | print('Morelogin注册链接(15天免费50个环境):https://www.morelogin.com/?from=AA5enIPURMdF') 74 | print('如果你使用了我的链接注册,我可以提供共享脚本或技术支持,加我微信:lumaoyangmao') 75 | except Exception as e: 76 | print(f"无法打开浏览器页面: {e}") 77 | else: 78 | print("无效的调试端口,无法启动浏览器。") 79 | 80 | # 可继续续写自动化相关代码 81 | page.get(url) 82 | 83 | 84 | def parse_range(range_string): 85 | """解析用户输入的范围字符串""" 86 | result = set() 87 | parts = range_string.split(',') 88 | for part in parts: 89 | if '-' in part: 90 | start, end = map(int, part.split('-')) 91 | result.update(range(start, end + 1)) 92 | else: 93 | result.add(int(part)) 94 | return sorted(list(result)) 95 | 96 | def get_ids_from_excel(filename='morelogin_ids.xlsx', indices=None): 97 | """从Excel文件中读取指定索引的id和env_id""" 98 | df = pd.read_excel(filename, names=['id', 'env_id'], dtype={'env_id': str}) 99 | if indices: 100 | return df['env_id'].iloc[[i-1 for i in indices]].tolist() # 转换为0-based索引 101 | return df['env_id'].tolist() 102 | 103 | def process_environment(count, total, evn_id, url): 104 | print(f'[{count}/{total}] 等待打开环境ID:{evn_id}') 105 | debug_port = start_environment(evn_id) 106 | open_browser(debug_port, url, evn_id) 107 | 108 | if __name__ == '__main__': 109 | url = 'https://x.com/lumaoyangmao' # 目标 URL 110 | 111 | # 询问用户要执行的编号范围 112 | range_input = input("请输入要执行的编号范围(例如:10 或 1-5 或 1,3,5,7): ") 113 | indices = parse_range(range_input) 114 | 115 | # 询问用户想要使用的线程数 116 | thread_count = int(input("请输入要使用的线程数: ")) 117 | 118 | ids = get_ids_from_excel(indices=indices) 119 | total = len(ids) 120 | 121 | print(f"将处理 {total} 个环境,使用 {thread_count} 个线程") 122 | 123 | # 使用线程池执行任务 124 | with ThreadPoolExecutor(max_workers=thread_count) as executor: 125 | futures = [] 126 | for count, evn_id in enumerate(ids, 1): 127 | future = executor.submit(process_environment, count, total, evn_id, url) 128 | futures.append(future) 129 | sleep(1) # 在每次启动任务时增加1秒延迟 130 | 131 | # 等待所有任务完成 132 | for future in futures: 133 | future.result() 134 | 135 | print("所有任务已完成") 136 | -------------------------------------------------------------------------------- /adspower.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from time import sleep 3 | from DrissionPage import ChromiumPage 4 | 5 | 6 | def start_browser(serial_number): 7 | open_url = f"http://localhost:50325/api/v1/browser/start?serial_number={serial_number}" 8 | 9 | for attempt in range(5): 10 | try: 11 | resp = requests.get(open_url, timeout=10).json() 12 | if resp.get("code") == 0: 13 | debug_port = int(resp["data"]["debug_port"]) 14 | return ChromiumPage(debug_port) 15 | else: 16 | print(f"\033[0;31m浏览器[{serial_number}]打开出错,正在重试...错误信息:[{resp}]\033[0m") 17 | except requests.RequestException as e: 18 | print(f"\033[0;31m请求失败: {e}\033[0m") 19 | 20 | sleep(1) 21 | 22 | raise Exception(f"无法启动浏览器 {serial_number},已达到最大重试次数") 23 | 24 | 25 | # 使用方法 26 | serial_number = 1 # 环境编号 27 | 28 | try: 29 | page = start_browser(serial_number) 30 | print(f"环境 {serial_number} 已成功启动或接管") 31 | # 在这里继续使用 page 对象进行后续操作 32 | page.new_tab(url='https://x.com/lumaoyangmao') 33 | except Exception as e: 34 | print(f"错误: {e}") 35 | -------------------------------------------------------------------------------- /change_proxies.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import random 3 | import logging 4 | import configparser 5 | 6 | # 创建日志记录器 7 | logger = logging.getLogger(__name__) 8 | logging.basicConfig(level=logging.INFO) 9 | 10 | # 设置代理服务器的配置信息 11 | port = '端口' 12 | secret = '密钥' 13 | selector = '机场名字' 14 | 15 | headers_secret = { 16 | 'Authorization': 'Bearer {}'.format(secret) 17 | } 18 | 19 | # 代理的URL信息 20 | url_all_proxies_info = 'http://127.0.0.1:{}/proxies'.format(port) 21 | url_all_proxies = 'http://127.0.0.1:{}/proxies/{}'.format(port, selector) 22 | 23 | def change_proxy(url_all_proxies): 24 | try: 25 | # 获取当前的代理信息 26 | res_proxies = requests.get(url_all_proxies, headers=headers_secret).json() 27 | now_proxy = res_proxies['now'] 28 | logger.info(f'现在的代理是 {now_proxy}') 29 | 30 | # 获取代理名称列表 31 | proxy_name_list = res_proxies['all'] 32 | if len(proxy_name_list) > 6: 33 | proxy_name_list = proxy_name_list[3:-3] 34 | 35 | # 如果当前代理不在特殊代理列表中,且在代理列表里,则移除它 36 | if now_proxy not in ['DIRECT', 'REJECT', '账号邮箱看最新的地址', 'NETV2', '自动选择', '故障转移']: 37 | if now_proxy in proxy_name_list: 38 | proxy_name_list.remove(now_proxy) 39 | 40 | # 无限循环,直到找到延迟不为零的代理(有最大尝试次数限制) 41 | max_attempts = 10 42 | attempts = 0 43 | while attempts < max_attempts: 44 | random_proxy = random.choice(proxy_name_list) 45 | proxies_info = requests.get(url_all_proxies_info, headers=headers_secret).json() 46 | delay = proxies_info['proxies'][random_proxy]['history'][-1]['delay'] 47 | if delay != 0: 48 | break 49 | attempts += 1 50 | 51 | if attempts >= max_attempts: 52 | logger.error("未能找到合适的代理,尝试次数过多") 53 | return 54 | 55 | logger.info(f'随机选择的代理为 {random_proxy}') 56 | 57 | # 设置要更换的代理 58 | data = { 59 | "name": random_proxy 60 | } 61 | 62 | # 请求头,包含内容类型和授权信息 63 | headers = { 64 | "content-type": "application/json", 65 | 'Authorization': f'Bearer {secret}' 66 | } 67 | 68 | # 发送 PUT 请求到代理服务器以更新当前使用的代理 69 | res = requests.put(url=url_all_proxies, json=data, headers=headers) 70 | 71 | # logger.info(f'切换代理请求的状态码为 {res.status_code}') 72 | 73 | if res.status_code == 204: 74 | logger.info(f'切换代理成功!现在的代理为 {random_proxy}') 75 | else: 76 | logger.error(f'切换代理失败,状态码:{res.status_code}') 77 | 78 | except Exception as e: 79 | logger.error(f"切换代理时出错: {e}") 80 | 81 | if __name__ == "__main__": 82 | change_proxy(url_all_proxies=url_all_proxies) -------------------------------------------------------------------------------- /new_browser.py: -------------------------------------------------------------------------------- 1 | from DrissionPage import ChromiumOptions, ChromiumPage 2 | import os 3 | 4 | # 设置基础路径 5 | base_path = r"D:\Browser" 6 | 7 | 8 | # 获取当前最大的文件夹编号 9 | def get_max_folder_number(): 10 | if not os.path.exists(base_path): 11 | return 0 12 | folders = [f for f in os.listdir(base_path) if f.isdigit()] 13 | return max(map(int, folders)) if folders else 0 14 | 15 | 16 | if __name__ == "__main__": 17 | # 确保基础路径存在 18 | if not os.path.exists(base_path): 19 | os.makedirs(base_path) 20 | 21 | # 获取当前最大的文件夹编号 22 | max_number = get_max_folder_number() 23 | 24 | # 询问要创建的浏览器分身数量 25 | count = int(input("请输入要创建的浏览器分身数量: ")) 26 | # 创建指定数量的浏览器分身 27 | for i in range(max_number + 1, max_number + count + 1): 28 | # 为每个分身创建一个唯一的用户数据路径 29 | user_data_dir = os.path.join(base_path, str(i)) 30 | 31 | # 如果文件夹已存在,则跳过 32 | if os.path.exists(user_data_dir): 33 | print(f"第 {i} 个浏览器分身已存在,跳过创建。") 34 | continue 35 | 36 | # 创建ChromiumOptions对象 37 | co = ChromiumOptions() 38 | 39 | # 设置用户数据路径 40 | co.set_paths(user_data_path=user_data_dir) 41 | 42 | # 创建ChromiumPage对象 43 | page = ChromiumPage(co) 44 | 45 | # 访问一个网页以初始化浏览器配置 46 | page.get('https://www.example.com') 47 | 48 | print(f"已创建第 {i} 个浏览器分身,路径: {user_data_dir}") 49 | 50 | # 关闭浏览器 51 | page.quit() 52 | 53 | print("所有浏览器分身已创建完成。") 54 | -------------------------------------------------------------------------------- /open.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set CHROME_PATH="C:\Program Files\Google\Chrome\Application\chrome.exe" 3 | set USER_DATA_DIR="D:\Browser\1" 4 | 5 | %CHROME_PATH% --user-data-dir=%USER_DATA_DIR% --remote-debugging-port=0 -------------------------------------------------------------------------------- /open_browser.py: -------------------------------------------------------------------------------- 1 | from DrissionPage import ChromiumOptions, ChromiumPage 2 | import os 3 | import socket 4 | 5 | # 设置基础路径 6 | base_path = r"D:\Browser" 7 | 8 | 9 | # 获取空闲端口 10 | def get_free_port(): 11 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 12 | s.bind(('', 0)) 13 | s.listen(1) 14 | port = s.getsockname()[1] 15 | return port 16 | 17 | 18 | def parse_input(input_string): 19 | # 移除所有空白字符 20 | input_string = ''.join(input_string.split()) 21 | 22 | # 解析输入 23 | numbers = set() 24 | for part in input_string.split(','): 25 | if '-' in part: 26 | start, end = map(int, part.split('-')) 27 | numbers.update(range(start, end + 1)) 28 | else: 29 | numbers.add(int(part)) 30 | 31 | return sorted(list(numbers)) 32 | 33 | 34 | if __name__ == "__main__": 35 | # 询问用户输入 36 | user_input = input("请输入要执行的浏览器编号,若编号不存在则自动创建。(支持格式:1, 1-3, 1,2,3): ") 37 | 38 | # 解析用户输入 39 | browser_numbers = parse_input(user_input) 40 | 41 | print(f"将要执行的浏览器编号: {browser_numbers}") 42 | 43 | # 为每个浏览器配置参数 44 | for number in browser_numbers: 45 | debug_port = get_free_port() 46 | user_data_path = rf'D:\Browser\{number}' 47 | co = ChromiumOptions() 48 | co.set_paths(local_port=debug_port, user_data_path=user_data_path) 49 | page = ChromiumPage(addr_or_opts=co) 50 | page.get('https://x.com/lumaoyangmao') 51 | -------------------------------------------------------------------------------- /selenium_morelogin.py: -------------------------------------------------------------------------------- 1 | # pip install selenium 2 | from selenium import webdriver 3 | 4 | import sys 5 | import asyncio 6 | import traceback 7 | import time 8 | import hashlib 9 | import random 10 | import string 11 | import requests 12 | 13 | # count auth info for web-request 14 | def requestHeader(appId, secretKey): 15 | nonceId = generateNonceId() 16 | md5Str = md5Encode(nonceId, appId, secretKey) 17 | return { 18 | 'X-Api-Id': appId, 19 | 'Authorization': md5Str, 20 | 'X-Nonce-Id': nonceId 21 | } 22 | 23 | 24 | # generate a random string 25 | def generateRandom(length=6): 26 | characters = string.ascii_letters + string.digits 27 | random_string = ''.join(random.choice(characters) for _ in range(length)) 28 | return random_string 29 | 30 | 31 | # count globally unique ID 32 | def generateNonceId(): 33 | return str(int(time.time()* 1000)) + generateRandom() 34 | 35 | 36 | # count signature parameter 37 | def md5Encode(nonceId, appId, secretKey): 38 | md5 = hashlib.md5() 39 | md5.update((appId + nonceId + secretKey).encode('utf-8')) 40 | return md5.hexdigest() 41 | 42 | 43 | # send web-request with POST 44 | def postRequest(url, data, headers): 45 | headers['Content-Type'] = 'application/json' 46 | return requests.post(url, json=data, headers=headers) 47 | 48 | 49 | # send web-request with GET 50 | def getRequest(url, headers): 51 | return requests.get(url, headers=headers) 52 | 53 | 54 | # 将 API ID 和 SECRETKEY 复制到下面。 55 | APPID = '' 56 | SECRETKEY = '' 57 | BASEURL = 'http://127.0.0.1:40000' 58 | 59 | 60 | async def main(): 61 | try: 62 | # 环境序号, 63 | uniqueId = 1 64 | # 环境ID 启动按钮后面三个点,选择复制环境ID 65 | # 环境序号和环境ID可只填写一个,两个都填,优先使用环境ID 66 | envId = '1823684318728519683' 67 | debugUrl = await startEnv(envId, uniqueId, APPID, SECRETKEY, BASEURL) 68 | print(debugUrl) 69 | 70 | driver = createWebDriver(debugUrl) 71 | operationEnv(driver) 72 | except: 73 | errorMessage = traceback.format_exc() 74 | print('run-error: ' + errorMessage) 75 | 76 | # create webdriver with exist browser 77 | def createWebDriver(debugUrl): 78 | opts = webdriver.ChromeOptions() 79 | opts.set_capability('browserVersion', '126') 80 | opts.add_experimental_option('debuggerAddress', debugUrl) 81 | driver = webdriver.Chrome(options=opts) 82 | print(driver.current_url) 83 | return driver 84 | 85 | 86 | async def startEnv(envId, uniqueId, appId, secretKey, baseUrl): 87 | requestPath = baseUrl + '/api/env/start' 88 | data = { 89 | 'envId': envId, 90 | 'uniqueId': uniqueId 91 | } 92 | headers = requestHeader(appId, secretKey) 93 | response = postRequest(requestPath, data, headers).json() 94 | 95 | if response['code'] != 0: 96 | print(response['msg']) 97 | print('please check envId') 98 | sys.exit() 99 | 100 | port = response['data']['debugPort'] 101 | print('env open result:', response['data']) 102 | return '127.0.0.1:' + port 103 | 104 | 105 | # open page and operation 106 | def operationEnv(driver): 107 | driver.switch_to.new_window('tab') 108 | driver.get('https://x.com/lumaoyangmao') 109 | 110 | # 可续写自动化流程 111 | print('浏览器启动或接管成功') 112 | print('Morelogin注册链接(15天免费50个环境):https://www.morelogin.com/?from=AA5enIPURMdF') 113 | print('如果你使用了我的链接注册,我可以提供共享脚本或技术支持,加我微信:lumaoyangmao') 114 | 115 | 116 | if __name__ == '__main__': 117 | asyncio.run(main()) 118 | -------------------------------------------------------------------------------- /xverse.py: -------------------------------------------------------------------------------- 1 | import os 2 | import csv 3 | import threading 4 | from time import sleep, time 5 | from concurrent.futures import ThreadPoolExecutor, as_completed 6 | import pyperclip 7 | from DrissionPage import ChromiumPage, ChromiumOptions 8 | from mnemonic import Mnemonic 9 | import uuid 10 | 11 | # 初始化全局锁 12 | lock = threading.Lock() 13 | 14 | def save_to_csv(address, seed_phrase_list): 15 | """将地址和助记词保存到 CSV 文件中""" 16 | main_filename = 'xverse.csv' 17 | temp_filename = f'xverse_temp_{uuid.uuid4().hex}.csv' # 使用唯一的临时文件名 18 | 19 | with lock: # 使用锁来防止多个线程同时写入文件时发生冲突 20 | with open(temp_filename, 'w', newline='', encoding='utf-8') as csvfile: 21 | writer = csv.writer(csvfile) 22 | # 将助记词列表转换为单个字符串 23 | seed_phrase = ' '.join(seed_phrase_list) 24 | writer.writerow([address, seed_phrase]) 25 | 26 | # 确保将临时文件内容写入主文件 27 | with lock: 28 | if os.path.exists(main_filename): 29 | with open(main_filename, 'a', newline='', encoding='utf-8') as mainfile: 30 | with open(temp_filename, 'r', newline='', encoding='utf-8') as tempfile: 31 | reader = csv.reader(tempfile) 32 | writer = csv.writer(mainfile) 33 | for row in reader: 34 | writer.writerow(row) 35 | else: 36 | os.rename(temp_filename, main_filename) 37 | 38 | if os.path.exists(temp_filename): 39 | os.remove(temp_filename) 40 | 41 | print(f"地址与助记词数据已保存到 {main_filename}") 42 | 43 | def create_wallet(): 44 | """创建钱包并返回钱包地址和助记词列表""" 45 | chrome_options = ChromiumOptions().auto_port().set_argument('--lang=en').add_extension(r'D:\llq\detail\Xverse-Wallet') 46 | page = ChromiumPage(addr_or_opts=chrome_options) 47 | page.set.timeouts(0.1) 48 | 49 | try: 50 | # 生成助记词 51 | mnemo = Mnemonic("english") 52 | seed_phrase_list = mnemo.generate(strength=128).split() 53 | while True: # 通过标签页数量判断弹出钱包 54 | if page.tabs_count > 1: 55 | page.close_tabs(others=True) 56 | page.get('chrome-extension://hmocdlaipfjakhcngkfcpfkmgapbogfo/options.html#/') 57 | break 58 | sleep(1) 59 | # 处理创建钱包的循环,最多尝试60次 60 | for _ in range(60): 61 | try: 62 | page('text=Restore an existing wallet').click() 63 | sleep(1) 64 | except Exception: 65 | pass 66 | 67 | try: 68 | page('text=Accept').click() 69 | sleep(1) 70 | except Exception: 71 | pass 72 | 73 | if page('text=Enter your seedphrase to restore your wallet.'): 74 | for i in range(12): 75 | input_field = page(f'#input{i}') 76 | input_field.input(seed_phrase_list[i]) 77 | sleep(0.2) # 添加一个短暂的延迟,以确保输入顺利 78 | print(f"助记词已输入: {seed_phrase_list}") 79 | 80 | try: 81 | page('text=Continue').click() 82 | sleep(0.5) 83 | except Exception: 84 | pass 85 | 86 | try: 87 | page('@@type=password@@value=').input('Lumaoyangmao\n') # 钱包密码 88 | sleep(0.5) 89 | except Exception: 90 | pass 91 | 92 | if page('text=Close this tab'): 93 | sleep(1) 94 | break 95 | sleep(1) 96 | else: 97 | page.quit() 98 | return False 99 | 100 | # 处理注册的超时循环 101 | start_time = time() 102 | timeout = 60 # 设置超时时间为60秒 103 | page.get('https://wallet.xverse.app/whitelist') 104 | while True: 105 | if time() - start_time > timeout: 106 | print("注册过程超时") 107 | page.quit() 108 | return False 109 | 110 | try: 111 | page('text=Register').click() 112 | page.wait(1) 113 | except Exception: 114 | pass 115 | 116 | tab = page.get_tab(title='Xverse Wallet') 117 | if tab: 118 | try: 119 | tab('text=Connect').click() 120 | page.wait(1) 121 | except Exception: 122 | pass 123 | 124 | if page('text=Registration successful'): 125 | sleep(2) 126 | break 127 | sleep(1) 128 | 129 | # 获取钱包地址 130 | page.get('chrome-extension://hmocdlaipfjakhcngkfcpfkmgapbogfo/options.html#/') 131 | for _ in range(60): 132 | try: 133 | page('t:div@text()=Receive').click() 134 | page.wait(1) 135 | except Exception: 136 | pass 137 | try: 138 | page('x://button[contains(@id,"copy-address-Ordinals")]/..//button[2]').click() 139 | page.wait(1) 140 | except Exception: 141 | pass 142 | bc1p = page('t:h1@text():bc1p') 143 | if bc1p: 144 | wallet_address = bc1p.text 145 | break 146 | sleep(1) 147 | else: 148 | page.quit() 149 | return False 150 | 151 | save_to_csv(wallet_address, seed_phrase_list) 152 | return wallet_address, seed_phrase_list 153 | except Exception as e: 154 | print(f"发生错误: {e}") 155 | finally: 156 | page.quit() 157 | 158 | def main(iterations, max_workers=4): 159 | """主函数,管理多线程执行""" 160 | with ThreadPoolExecutor(max_workers=max_workers) as executor: 161 | futures = [executor.submit(create_wallet) for _ in range(iterations)] 162 | 163 | for i, future in enumerate(as_completed(futures)): 164 | try: 165 | result = future.result() 166 | if result: 167 | address, seed_phrase_list = result 168 | print(f"第 {i + 1} 个任务创建成功。钱包地址: {address}") 169 | else: 170 | print(f"第 {i + 1} 个任务失败。") 171 | except Exception as e: 172 | print(f"执行第 {i + 1} 个任务时出错: {e}") 173 | sleep(2) 174 | 175 | if __name__ == "__main__": 176 | try: 177 | print('钱包密码在87行,默认Lumaoyangmao,浏览器用完即销毁,密码不重要,保存好助记词文件即可。') 178 | iterations = int(input("要执行多少次?(输入数字并回车): ")) 179 | max_workers = int(input("要开几个线程?(输入数字并回车): ")) 180 | main(iterations, max_workers) 181 | print("所有线程执行完毕。") 182 | except ValueError: 183 | print("请输入有效的数字") 184 | --------------------------------------------------------------------------------