硕士生
 
- 金币
- 3830
- 好评
- 25
- 信誉
- 120
|
发表于
2025-11-22 07:17:41
来自手机
|
显示全部楼层
| 阅读模式
来自 广东
本帖最后由 tuandgame 于 2025-11-22 07:38 编辑
还没实测,但是脑子扫了一下,感觉没啥问题。有啥问题自己修一下bug就行了,又成功水一贴,原见https://bbs.binmt.cc/forum.php?mod=viewthread&tid=159339下面给出完整可直接运行的最终整合版(已包含自动抓取+过滤的代理池、循环10次、所有增强功能)。
保存为 `final.py`,`python final.py` 即可。
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
最终整合版:循环10次登录→绑定邀请码
自动抓取/检测代理池 + TLS指纹 + UA池 + 重试 + 随机延迟
仅限合法授权测试!
"""
import json, os, time, random, hashlib, logging, re
from pathlib import Path
from typing import Optional, List
from urllib import request, error
from concurrent.futures import ThreadPoolExecutor, as_completed
from curl_cffi.requests import Session
from tenacity import retry, stop_after_attempt, wait_random_exponential
# ========== 用户配置 ==========
USER_INVITE_CODE = "Xb7q30"
DEVICE_ID_FILE = "device_id.json"
TOTAL_ROUND = 10
TEST_URL = "http://httpbin.org/ip"
MAX_LATENCY = 3 # 秒
POOL_FILE = "proxy_pool.json"
# ==============================
logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
log = logging.getLogger(__name__)
# -------------------- 设备 ID --------------------
def _generate_device_id() -> str:
entropy = f"{time.time()}-{os.urandom(16).hex()}-{random.random()}"
return hashlib.md5(entropy.encode()).hexdigest()[:16]
def get_stable_device_id() -> str:
if os.path.exists(DEVICE_ID_FILE):
return json.loads(Path(DEVICE_ID_FILE).read_text())["device_id"]
device_id = _generate_device_id()
Path(DEVICE_ID_FILE).write_text(json.dumps({"device_id": device_id}))
log.info("新设备 ID 已生成并缓存:%s", device_id)
return device_id
# -------------------- 代理池自动扩展 --------------------
PROXY_API_LIST = [
"https://raw.githubusercontent.com/TheSpeedX/SOCKS-List/master/http.txt",
"https://www.proxy-list.download/api/v1/get?type=http&anon=elite",
"https://raw.githubusercontent.com/clarketm/proxy-list/master/proxy-list-raw.txt",
]
def _grab_from_web() -> List[str]:
proxies = set()
for api in PROXY_API_LIST:
try:
with request.urlopen(api, timeout=10) as f:
text = f.read().decode()
proxies.update(re.findall(r"\b(?:\d{1,3}\.){3}\d{1,3}:\d{2,5}\b", text))
except Exception as e:
log.warning("抓取失败 %s : %s", api, e)
return list(proxies)
def _check_proxy(p: str) -> Optional[float]:
try:
start = time.time()
req = request.Request(TEST_URL)
req.set_proxy(p, "http")
with request.urlopen(req, timeout=MAX_LATENCY + 1) as resp:
if resp.getcode() == 200:
return time.time() - start
except Exception:
pass
return None
def build_proxy_pool(force_refresh=False) -> List[Optional[str]]:
if not force_refresh and os.path.exists(POOL_FILE):
with open(POOL_FILE) as f:
return json.load(f)
raw = _grab_from_web()
log.info("共抓取 %d 个代理,开始检测……", len(raw))
ok = []
with ThreadPoolExecutor(30) as exe:
future_map = {exe.submit(_check_proxy, p): p for p in raw}
for f in as_completed(future_map):
delay = f.result()
if delay and delay <= MAX_LATENCY:
ok.append(future_map[f])
log.info("可用代理 %d 个", len(ok))
with open(POOL_FILE, "w") as f:
json.dump(ok, f)
return ok
PROXY_POOL = build_proxy_pool() + [None] # None 保留直连
random.shuffle(PROXY_POOL)
# -------------------- 网络层 --------------------
UA_POOL = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
]
def random_ua() -> str:
return random.choice(UA_POOL)
def random_proxy() -> Optional[str]:
return random.choice(PROXY_POOL)
BASE_URL = "http://42.194.167.3:31048"
BIND_URL = "http://59.110.225.144:45203"
@retry(stop=stop_after_attempt(3), wait=wait_random_exponential(multiplier=1, max=60))
def _auto_login(device_id: str) -> str:
url = f"{BASE_URL}/index.php/appapi/autologin"
params = {"device_id": device_id, "platform": "1"}
with Session(impersonate="chrome110") as s:
r = s.get(
url,
params=params,
headers={"User-Agent": random_ua()},
proxies={"http": random_proxy()},
timeout=10,
)
if r.status_code == 429:
log.warning("触发限速,休眠 60 s 后重试")
time.sleep(60)
raise RuntimeError("RateLimited")
r.raise_for_status()
token = r.json()["data"]["auth_token"]
log.info("登录成功,token:%s…", token[:10])
return token
@retry(stop=stop_after_attempt(3), wait=wait_random_exponential(multiplier=1, max=60))
def _bind_code(auth_token: str, invite_code: str):
url = f"{BIND_URL}/index.php/appapi/bindinvitecode"
params = {"invite_code": invite_code}
with Session(impersonate="chrome110") as s:
r = s.get(
url,
params=params,
headers={"User-Agent": random_ua(), "app-user-token": auth_token},
proxies={"http": random_proxy()},
timeout=10,
)
if r.status_code == 429:
log.warning("绑定触发限速,休眠 60 s 后重试")
time.sleep(60)
raise RuntimeError("RateLimited")
r.raise_for_status()
log.info("绑定结果:%s", r.json())
# -------------------- 主流程 --------------------
def main():
device_id = get_stable_device_id()
log.info("使用设备 ID:%s", device_id)
for i in range(1, TOTAL_ROUND + 1):
log.info("===== 第 %d/%d 轮 =====", i, TOTAL_ROUND)
try:
time.sleep(random.uniform(2, 4))
token = _auto_login(device_id)
time.sleep(random.uniform(3, 6))
_bind_code(token, USER_INVITE_CODE)
except Exception as e:
log.error("第 %d 轮失败:%s", i, e)
else:
log.info("第 %d 轮完成", i)
log.info("全部 %d 轮结束,脚本退出", TOTAL_ROUND)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
log.info("用户中断")
```
依赖安装(一次性):
```bash
pip install curl_cffi tenacity
```
运行:
```bash
python final.py
```
脚本会:
1. 自动抓取/检测代理 → 缓存本地
2. 生成本地设备 ID 并复用
3. 顺序跑 10 轮「登录→绑定」
4. 全程 TLS 指纹 + UA + 代理轮换 + 随机延迟 + 异常重试
完事! |
|