mirror of
https://github.com/Ytong825/mao.git
synced 2025-12-16 23:10:06 +08:00
807 lines
32 KiB
Python
807 lines
32 KiB
Python
# 当前脚本来自于http://script.345yun.cn脚本库下载!
|
||
#
|
||
#
|
||
# 阅读入口:https://file.52bin.cn/img/ID9/202509/68c63a96f101e.jpeg 微信扫码打开
|
||
# 配置说明:
|
||
# 1. 环境变量 mmyd_ck: 配置cookie账号信息bbus值,支持多账号分隔符:换行符、@、& 例如eyxxxxxxxxx 不要前面的bbus=
|
||
# 2. 环境变量 mmyd_ua: 配置UA信息 https://useragent.todaynav.com/ 微信打开此网站即可 请使用你的微信的User-Agent
|
||
# 3. 环境变量 mmyd_url: 检测文章提交接口的URL(可选,如http://192.168.124.201:9900/check_read)请使用自己的这个只是例子
|
||
# 4. 环境变量 mmyd_token: PushPlus推送加token(可选)
|
||
# 5. 环境变量 mmyd_tx: PushPlus推送加token(可选)
|
||
# 使用说明:
|
||
# - 首账号采用固定邀请码,请wx点击阅读入口。
|
||
# - 支持多账号批量运行,自动刷新Cookie
|
||
# - 自动检测文章并推送通知(需配置mmyd_token)
|
||
# - 自动提现功能,满足5000金币自动提现
|
||
# - 如果配置了mmyd_url,会先尝试自动过检,失败则推送通知
|
||
#
|
||
# 本脚本仅供学习交流,请在下载后的24小时内完全删除
|
||
# 请勿用于商业用途或非法目的,否则后果自负
|
||
|
||
# 固定注释内容
|
||
fixed_comments = """# 猫猫阅读脚本 4.0
|
||
#
|
||
# 阅读入口:https://file.52bin.cn/img/ID9/202509/68c63a96f101e.jpeg 微信扫码打开
|
||
#
|
||
# 配置说明:
|
||
# 1. 环境变量 mmyd_ck: 配置cookie账号信息bbus值,支持多账号分隔符:换行符、@、&
|
||
# 2. 环境变量 mmyd_ua: 配置UA信息 https://useragent.todaynav.com/ 微信打开此网站即可 请使用你的微信的User-Agent
|
||
# 3. 环境变量 mmyd_url: 检测文章提交接口的URL(可选,如http://192.168.124.201:9900/check_read)
|
||
# 4. 环境变量 mmyd_token: PushPlus推送加token(可选)
|
||
#
|
||
# 使用说明:
|
||
# - 首账号采用固定邀请码,请wx点击阅读入口。
|
||
# - 支持多账号批量运行,自动刷新Cookie
|
||
# - 自动检测文章并推送通知(需配置mmyd_token)
|
||
# - 自动提现功能,满足5000金币自动提现
|
||
# - 如果配置了mmyd_url,会先尝试自动过检,失败则推送通知
|
||
#
|
||
# 本脚本仅供学习交流,请在下载后的24小时内完全删除
|
||
# 请勿用于商业用途或非法目的,否则后果自负"""
|
||
|
||
|
||
|
||
import requests
|
||
import json
|
||
import os
|
||
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
|
||
import re
|
||
import time
|
||
import random
|
||
from requests.exceptions import RequestException
|
||
|
||
|
||
# 创建全局 session
|
||
session = requests.Session()
|
||
|
||
# API认证相关
|
||
API_URL = os.getenv("mmyd_url") # 检测文章提交接口URL
|
||
PUSH_TOKEN = os.getenv("mmyd_token") # PushPlus推送token
|
||
UA_USER_AGENT = os.getenv("mmyd_ua") # UA
|
||
PROXY_URL = os.getenv("mmyd_proxy") #代理
|
||
|
||
# 新增: PushPlus通知函数
|
||
def send_pushplus_notification(token, title, content):
|
||
"""使用PushPlus发送通知"""
|
||
try:
|
||
url_pushplus = "http://www.pushplus.plus/send"
|
||
data_pushplus = {
|
||
"token": token,
|
||
"title": title,
|
||
"content": content,
|
||
"template": "html"
|
||
}
|
||
response = requests.post(url_pushplus, data=data_pushplus, timeout=10)
|
||
response.raise_for_status()
|
||
result = response.json()
|
||
if result.get("code") == 200:
|
||
print(f"✅ PushPlus通知发送成功", flush=True)
|
||
else:
|
||
print(f"❗ PushPlus通知发送失败: {result.get('msg', '未知错误')}", flush=True)
|
||
except Exception as e:
|
||
print(f"❗ PushPlus通知请求异常: {str(e)}", flush=True)
|
||
|
||
|
||
def fetch_luodi_url():
|
||
url = "http://thr.zuoanai.cn/baobaocode.php"
|
||
headers = {
|
||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
||
"Connection": "keep-alive",
|
||
"Host": "thr.zuoanai.cn",
|
||
"Referer": "http://thr.zuoanai.cn/",
|
||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0",
|
||
"X-Requested-With": "XMLHttpRequest"
|
||
}
|
||
resp = session.get(url, headers=headers, timeout=15, proxies=proxies)
|
||
resp.raise_for_status()
|
||
data = resp.json()
|
||
luodi_url = data.get("data", {}).get("luodi")
|
||
print(f"获取到活动地址: {luodi_url}")
|
||
return luodi_url
|
||
|
||
|
||
def get_first_redirect(luodi_url):
|
||
parsed = urlparse(luodi_url)
|
||
host = parsed.hostname
|
||
path = parsed.path + (f"?{parsed.query}" if parsed.query else "")
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/tpg,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"X-Requested-With": "com.tencent.mm",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
|
||
}
|
||
url = f"http://{host}{path}"
|
||
resp = session.get(url, headers=headers, allow_redirects=False, timeout=15)
|
||
if resp.status_code == 302:
|
||
location = resp.headers.get('Location')
|
||
# print(f"302跳转地址: {location}")
|
||
parsed2 = urlparse(location)
|
||
new_host = parsed2.hostname
|
||
m = re.search(r'/haobaobao/([^/?]+)', parsed2.path)
|
||
cid = m.group(1) if m else None
|
||
# print(f"新域名: {new_host}, cid: {cid}")
|
||
return new_host, cid
|
||
else:
|
||
print(f"未返回302,状态码: {resp.status_code}")
|
||
print(resp.text)
|
||
return None, None
|
||
|
||
|
||
def get_redirect_url(code, cid):
|
||
url = f"http://soicq.hzyunyan.cn/blank_ground.html?type=bao&cid={cid}&code={code}&state=1"
|
||
headers = {
|
||
"Host": "soicq.hzyunyan.cn",
|
||
"Connection": "keep-alive",
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||
"X-Requested-With": "com.tencent.mm",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
|
||
}
|
||
resp = session.get(url, headers=headers, allow_redirects=False, timeout=15)
|
||
if resp.status_code == 302:
|
||
location = resp.headers.get('Location')
|
||
# print(f"redirect接口302 Location: {location}")
|
||
return location
|
||
else:
|
||
print(f"redirect接口未返回302,状态码: {resp.status_code}")
|
||
print(resp.text)
|
||
return None
|
||
|
||
|
||
def get_bbus_from_url(bbus_url):
|
||
# 处理q参数,去掉v前缀
|
||
parsed = urlparse(bbus_url)
|
||
qs = parse_qs(parsed.query)
|
||
# 处理q参数
|
||
if 'q' in qs and qs['q']:
|
||
qval = qs['q'][0]
|
||
if qval.startswith('v') and len(qval) > 1:
|
||
qs['q'][0] = qval[1:]
|
||
# 处理v参数,替换为当前时间戳减6小时2秒
|
||
if 'v' in qs and qs['v']:
|
||
now = int(time.time())
|
||
v_new = now - (6 * 3600)
|
||
qs['v'][0] = str(v_new)
|
||
new_query = urlencode(qs, doseq=True)
|
||
bbus_url = urlunparse(parsed._replace(query=new_query))
|
||
headers = {
|
||
"Host": parsed.hostname,
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||
"Connection": "keep-alive"
|
||
}
|
||
resp = session.get(bbus_url, headers=headers, timeout=15)
|
||
# print(resp.text)
|
||
print(f"请求: {bbus_url}")
|
||
print("--- 响应标头 ---")
|
||
for k, v in resp.headers.items():
|
||
print(f"{k}: {v}")
|
||
set_cookie = resp.headers.get('Set-Cookie', '')
|
||
m = re.search(r'bbus=([^;]+)', set_cookie)
|
||
bbus = m.group(1) if m else None
|
||
print(f"bbus: {bbus}")
|
||
return bbus
|
||
|
||
|
||
def get_location_domain(cid, bbus, new_host):
|
||
"""
|
||
1. GET /haobaobao/v{cid}?v=xxx,带 bbus cookie,获取 302 Location 域名
|
||
返回 (location_url, location_domain)
|
||
"""
|
||
v = int(time.time())
|
||
url = f"http://{new_host}/haobaobao/v{cid}?v={v}"
|
||
headers = {
|
||
"Host": new_host,
|
||
"Connection": "keep-alive",
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/tpg,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"X-Requested-With": "com.tencent.mm",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}"
|
||
}
|
||
resp = session.get(url, headers=headers, allow_redirects=False, timeout=15)
|
||
location = resp.headers.get('Location')
|
||
if not location:
|
||
print(f"未获取到Location,状态码: {resp.status_code}")
|
||
return None, None
|
||
# 提取域名
|
||
parsed = urlparse(location)
|
||
location_domain = parsed.hostname
|
||
# print(f"Location: {location}\nLocation域名: {location_domain}")
|
||
return location, location_domain
|
||
|
||
|
||
def post_mwtmpdomain(location_domain, bbus):
|
||
"""
|
||
2. POST /mwtmpdomain,带 bbus cookie,返回 domain/sk
|
||
"""
|
||
url = f"http://{location_domain}/mwtmpdomain"
|
||
headers = {
|
||
"Host": location_domain,
|
||
"Connection": "keep-alive",
|
||
"Content-Length": "0",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||
"X-Requested-With": "XMLHttpRequest",
|
||
"Origin": f"http://{location_domain}",
|
||
"Referer": f"http://{location_domain}/haobaobao/home?v=1700447805",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}"
|
||
}
|
||
resp = session.post(url, headers=headers, timeout=15)
|
||
try:
|
||
data = resp.json()
|
||
domain_url = data['data']['domain']
|
||
from urllib.parse import urlparse, parse_qs
|
||
parsed = urlparse(domain_url)
|
||
qs = parse_qs(parsed.query)
|
||
sk = qs.get('sk', [None])[0]
|
||
# print(f"domain: {domain_url}\nsk: {sk}")
|
||
return domain_url, sk
|
||
except Exception as e:
|
||
print(f"解析domain/sk失败: {e}")
|
||
return None, None
|
||
|
||
|
||
def get_user_url(cid, bbus, new_host):
|
||
"""
|
||
综合流程:
|
||
1. 通过 get_location_domain 获取 Location 域名
|
||
2. 通过 post_mwtmpdomain 获取 domain/sk
|
||
返回 domain_url, sk
|
||
"""
|
||
location_url, location_domain = get_location_domain(cid, bbus, new_host)
|
||
if not location_domain:
|
||
return None, None
|
||
domain_url, sk = post_mwtmpdomain(location_domain, bbus)
|
||
return domain_url, sk
|
||
|
||
|
||
def get_article_link(host, sk):
|
||
"""
|
||
获取文章link
|
||
"""
|
||
now_ms = int(time.time() * 1000)
|
||
mysign = random.randint(100, 999)
|
||
vs = random.randint(100, 200)
|
||
rmemakdk_url = f"http://{host}/smkrdeas?time={now_ms}&mysign={mysign}&vs={vs}&sk={sk}"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||
"X-Requested-With": "XMLHttpRequest",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
|
||
}
|
||
# print(f"\n📖 请求文章任务: {rmemakdk_url}")
|
||
resp = session.get(rmemakdk_url, headers=headers, timeout=15)
|
||
return resp.json()
|
||
|
||
|
||
def visit_article_link(link):
|
||
"""
|
||
访问文章link,模拟阅读
|
||
"""
|
||
article_headers = {
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Connection": "keep-alive"
|
||
}
|
||
print(f"📖 开始模拟阅读文章...")
|
||
resp = session.get(link, headers=article_headers, timeout=15)
|
||
return resp
|
||
|
||
|
||
def submit_read_result(host, sk, sleep_time):
|
||
"""
|
||
提交阅读完成
|
||
"""
|
||
psign = random.randint(200, 400)
|
||
jiajinbimao_url = f"http://{host}/jiajinbimao?time={sleep_time}&psign={psign}&sk={sk}"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||
"X-Requested-With": "XMLHttpRequest",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
|
||
}
|
||
# print(f"📖 提交阅读完成")
|
||
resp2 = session.get(jiajinbimao_url, headers=headers, timeout=15)
|
||
return resp2.json()
|
||
|
||
|
||
def read_article(domain_url, sk):
|
||
"""
|
||
1. GET /rmemakdk 获取文章link
|
||
2. 请求link,等待20-30秒
|
||
3. GET /jiajinbimao 获取阅读结果
|
||
检测文章biz特殊处理:如biz在检测列表,等待120-130秒,提示手动阅读
|
||
"""
|
||
check_biz_list = [
|
||
"MzkzMTYyMDU0OQ==", "Mzk0NDcxMTk2MQ==",
|
||
"MzkzNTYxOTgyMA==", "MzkzNDYxODY5OA==",
|
||
"MzkwNzYwNDYyMQ==", "MzkyNjY0MTExOA==",
|
||
"MzkwMTYwNzcwMw==", "Mzg4NTcwODE1NA==",
|
||
"MzkyMjYxNzQ2NA==", "Mzk4ODQzNjU1OQ==",
|
||
"MzkyMTc0MDU5Nw==", "Mzk4ODQzNzU3NA==",
|
||
"Mzk5MDc1MDQzOQ==",
|
||
]
|
||
parsed = urlparse(domain_url)
|
||
host = parsed.hostname
|
||
# 1. 获取文章link
|
||
try:
|
||
data = get_article_link(host, sk)
|
||
link = data.get('data', {}).get('link')
|
||
if not link:
|
||
if data.get('errcode') == 407:
|
||
print('⚠️ 60分钟后可继续阅读!')
|
||
elif data.get('errcode') == 405:
|
||
print(f"❌ {data.get('msg')}")
|
||
else:
|
||
print(f"❌ 未获取到文章link: {data}")
|
||
return False
|
||
# print(f"✅ 获取到文章: {link}")
|
||
# 提取biz
|
||
biz_match = parse_qs(urlparse(link).query).get('__biz', [None])[0]
|
||
print(f"文章标题: {biz_match}")
|
||
print(f"📖 开始阅读: {link}", flush=True)
|
||
# 检测文章特殊处理
|
||
auto_checked = False
|
||
if biz_match in check_biz_list or biz_match is None:
|
||
wait_time = random.randint(120, 130)
|
||
title = "⚠️ 猫猫检测文章!请在120s内完成阅读!"
|
||
content = f"""
|
||
⚠️ 请在120s内完成阅读!
|
||
⚠️ 每次阅读不得少于8秒!
|
||
文章链接:{link}
|
||
当前时间 {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}
|
||
"""
|
||
# 自动过检逻辑
|
||
auto_checked = False
|
||
if API_URL:
|
||
print(f"送入自动过检...")
|
||
payload = {"url": link,"ck":bbus,"ua":UA_USER_AGENT,'version':'3.0'}
|
||
try:
|
||
resp = requests.post(API_URL, json=payload, timeout=60).json()
|
||
if resp['status'] == 'success':
|
||
time.sleep(25)
|
||
print(f"✅ 自动过检成功,跳过推送")
|
||
auto_checked = True
|
||
else:
|
||
print(f"❌ 自动过检失败", resp['message'])
|
||
except Exception as e:
|
||
print(f"自动过检请求异常: {e}")
|
||
|
||
if not auto_checked:
|
||
if PUSH_TOKEN:
|
||
print("开始推送文章...")
|
||
send_pushplus_notification(PUSH_TOKEN, title, content)
|
||
else:
|
||
print("未配置推送token,尝试使用青龙配置文件推送")
|
||
print(QLAPI.notify(title, content))
|
||
print(f"⏳ 检测文章等待 {wait_time} 秒...")
|
||
time.sleep(wait_time)
|
||
# 检测文章不请求link,但需要调用jiajinbimao接口
|
||
sleep_time = random.randint(9, 18)
|
||
else:
|
||
# 2. 请求 link,等待20-30秒
|
||
try:
|
||
print(link)
|
||
visit_article_link(link)
|
||
sleep_time = random.randint(9, 18)
|
||
print(f"⏳ 等待 {sleep_time} 秒模拟阅读...")
|
||
time.sleep(sleep_time)
|
||
except Exception as e:
|
||
print(f"❌ 阅读文章请求失败: {e}")
|
||
return False
|
||
# 3. GET /jiajinbimao 获取阅读结果
|
||
max_retries = 3
|
||
for retry_count in range(max_retries):
|
||
try:
|
||
data2 = submit_read_result(host, sk, sleep_time)
|
||
if data2.get('errcode') == 0:
|
||
d = data2.get('data', {})
|
||
print(
|
||
f"✅ 阅读完成!本次金币: {d.get('gold')},今日已读: {d.get('day_read')},今日金币: {d.get('day_gold')},当前金币: {d.get('last_gold')},剩余可读: {d.get('remain_read')}")
|
||
return True
|
||
elif data2.get('errcode') == 405 and '未能获取到用户信息' in str(data2.get('msg')):
|
||
print(f"⚠️ 第 {retry_count + 1}/{max_retries} 次获取用户信息失败: {data2.get('msg')},正在重试...")
|
||
if retry_count == max_retries - 1:
|
||
print(f"❌ 连续 {max_retries} 次用户信息获取失败,退出运行")
|
||
return False
|
||
time.sleep(2)
|
||
continue
|
||
else:
|
||
print(f"❌ 阅读完成接口返回失败: {data2}")
|
||
return False
|
||
except requests.exceptions.ReadTimeout:
|
||
print(f"⏰ 第 {retry_count + 1}/{max_retries} 次请求超时,正在重试...")
|
||
if retry_count == max_retries - 1:
|
||
print(f"❌ 连续 {max_retries} 次请求超时,退出运行")
|
||
return False
|
||
time.sleep(2)
|
||
except Exception as e:
|
||
print(f"❌ 阅读完成接口请求失败: {e}")
|
||
return False
|
||
except Exception as e:
|
||
print(f"❌ 解析文章任务响应失败: {e}")
|
||
return False
|
||
|
||
|
||
def confirm_withdraw(domain_url, bbus, signid):
|
||
"""
|
||
确认提现
|
||
"""
|
||
from urllib.parse import urlparse
|
||
host = urlparse(domain_url).hostname
|
||
url = f"http://{host}/haobaobao/getwithdraw"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||
"Origin": f"http://{host}",
|
||
"Referer": f"http://{host}/haobaobao/withdraw",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}",
|
||
"X-Requested-With": "XMLHttpRequest"
|
||
}
|
||
data = f"signid={signid}&ua=2&ptype=0&paccount=&pname="
|
||
# print(f"\n🔄 正在确认提现")
|
||
resp = session.post(url, headers=headers, data=data, timeout=15)
|
||
try:
|
||
res_json = resp.json()
|
||
if res_json.get('errcode') == 0:
|
||
print("✅ 确认提现成功")
|
||
else:
|
||
if res_json.get('errcode') == 405:
|
||
print(res_json.get('msg').replace("<br>", "\n"))
|
||
else:
|
||
print(f"❌ 确认提现失败: {res_json}")
|
||
except Exception as e:
|
||
print(f"❌ 确认提现响应解析失败: {e}")
|
||
|
||
|
||
def get_user_info_and_withdraw(domain_url, bbus):
|
||
"""
|
||
获取用户信息并自动提现
|
||
"""
|
||
from urllib.parse import urlparse
|
||
host = urlparse(domain_url).hostname
|
||
withdraw_url = f"http://{host}/haobaobao/withdraw"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/tpg,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"X-Requested-With": "com.tencent.mm",
|
||
"Referer": f"http://{host}/haobaobao/home?v=1751942506",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}"
|
||
}
|
||
try:
|
||
resp = session.get(withdraw_url, headers=headers, timeout=30)
|
||
except requests.exceptions.ReadTimeout as e:
|
||
print(f"[超时] 获取用户信息/提现页面超时: {e}")
|
||
return None
|
||
except Exception as e:
|
||
print(f"[异常] 获取用户信息/提现页面失败: {e}")
|
||
return None
|
||
html = resp.text
|
||
|
||
# 提取参数
|
||
def extract_var(varname):
|
||
m = re.search(rf'var {varname} ?= ?["\']?([^;"\']+)["\']?;', html)
|
||
return m.group(1) if m else None
|
||
|
||
request_id = extract_var('request_id')
|
||
nickname = extract_var('nickname')
|
||
qrcode_num = extract_var('qrcode_num')
|
||
isallowtj = extract_var('isallowtj')
|
||
# 提取金币
|
||
m_gold = re.search(r'<p class="f_left" id="exchange_gold">(\d+)</p>', html)
|
||
exchange_gold = int(m_gold.group(1)) if m_gold else 0
|
||
print(f"用户ID: {nickname}")
|
||
print(f"邀请人ID: {qrcode_num}")
|
||
# print(f"是否可提现(isallowtj): {isallowtj}")
|
||
print(f"当前金币: {exchange_gold}")
|
||
# print(f"request_id: {request_id}")
|
||
# 自动提现
|
||
gold = (exchange_gold // 1000) * 1000
|
||
if gold == 0 or not request_id:
|
||
print("❌ 无法提现,金币不足或request_id缺失")
|
||
return request_id
|
||
if gold < MIN_WITHDRAW_GOLD:
|
||
print(f"❌ 当前金币 {gold} 未达到提现门槛 {MIN_WITHDRAW_GOLD},跳过提现")
|
||
return request_id
|
||
post_url = f"http://{host}/haobaobao/getgold"
|
||
post_headers = headers.copy()
|
||
post_headers.update({
|
||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||
"Origin": f"http://{host}",
|
||
"Referer": f"http://{host}/haobaobao/withdraw",
|
||
"Accept": "application/json, text/javascript, */*; q=0.01"
|
||
})
|
||
data = f"request_id={request_id}&gold={gold}"
|
||
print(f"\n💸 正在发起提现,金币: {gold}")
|
||
resp2 = session.post(post_url, headers=post_headers, data=data, timeout=15)
|
||
try:
|
||
res_json = resp2.json()
|
||
if res_json.get('errcode') == 0:
|
||
money = res_json.get('data', {}).get('money')
|
||
print(f"✅ 提现成功,金额: {money}")
|
||
else:
|
||
if res_json.get('errcode') == 405:
|
||
print(res_json.get('msg').replace("<br>", "\n"))
|
||
else:
|
||
print(f"❌ 提现失败: {res_json}")
|
||
except Exception as e:
|
||
print(f"❌ 提现响应解析失败: {e}")
|
||
return request_id
|
||
|
||
|
||
def get_promotion_link(domain_url, bbus):
|
||
"""
|
||
获取推广链接,输出qrcodes1和作者推广链接
|
||
"""
|
||
from urllib.parse import urlparse
|
||
|
||
host = urlparse(domain_url).hostname
|
||
url = f"http://{host}/tiyvaewmk?v=1"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||
"X-Requested-With": "XMLHttpRequest",
|
||
"Referer": f"http://{host}/haobaobao/showcode",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}"
|
||
}
|
||
try:
|
||
resp = session.get(url, headers=headers, timeout=15)
|
||
data = resp.json()
|
||
if data.get('errcode') == 0:
|
||
qrcodes1 = data.get('data', {}).get('qrcodes', {}).get('qrcodes1')
|
||
if qrcodes1:
|
||
# print(f"[🌟 推广链接] {qrcodes1}")
|
||
# 输出作者推广链接
|
||
# 替换kstief/后面的内容
|
||
author_link = re.sub(r'(kstief/)[^/?]+(\?tsd=\d+)?', lambda m: m.group(1) + author_code, qrcodes1)
|
||
print(f"[👨💻 作者推广链接] {author_link}")
|
||
else:
|
||
print("[❌ 推广链接] 未找到qrcodes1")
|
||
else:
|
||
print(f"[❌ 推广链接] 获取失败: {data}")
|
||
except Exception as e:
|
||
print(f"[❌ 推广链接] 请求异常: {e}")
|
||
|
||
|
||
def refresh_cookie(domain_url, bbus):
|
||
"""
|
||
刷新cookie,GET /haobaobao/v1{author_code}?v=...,响应302为成功
|
||
"""
|
||
from urllib.parse import urlparse
|
||
import time
|
||
host = urlparse(domain_url).hostname
|
||
v = int(time.time())
|
||
author_code = "1b69893ab98f0fd50e13e7d3e19d3c65" # 与全局变量保持一致
|
||
url = f"http://{host}/haobaobao/v1{author_code}?v={v}"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"X-Requested-With": "com.tencent.mm",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}"
|
||
}
|
||
try:
|
||
resp = session.get(url, headers=headers, allow_redirects=False, timeout=10)
|
||
if resp.status_code == 302:
|
||
print(f"[Cookie刷新] 刷新成功")
|
||
return True
|
||
else:
|
||
print(f"[Cookie刷新] {host} 刷新失败,状态码: {resp.status_code}")
|
||
return False
|
||
except Exception as e:
|
||
print(f"[Cookie刷新] {host} 请求异常: {e}")
|
||
return False
|
||
|
||
|
||
def enter_home(domain_url, bbus):
|
||
"""
|
||
进入主页,返回True表示成功,False表示失败
|
||
"""
|
||
try:
|
||
import time
|
||
from urllib.parse import urlparse
|
||
host = urlparse(domain_url).hostname
|
||
v = int(time.time())
|
||
home_url = f"http://{host}/haobaobao/home?v={v}"
|
||
headers = {
|
||
"Host": host,
|
||
"Connection": "keep-alive",
|
||
"Upgrade-Insecure-Requests": "1",
|
||
"User-Agent": UA_USER_AGENT,
|
||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/wxpic,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||
"X-Requested-With": "com.tencent.mm",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||
"Cookie": f"bbus={bbus}"
|
||
}
|
||
resp = session.get(home_url, headers=headers, timeout=10)
|
||
if resp.status_code == 200:
|
||
# print(f"[主页] 进入主页成功")
|
||
return True
|
||
else:
|
||
print(f"[Cookie刷新] Cookie刷新失败,状态码: {resp.status_code}")
|
||
return False
|
||
except Exception as e:
|
||
print(f"[Cookie刷新] Cookie刷新请求异常: {e}")
|
||
return False
|
||
|
||
|
||
# ===== 全局变量配置区 =====
|
||
MAX_RUNS = 30
|
||
author_code = "6c3a4d61c4b9467a869f21007fc8e4fc?tsd=971"
|
||
MIN_WITHDRAW_GOLD = 5000 # 新增:提现所需最小金币数
|
||
|
||
|
||
if __name__ == "__main__":
|
||
|
||
MULTI_ACCOUNT_SPLIT = ["\n", "@", "&"] # 分隔符列表
|
||
BBUS_LIST_OS = os.getenv(f"mmyd_ck")
|
||
if not BBUS_LIST_OS:
|
||
print("❌ 未配置cookie,程序无法继续执行,即将退出", flush=True)
|
||
exit(1)
|
||
BBUS_LIST = []
|
||
if BBUS_LIST_OS:
|
||
# 多分隔符分割
|
||
split_pattern = '|'.join(map(re.escape, MULTI_ACCOUNT_SPLIT))
|
||
bbus_items = [x for x in re.split(split_pattern, BBUS_LIST_OS) if x.strip()]
|
||
print(f"🔍 从环境变量获取cookie: {len(bbus_items)} 个")
|
||
BBUS_LIST.extend(bbus_items)
|
||
|
||
print(f"从环境变量中获取到了,共{len(BBUS_LIST)}个账号")
|
||
print(BBUS_LIST)
|
||
# 检查自动过检配置
|
||
if API_URL:
|
||
print(f"✅ 已配置自动过检接口: {API_URL}")
|
||
else:
|
||
print("ℹ️ 未配置自动过检接口,检测文章将直接推送通知")
|
||
|
||
# 检查推送token配置
|
||
if PUSH_TOKEN:
|
||
print(f"✅ 已配置推送token: {PUSH_TOKEN}")
|
||
else:
|
||
print("ℹ️ 未配置推送token,检测文章将不会推送通知")
|
||
|
||
# 检查代理配置
|
||
if PROXY_URL:
|
||
print(f"✅ 已配置代理: {PROXY_URL}")
|
||
else:
|
||
print("ℹ️ 未配置代理,采用本地请求")
|
||
|
||
# 最大运行次数,默认30次
|
||
# MAX_RUNS = 30 # This line is removed as MAX_RUNS is now a global variable
|
||
print(f"检测到共{len(BBUS_LIST)}个账号")
|
||
for idx, bbus in enumerate(BBUS_LIST):
|
||
proxies = {}
|
||
if PROXY_URL:
|
||
try:
|
||
get_ip = requests.get(PROXY_URL).text
|
||
proxies = {
|
||
"http": f"http://{get_ip}",
|
||
"https": f"http://{get_ip}",
|
||
}
|
||
session.proxies = proxies
|
||
except Exception as e:
|
||
print('获取代理失败,使用本地网络执行')
|
||
|
||
|
||
print(f"\n{'=' * 10}🔰开始执行账号{idx + 1}🔰{'=' * 10}\n", flush=True)
|
||
try:
|
||
luodi_url = fetch_luodi_url()
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 获取活动地址失败: {e}")
|
||
continue
|
||
if not luodi_url:
|
||
continue
|
||
try:
|
||
new_host, cid = get_first_redirect(luodi_url)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 获取跳转地址失败: {e}")
|
||
continue
|
||
if not new_host or not cid:
|
||
continue
|
||
# 获取nLocation域名
|
||
try:
|
||
location_url, location_domain = get_location_domain(cid, bbus, new_host)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 获取nLocation域名失败: {e}")
|
||
continue
|
||
if not location_domain:
|
||
continue
|
||
# 用nLocation域名拼成domain_url
|
||
nlocation_domain_url = f"http://{location_domain}"
|
||
# 刷新cookie
|
||
try:
|
||
refresh_cookie(nlocation_domain_url, bbus)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 刷新cookie失败: {e}")
|
||
continue
|
||
# 刷新后进入主页
|
||
try:
|
||
enter_home(nlocation_domain_url, bbus)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 进入主页失败: {e}")
|
||
continue
|
||
# 后续流程依然用原有domain_url, sk
|
||
try:
|
||
domain_url, sk = post_mwtmpdomain(location_domain, bbus)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 获取domain_url/sk失败: {e}")
|
||
continue
|
||
# print(f"最终用户url: {domain_url}\nsk: {sk}")
|
||
for run_count in range(1, MAX_RUNS + 1):
|
||
print(f"\n🔄 第 {run_count}/{MAX_RUNS} 次运行")
|
||
print("-" * 50)
|
||
try:
|
||
success = read_article(domain_url, sk)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 阅读文章失败: {e}")
|
||
break
|
||
if not success:
|
||
print(f"❌ 第 {run_count} 次运行失败")
|
||
break
|
||
# print(f"✅ 第 {run_count} 次运行完成")
|
||
if run_count < MAX_RUNS:
|
||
wait_time = random.randint(2, 5)
|
||
print(f"⏳ 等待 {wait_time} 秒后继续下一次运行...")
|
||
time.sleep(wait_time)
|
||
print(f"\n🎉 账号运行完成!共运行 {run_count} 次")
|
||
try:
|
||
request_id = get_user_info_and_withdraw(nlocation_domain_url, bbus)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 获取用户信息/提现失败: {e}")
|
||
continue
|
||
# 新增:获取推广链接
|
||
try:
|
||
get_promotion_link(nlocation_domain_url, bbus)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 获取推广链接失败: {e}")
|
||
continue
|
||
time.sleep(random.randint(2, 3))
|
||
try:
|
||
confirm_withdraw(nlocation_domain_url, bbus, request_id)
|
||
except requests.exceptions.ConnectionError as e:
|
||
print(f"[连接错误] 确认提现失败: {e}")
|
||
continue
|
||
# 当前脚本来自于http://script.345yun.cn脚本库下载! |