├── .gitignore ├── requirements.txt ├── config └── redis.py ├── wallet └── users.txt ├── LICENSE ├── util ├── redis_util.py └── common_utils.py ├── README.md ├── start_proxy.py └── start_no_proxy.py /.gitignore: -------------------------------------------------------------------------------- 1 | /venv/ 2 | *.xml 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | websockets==12.0 2 | websockets_proxy==0.1.2 3 | Faker==22.7.0 4 | async_timeout==4.0.3 5 | redis~=5.0.3 6 | loguru==0.7.2 7 | -------------------------------------------------------------------------------- /config/redis.py: -------------------------------------------------------------------------------- 1 | redis_web3_host = 'localhost' 2 | redis_web3_port = 6379 3 | redis_web3_db = 0 4 | redis_web3_password = '' 5 | 6 | redis_prefix_agent = "ip:fake:agent:" 7 | redis_device_id= "ip:fake:device:" 8 | -------------------------------------------------------------------------------- /wallet/users.txt: -------------------------------------------------------------------------------- 1 | 5b62d235-273c-4707-85df-9bcca26a5306,socks5://user:pwd@193.168.221.27:21332 2 | 5b62d235-273c-4707-85df-9bcca26a5306,socks5://user:pwd@193.168.221.27:21333 3 | 5b62d235-273c-4707-85df-9bcca26a5306,socks5://user:pwd@193.168.221.27:21334 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 91qkxs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /util/redis_util.py: -------------------------------------------------------------------------------- 1 | import redis 2 | from config.redis import * 3 | 4 | 5 | class RedisUtils: 6 | def __init__(self): 7 | self.redis_client = self.init_redis() 8 | 9 | def init_redis(self): 10 | """ 11 | 初始化 Redis 连接 12 | """ 13 | redis_client = redis.StrictRedis( 14 | host=redis_web3_host, 15 | port=redis_web3_port, 16 | db=redis_web3_db, 17 | password=redis_web3_password, 18 | decode_responses=True # 设置为True以便返回字符串而不是字节 19 | ) 20 | return redis_client 21 | 22 | def set(self, key, value, expiration=None): 23 | """ 24 | 设置缓存 25 | """ 26 | self.redis_client.set(key, value, ex=expiration) 27 | 28 | def get(self, key): 29 | """ 30 | 获取缓存 31 | """ 32 | return self.redis_client.get(key) 33 | 34 | def delete(self, key): 35 | """ 36 | 删除缓存 37 | """ 38 | self.redis_client.delete(key) 39 | 40 | def sadd(self, key, *values): 41 | """ 42 | 将一个或多个元素添加到集合中 43 | """ 44 | return self.redis_client.sadd(key, *values) 45 | 46 | def sismember(self, key, value): 47 | """ 48 | 检查元素是否在集合中 49 | """ 50 | return self.redis_client.sismember(key, value) 51 | 52 | def smembers(self, key): 53 | """ 54 | 获取集合中的所有成员 55 | """ 56 | return self.redis_client.smembers(key) 57 | 58 | def srem(self, key, *values): 59 | """ 60 | 从集合中移除一个或多个元素 61 | """ 62 | return self.redis_client.srem(key, *values) 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # getgrass.io脚本 2 | 3 | ### 本项目为grass运行脚本 4 | 5 | 目前市面上很多代挂工作室或者,本脚本主要服务需要的人 6 | 7 | 项目官网https://app.getgrass.io/register/?referralCode=xv4tsqSC9SftAXJ 8 | 9 | 为什么浏览器可以挖要用脚本?在浏览器环境必须打开浏览器才能挖,很多人想多号或者在linux等环境下运行,此时这个脚本就发挥用武之地 10 | 11 | ### 使用教程 12 | 13 | - 安装python 14 | 15 | ​ 环境要求python 3.9以上,具体操作百度一下 16 | 17 | - 导包 18 | 19 | ​ 打开shell命令行 进入到文件根目录,执行:pip3 install -r requirements.txt 20 | 21 | ##### 不用代理运行: 22 | 23 | 找到start_no_proxy.py将main方法参数换成你的既可,然后执行python3 start_no_proxy.py 就行 24 | 25 | ~~~python 26 | user_id = '5b62d235-273c-4707-85df-9bcca26a5306' #你自己的user_id 27 | ~~~ 28 | 29 | ##### 使用代理运行 30 | 31 | 注意:如果你使用代理的话,此脚本需要依赖redis环境 32 | 33 | 第一步:安装redis 34 | 35 | ~~~ 36 | 为何要使用redis? 37 | 38 | 正常脚本每次运行会模拟生成一个浏览器agent和设备id,你第运行10次就会生成10个,通过使用redis,保障每个代理的设备号和agent永远只有1个 39 | 即便你运行1000次 你设备依然只有这1个。 40 | 41 | 安装方式 42 | 如果你是windows: 43 | 打开这个网站:https://github.com/MicrosoftArchive/redis/releases 44 | 建议下载.ZIP格式文件 45 | 下载完成后找到 redis-server.exe 46 | 使用脚本时候 点一下运行,出来个运行界面即可,不用脚本里 就关闭窗口 47 | 如果你安装msi服务,安装完成基本这个服务就一直处于打开状态 48 | 49 | 如果你是mac 50 | 直接brew安装即可 51 | linux简单直接google对应安装教程 52 | 53 | 注意每次使用脚本必须要保证redis服务处于开启状态 54 | 如果运行报错提示6379错误就是redis没有打开 55 | 56 | 如果你本机以前已经有redis,或者你有redis服务 57 | 你直接找到config目录下的redis.py配置你的redis服务地址就行 58 | 59 | ~~~ 60 | 61 | 第二步:配置用户ID和代理信息 62 | 63 | ~~~ 64 | 格式如下: 65 | 5b62d230-xxxxx-5307,socks5://user1:pwd1@193.168.221.1:21322 66 | 5b62d230-xxxxx-5307,socks5://user1:pwd1@193.168.221.1:21320 67 | 5b62d231-xxxxx-5307,socks5://193.168.221.1:21322 68 | 5b62d232-xxxxx-5308,socks5://193.168.221.2:21322 69 | ~~~ 70 | 找到wallet目录下的users.txt,将你的用户id和socket5代理复制进去即可,注意账号和代理直接用英文逗号分隔然后执行python3 start_proxy.py 就行 71 | 72 | 73 | 74 | - 如何获取user_id 75 | 76 | 打开链接登录https://app.getgrass.io/dashboard, 然后浏览器按F12打开开发者工具 在控制台(console)输入下面代码 77 | 78 | ``` 79 | localStorage.userId 80 | ``` 81 | 82 | 打印的就是你目前的user_id 83 | 84 | ![image-20240206145338215](https://raw.githubusercontent.com/91qkxs/tc/file/uPic/image-20240206145338215.png) 85 | 86 | 如果第一次用出现这样警告,就按提示输入allow pasting即可粘贴 87 | 88 | ![image-20240206145444725](https://raw.githubusercontent.com/91qkxs/tc/file/uPic/image-20240206145444725.png) 89 | 90 | 91 | # 一定要使用纯净家庭宽带ip否则跑不起来的 跑不起来检测自己网络问题,像阿里云这些机房服务器没积分的 -------------------------------------------------------------------------------- /start_proxy.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import os 4 | import random 5 | import ssl 6 | import time 7 | import uuid 8 | 9 | from faker import Faker 10 | from loguru import logger 11 | from websockets_proxy import Proxy, proxy_connect 12 | 13 | 14 | 15 | from config.redis import redis_device_id, redis_prefix_agent 16 | from util.common_utils import read_users_from_files, to_md5 17 | from util.redis_util import RedisUtils 18 | 19 | # 存储已连接的 WebSocket 对象的列表 20 | connected_websockets = [] 21 | 22 | redis_util = RedisUtils().init_redis() 23 | 24 | 25 | async def send_message(websocket, message): 26 | """ 27 | 发送消息到 WebSocket 服务器 28 | """ 29 | message_str = json.dumps(message) 30 | await websocket.send(message_str) 31 | 32 | 33 | async def receive_message(websocket): 34 | """ 35 | 接收 WebSocket 服务器的消息 36 | """ 37 | response = await websocket.recv() 38 | return json.loads(response) 39 | 40 | 41 | async def authenticate(websocket, auth_id, device_id, user_id, agent): 42 | """ 43 | 发送认证消息到 WebSocket 服务器 44 | """ 45 | auth_message = { 46 | "id": auth_id, 47 | "origin_action": "AUTH", 48 | "result": { 49 | "browser_id": device_id, 50 | "user_id": user_id, 51 | "user_agent": agent, 52 | "timestamp": int(time.time()), 53 | "device_type": "extension", 54 | "version": "3.3.2" 55 | } 56 | } 57 | await send_message(websocket, auth_message) 58 | 59 | 60 | async def task_single(user): 61 | proxy_ip = user['proxy_ip'] 62 | user_id = user['user'] 63 | device_id = redis_util.get(redis_device_id + to_md5(proxy_ip)) 64 | if device_id is None: 65 | device_id = str(uuid.uuid4()) 66 | redis_util.set(redis_device_id + to_md5(proxy_ip), device_id) 67 | device_id = redis_util.get(redis_device_id + to_md5(proxy_ip)) 68 | 69 | agent = redis_util.get(redis_prefix_agent + to_md5(proxy_ip)) 70 | if agent is None: 71 | agent = Faker().chrome() 72 | redis_util.set(redis_prefix_agent + to_md5(proxy_ip), agent) 73 | agent = redis_util.get(redis_prefix_agent + to_md5(proxy_ip)) 74 | logger.info(f"当年固定设备id:{device_id}, 固定浏览器agent:{agent}") 75 | uri_options = ["wss://proxy.wynd.network:4650/"] 76 | ssl_context = ssl.create_default_context() 77 | ssl_context.check_hostname = False 78 | ssl_context.verify_mode = ssl.CERT_NONE 79 | # 第一步发起sock链接 80 | uri = random.choice(uri_options) 81 | myproxy = Proxy.from_url(proxy_ip) 82 | while True: 83 | try: 84 | async with proxy_connect(uri, ssl=ssl_context, extra_headers={"User-Agent": agent}, proxy=myproxy, 85 | proxy_conn_timeout=30) as websocket: 86 | # 将连接加入到已连接的 WebSocket 列表中 87 | connected_websockets.append(websocket) 88 | 89 | # 第1步:接收平台auth请求响应 90 | auth_response = await receive_message(websocket) 91 | logger.info(f"{myproxy.proxy_host} 平台auth认证响应成功:{auth_response}") 92 | await asyncio.sleep(random.randint(10, 20) / 10) 93 | # 第3步:进行auth请求 94 | await authenticate(websocket, auth_response["id"], device_id, user_id, agent) 95 | await asyncio.sleep(20) 96 | 97 | """ 98 | 业务逻辑处理 99 | """ 100 | # 第2步:发送ping请求 101 | message = { 102 | "id": str(uuid.uuid4()), 103 | "version": "1.0.0", 104 | "action": "PING", 105 | "data": {} 106 | } 107 | await send_message(websocket, message) 108 | 109 | while True: 110 | # 第4步:得到认证成功请求响应 111 | pong_response = await receive_message(websocket) 112 | logger.info(f"{myproxy.proxy_host} 报文响应成功:{pong_response}") 113 | await asyncio.sleep(random.randint(1, 9) / 10) 114 | pong_message = { 115 | "id": pong_response["id"], 116 | "origin_action": "PONG" 117 | } 118 | # 第5步:回复平台已得到认证成功请求响应 119 | await send_message(websocket, pong_message) 120 | 121 | await asyncio.sleep(random.randint(180, 250) / 10) 122 | 123 | ping_message = { 124 | "id": str(uuid.uuid4()), 125 | "version": "1.0.0", 126 | "action": "PING", 127 | "data": {} 128 | } 129 | # 第6步:发送心跳包 130 | await send_message(websocket, ping_message) 131 | await asyncio.sleep(random.randint(1, 9) / 10) 132 | except Exception as e: 133 | sleep_time = random.randint(5, 15) 134 | logger.error(f"代理连接失败,准备重连 {myproxy.proxy_host}: {myproxy.proxy_port} ,异常信息:{e}") 135 | await asyncio.sleep(sleep_time) 136 | 137 | 138 | async def task_multi(file_names): 139 | current_directory = os.path.dirname(os.path.abspath(__file__)) 140 | # 从多个文件中读取钱包数据 141 | users = read_users_from_files(file_names, current_directory, "wallet") 142 | if users is None or len(users) <= 0: 143 | raise ValueError("请导入用户和代理!!!!") 144 | # 打乱数据顺序 145 | random.shuffle(users) 146 | semaphore = asyncio.Semaphore(len(users)) 147 | async def limited_task(wallet): 148 | async with semaphore: 149 | try: 150 | await task_single(wallet) 151 | except Exception as e: 152 | logger.error(e) 153 | 154 | # 并发处理 155 | tasks = [limited_task(user) for user in users] 156 | await asyncio.gather(*tasks) 157 | 158 | 159 | if __name__ == "__main__": 160 | file_names = ['users.txt'] 161 | loop = asyncio.get_event_loop() 162 | loop.run_until_complete(task_multi(file_names)) 163 | -------------------------------------------------------------------------------- /start_no_proxy.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import json 3 | import random 4 | import ssl 5 | import time 6 | import uuid 7 | 8 | import websockets 9 | from faker import Faker 10 | from loguru import logger 11 | from websockets_proxy import proxy_connect 12 | 13 | # 配置日志级别 14 | 15 | # 存储已连接的 WebSocket 对象的列表 16 | connected_websockets = [] 17 | 18 | 19 | async def send_message(websocket, message): 20 | """ 21 | 发送消息到 WebSocket 服务器 22 | """ 23 | message_str = json.dumps(message) 24 | logger.info(f"Sending message: {message_str}") 25 | await websocket.send(message_str) 26 | 27 | 28 | async def receive_message(websocket): 29 | """ 30 | 接收 WebSocket 服务器的消息 31 | """ 32 | response = await websocket.recv() 33 | logger.info(f"Received response: {response}") 34 | return json.loads(response) 35 | 36 | 37 | async def authenticate(websocket, auth_id, device_id, user_id, agent): 38 | """ 39 | 发送认证消息到 WebSocket 服务器 40 | """ 41 | auth_message = { 42 | "id": auth_id, 43 | "origin_action": "AUTH", 44 | "result": { 45 | "browser_id": device_id, 46 | "user_id": user_id, 47 | "user_agent": agent, 48 | "timestamp": int(time.time()), 49 | "device_type": "extension", 50 | "version": "3.3.2" 51 | } 52 | } 53 | await send_message(websocket, auth_message) 54 | 55 | 56 | async def run_websocket_logic(websocket, user_id, device_id, agent): 57 | try: 58 | # 第1步:接收平台auth请求响应 59 | auth_response = await receive_message(websocket) 60 | 61 | await asyncio.sleep(random.randint(10, 20) / 10) 62 | # 第3步:进行auth请求 63 | await authenticate(websocket, auth_response["id"], device_id, user_id, agent) 64 | await asyncio.sleep(20) 65 | 66 | """ 67 | 业务逻辑处理 68 | """ 69 | # 第2步:发送ping请求 70 | message = { 71 | "id": str(uuid.uuid4()), 72 | "version": "1.0.0", 73 | "action": "PING", 74 | "data": {} 75 | } 76 | await send_message(websocket, message) 77 | 78 | while True: 79 | # 第4步:得到认证成功请求响应 80 | pong_response = await receive_message(websocket) 81 | await asyncio.sleep(random.randint(1, 9) / 10) 82 | pong_message = { 83 | "id": pong_response["id"], 84 | "origin_action": "PONG" 85 | } 86 | # 第5步:回复平台已得到认证成功请求响应 87 | await send_message(websocket, pong_message) 88 | 89 | await asyncio.sleep(random.randint(180, 250) / 10) 90 | 91 | ping_message = { 92 | "id": str(uuid.uuid4()), 93 | "version": "1.0.0", 94 | "action": "PING", 95 | "data": {} 96 | } 97 | # 第6步:发送心跳包 98 | await send_message(websocket, ping_message) 99 | await asyncio.sleep(random.randint(1, 9) / 10) 100 | 101 | except websockets.exceptions.ConnectionClosed as e: 102 | logger.error(f"Connection closed unexpectedly: {e}") 103 | finally: 104 | await websocket.close() # 确保关闭连接 105 | 106 | 107 | 108 | async def close_connected_websockets(): 109 | """ 110 | 关闭所有已连接的 WebSocket 连接 111 | """ 112 | # 等待一段时间,确保之前的连接已经完全关闭 113 | await asyncio.sleep(5) 114 | for ws in connected_websockets: 115 | await ws.close() 116 | 117 | 118 | async def main(user_id): 119 | """ 120 | 主函数 121 | """ 122 | # 在运行主函数之前确保关闭之前的所有 WebSocket 连接 123 | await close_connected_websockets() 124 | 125 | device_id = str(uuid.uuid4()) 126 | logger.info(device_id) 127 | ssl_context = ssl.create_default_context() 128 | ssl_context.check_hostname = False 129 | ssl_context.verify_mode = ssl.CERT_NONE 130 | device_id = str(uuid.uuid4()) 131 | agent = Faker().chrome() 132 | uri_options = ["wss://proxy.wynd.network:4650/"] 133 | ssl_context = ssl.create_default_context() 134 | ssl_context.check_hostname = False 135 | ssl_context.verify_mode = ssl.CERT_NONE 136 | # 第一步发起sock链接 137 | uri = random.choice(uri_options) 138 | while True: 139 | try: 140 | async with websockets.connect(uri, ssl=ssl_context, extra_headers={"User-Agent": agent}) as websocket: 141 | # 将连接加入到已连接的 WebSocket 列表中 142 | connected_websockets.append(websocket) 143 | 144 | # 第1步:接收平台auth请求响应 145 | auth_response = await receive_message(websocket) 146 | logger.info(f" 平台auth认证响应成功:{auth_response}") 147 | await asyncio.sleep(random.randint(10, 20) / 10) 148 | # 第3步:进行auth请求 149 | await authenticate(websocket, auth_response["id"], device_id, user_id, agent) 150 | await asyncio.sleep(20) 151 | 152 | """ 153 | 业务逻辑处理 154 | """ 155 | # 第2步:发送ping请求 156 | message = { 157 | "id": str(uuid.uuid4()), 158 | "version": "1.0.0", 159 | "action": "PING", 160 | "data": {} 161 | } 162 | await send_message(websocket, message) 163 | 164 | while True: 165 | # 第4步:得到认证成功请求响应 166 | pong_response = await receive_message(websocket) 167 | logger.info(f"报文响应成功:{pong_response}") 168 | await asyncio.sleep(random.randint(1, 9) / 10) 169 | pong_message = { 170 | "id": pong_response["id"], 171 | "origin_action": "PONG" 172 | } 173 | # 第5步:回复平台已得到认证成功请求响应 174 | await send_message(websocket, pong_message) 175 | 176 | await asyncio.sleep(random.randint(180, 250) / 10) 177 | 178 | ping_message = { 179 | "id": str(uuid.uuid4()), 180 | "version": "1.0.0", 181 | "action": "PING", 182 | "data": {} 183 | } 184 | # 第6步:发送心跳包 185 | await send_message(websocket, ping_message) 186 | await asyncio.sleep(random.randint(1, 9) / 10) 187 | except Exception as e: 188 | sleep_time = random.randint(5, 15) 189 | logger.error(f"连接失败,准备重连,异常信息:{e}") 190 | await asyncio.sleep(sleep_time) 191 | 192 | 193 | if __name__ == "__main__": 194 | user_id = '5b62d235-273c-9bcca26a5306' 195 | asyncio.run(main(user_id)) 196 | -------------------------------------------------------------------------------- /util/common_utils.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import hashlib 3 | import json 4 | import random 5 | import secrets 6 | import string 7 | import time 8 | import os 9 | import uuid 10 | from datetime import datetime, timezone, timedelta 11 | from enum import Enum 12 | from http import HTTPStatus 13 | from typing import Optional 14 | 15 | from loguru import logger 16 | 17 | 18 | 19 | class DELAY2(Enum): 20 | account = (2, 3) # 不同帐户之间的秒数延迟 21 | chain = (2, 3) # 不同帐户之间的秒数延迟 22 | 23 | last_sequence = -1 24 | 25 | 26 | def countdown_timer(seconds): 27 | for remaining in range(seconds, 0, -1): 28 | print(f"\r当前线程休眠,剩余: {remaining} 秒", end='', flush=True) 29 | time.sleep(1) 30 | print("\r线程休眠结束,准备下一步操作 ") 31 | 32 | 33 | def sleep(key): 34 | rs = random.randint(key[0], key[1]) 35 | logger.info(f"线程休眠等待 {rs} 秒") 36 | time.sleep(rs) 37 | 38 | 39 | def print_wallet_address(wallet_address): 40 | address = wallet_address[:4] + "****" + wallet_address[-5:] 41 | return address 42 | 43 | 44 | def read_wallets_from_file(file_path): 45 | wallets = [] 46 | with open(file_path, 'r') as file: 47 | for line in file: 48 | address, private_key = line.strip().split(',') 49 | wallets.append({'address': address, 'private_key': private_key}) 50 | return wallets 51 | 52 | 53 | def print_wallet_address_sol(input_string): 54 | if len(input_string) <= 7: 55 | return input_string 56 | else: 57 | visible_prefix = input_string[:3] 58 | visible_suffix = input_string[-4:] 59 | masked_middle = '*' * (len(input_string) - 7) 60 | masked_string = visible_prefix + masked_middle + visible_suffix 61 | return masked_string 62 | 63 | 64 | def read_wallets_from_files(file_names, current_directory, *directories): 65 | wallets = [] 66 | for file_path in file_names: 67 | file_name = os.path.join(current_directory, *directories, file_path) 68 | with open(file_name, 'r', encoding='utf-8') as file: 69 | for line in file: 70 | address, private_key, proxy_ip = line.strip().split(',') 71 | wallets.append( 72 | {'address': address, 'private_key': private_key, 'proxy_ip': proxy_ip}) 73 | return wallets 74 | 75 | def read_users_from_files(file_names, current_directory, *directories): 76 | wallets = [] 77 | for file_path in file_names: 78 | file_name = os.path.join(current_directory, *directories, file_path) 79 | with open(file_name, 'r', encoding='utf-8') as file: 80 | for line in file: 81 | address, proxy_ip = line.strip().split(',') 82 | wallets.append( 83 | {'user': address ,'proxy_ip': proxy_ip}) 84 | return wallets 85 | 86 | 87 | def read_wallets(file_names, current_directory, *directories): 88 | wallets = [] 89 | for file_path in file_names: 90 | file_name = os.path.join(current_directory, *directories, file_path) 91 | with open(file_name, 'r', encoding='utf-8') as file: 92 | for line in file: 93 | address, private_key = line.strip().split(',') 94 | wallets.append( 95 | {'address': address, 'private_key': private_key}) 96 | return wallets 97 | 98 | 99 | def string_in_file(target_string, file_names, current_directory, *directories): 100 | for file_path in file_names: 101 | file_name = os.path.join(current_directory, *directories, file_path) 102 | try: 103 | with open(file_name, 'r', encoding='utf-8') as file: 104 | for line in file: 105 | if target_string in line: 106 | return True 107 | except FileNotFoundError: 108 | print(f"File {file_name} not found.") 109 | return False 110 | 111 | 112 | def get_random_line(filename, current_directory, *directories): 113 | file_name = os.path.join(current_directory, *directories, filename) 114 | with open(file_name, 'r', encoding='utf-8') as file: 115 | lines = file.readlines() 116 | if lines: 117 | return random.choice(lines) 118 | else: 119 | return None 120 | 121 | 122 | def read_wallets_twitter_from_files(file_names, current_directory, *directories): 123 | wallets = [] 124 | for file_path in file_names: 125 | file_name = os.path.join(current_directory, *directories, file_path) 126 | with open(file_name, 'r', encoding='utf-8') as file: 127 | for line in file: 128 | print("当前随机钱包", line) 129 | address, private_key, tw_token, ip_proxy = line.strip().split(',') 130 | wallets.append( 131 | {'address': address, 'private_key': private_key, 'tw_token': tw_token, 'ip_proxy': ip_proxy}) 132 | return wallets 133 | 134 | 135 | def generate_random_string(length): 136 | num_bytes = length // 2 # 一个十六进制字符对应4位二进制,所以需要length//2个字节 137 | random_bytes = secrets.token_bytes(num_bytes) # 生成安全的随机字节 138 | random_string = random_bytes.hex()[:length] # 将随机字节转换为十六进制表示并取前length位 139 | return random_string 140 | 141 | 142 | def generate_random_float(min_value, max_value, decimal_places): 143 | # 生成一个指定范围内的随机浮点数 144 | random_value = random.uniform(min_value, max_value) 145 | 146 | # 四舍五入到指定的小数位数 147 | rounded_float = round(random_value, decimal_places) 148 | 149 | # 格式化为字符串 150 | number_str = "{:.{}f}".format(random_value, decimal_places) 151 | logger.info(f"随机生成金额: {number_str}") 152 | return rounded_float 153 | 154 | 155 | def fmt_float(price, decimal_places): 156 | # 生成一个指定范围内的随机浮点数 157 | # 四舍五入到指定的小数位数 158 | rounded_float = round(price, decimal_places) 159 | 160 | # 格式化为字符串 161 | number_str = "{:.{}f}".format(rounded_float, decimal_places) 162 | logger.info(f"格式化金额: {number_str}") 163 | return rounded_float, number_str 164 | 165 | 166 | def load_abi(file_name, current_directory, *directories, encoding: Optional[str] = None) : 167 | path = os.path.join(current_directory, *directories, file_name) 168 | return json.load(open(path, encoding=encoding)) 169 | 170 | 171 | def read_json(path: str, encoding: Optional[str] = None): 172 | return json.load(open(path, encoding=encoding)) 173 | 174 | 175 | def generate_custom_id(): 176 | global last_sequence 177 | 178 | timestamp = int(time.time() * 1000) # 获取当前时间戳(毫秒) 179 | worker_id = random.randint(0, 1023) # 生成一个随机的工作节点 ID(0-1023) 180 | 181 | # 生成一个不等于上一个序列号的随机序列号 182 | sequence = random.randint(0, 4095) 183 | while sequence == last_sequence: 184 | sequence = random.randint(0, 4095) 185 | 186 | last_sequence = sequence 187 | 188 | prefix = random.randint(17, 57) # 生成一个17到57之间的随机前缀 189 | 190 | # 打乱序列号 191 | sequence_list = list(str(sequence)) 192 | random.shuffle(sequence_list) 193 | shuffled_sequence = int(''.join(sequence_list)) 194 | 195 | # 构造雪花 ID 196 | snowflake_id = ((prefix * 10 ** 16) | (timestamp % 10 ** 16) << 12 | worker_id << 2 | shuffled_sequence) 197 | snowflake_id_str = '{:018d}'.format(snowflake_id) # 将雪花 ID 转换为 18 位字符串 198 | 199 | return snowflake_id_str 200 | 201 | def write_to_file(filename, data, *directories): 202 | file_path = os.path.join(*directories, filename) 203 | # Check if data is already in the file 204 | if data in open(file_path, 'r', encoding='utf-8').read(): 205 | print("已经存在跳过") 206 | else: 207 | with open(file_path, 'a', encoding='utf-8') as file: 208 | file.write(data + '\n') 209 | print("已经写入email.txt") 210 | 211 | def convert_beijing_to_utc(): 212 | # 获取当前北京时间 213 | beijing_time = datetime.now(timezone(timedelta(hours=8))) 214 | 215 | # 将北京时间转换为UTC时间 216 | utc_time = beijing_time.astimezone(timezone.utc) 217 | 218 | # 格式化为ISO 8601字符串 219 | iso_string = utc_time.strftime('%Y-%m-%dT%H:%M:%S.%fZ') 220 | 221 | return iso_string 222 | 223 | 224 | def generate_moca_id(): 225 | # 生成长度在5到20之间的随机整数作为Moca ID的长度 226 | id_length = random.randint(5, 9) 227 | 228 | # 生成包含大小写字母和数字的可选字符集合 229 | characters = string.ascii_letters + string.digits 230 | 231 | # 从可选字符集合中随机选择字符生成Moca ID 232 | moca_id = ''.join(random.choices(characters, k=id_length)) 233 | 234 | return moca_id 235 | 236 | 237 | def to_md5(input_string): 238 | # 创建一个 hashlib.md5 对象 239 | hash_object = hashlib.md5() 240 | 241 | # 更新对象的状态,添加要计算散列值的数据 242 | hash_object.update(input_string.encode('utf-8')) 243 | 244 | # 获取 MD5 散列值的十六进制表示 245 | md5_hash = hash_object.hexdigest() 246 | 247 | return md5_hash 248 | # 示例用法 249 | if __name__ == "__main__": 250 | generated_id = generate_moca_id() 251 | print("Generated ID:", generated_id) 252 | 253 | 254 | --------------------------------------------------------------------------------