Files
weibo_signin/debug_full_signin.py

277 lines
9.6 KiB
Python
Raw Normal View History

"""
完整签到流程验证脚本
1. 用缓存 cookie 验证登录
2. 获取超话列表 (GET /ajax/profile/topicContent?tabid=231093_-_chaohua)
3. 逐个签到 (GET /p/aj/general/button?api=...checkin&id={containerid})
4. 汇总结果
Cookie 自动从 debug_cookies.json 加载失效才重新扫码
"""
import re, json, time, sys, os, requests
WEIBO_HEADERS = {
'User-Agent': (
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0'
),
'Referer': 'https://weibo.com/',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
}
COOKIE_FILE = 'debug_cookies.json'
def parse_jsonp(text):
if not text: return None
m = re.search(r'STK_\d+\s*\((.*)\)\s*;?\s*$', text, re.DOTALL)
if m:
try: return json.loads(m.group(1))
except: pass
m = re.search(r'\w+\s*\((.*)\)\s*;?\s*$', text, re.DOTALL)
if m:
try: return json.loads(m.group(1))
except: pass
try: return json.loads(text)
except: return None
def save_cookies(cookies, uid, nick):
with open(COOKIE_FILE, 'w', encoding='utf-8') as f:
json.dump({'cookies': cookies, 'uid': uid, 'nick': nick, 'time': time.time()},
f, ensure_ascii=False, indent=2)
def load_cookies():
if not os.path.exists(COOKIE_FILE):
return None, None, None
try:
with open(COOKIE_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
cookies = data.get('cookies', {})
uid = data.get('uid', '')
nick = data.get('nick', '')
age = time.time() - data.get('time', 0)
print(f"{COOKIE_FILE} 加载 (uid={uid}, nick={nick}, {age/3600:.1f}h ago)")
r = requests.get('https://weibo.com/ajax/side/cards', params={'count': 1},
cookies=cookies, headers=WEIBO_HEADERS, timeout=10)
if r.json().get('ok') == 1:
print(f" ✅ Cookie 有效")
return cookies, uid, nick
print(f" ❌ Cookie 已失效")
except Exception as e:
print(f" 加载失败: {e}")
return None, None, None
def qrcode_login():
print(" 扫码登录...")
sess = requests.Session()
sess.headers.update(WEIBO_HEADERS)
resp = sess.get('https://login.sina.com.cn/sso/qrcode/image',
params={'entry': 'weibo', 'size': '180',
'callback': f'STK_{int(time.time()*1000)}'}, timeout=10)
data = parse_jsonp(resp.text)
if not data or not isinstance(data.get('data'), dict):
print(f" ❌ 生成二维码失败"); sys.exit(1)
qrid = data['data']['qrid']
image = data['data']['image']
if image.startswith('//'): image = 'https:' + image
with open('qrcode.png', 'wb') as f:
f.write(requests.get(image, timeout=10).content)
print(f" 请扫描 qrcode.png ...")
alt_token = None
last = None
for i in range(120):
time.sleep(2)
resp = sess.get('https://login.sina.com.cn/sso/qrcode/check',
params={'entry': 'weibo', 'qrid': qrid,
'callback': f'STK_{int(time.time()*1000)}'}, timeout=10)
d = parse_jsonp(resp.text)
rc = d.get('retcode') if d else None
if rc != last: print(f" [{i+1}] {last} -> {rc}"); last = rc
if rc == 20000000 and isinstance(d.get('data'), dict) and d['data'].get('alt'):
alt_token = d['data']['alt']; break
if rc in (50114004, 50050002): sys.exit(1)
if not alt_token: sys.exit(1)
sso = requests.Session()
sso.headers.update(WEIBO_HEADERS)
resp = sso.get(
f"https://login.sina.com.cn/sso/login.php?entry=weibo&returntype=TEXT"
f"&crossdomain=1&cdult=3&domain=weibo.com&alt={alt_token}&savestate=30"
f"&callback=STK_{int(time.time()*1000)}",
allow_redirects=True, timeout=15)
sso_data = parse_jsonp(resp.text)
uid = str(sso_data.get('uid', ''))
nick = sso_data.get('nick', '')
for u in sso_data.get('crossDomainUrlList', []):
if isinstance(u, str) and u.startswith('http'):
try: sso.get(u, allow_redirects=True, timeout=10)
except: pass
cookies = {}
for c in sso.cookies:
if c.domain and 'weibo.com' in c.domain:
cookies[c.name] = c.value
print(f" ✅ uid={uid}, nick={nick}")
save_cookies(cookies, uid, nick)
return cookies, uid, nick
def get_super_topics(sess, xsrf, uid):
"""获取关注的超话列表"""
topics = []
page = 1
while page <= 10:
r = sess.get(
'https://weibo.com/ajax/profile/topicContent',
params={'tabid': '231093_-_chaohua', 'page': str(page)},
headers={
'Referer': f'https://weibo.com/u/page/follow/{uid}/231093_-_chaohua',
'X-XSRF-TOKEN': xsrf,
'X-Requested-With': 'XMLHttpRequest',
},
timeout=10,
)
d = r.json()
if d.get('ok') != 1:
break
topic_list = d.get('data', {}).get('list', [])
if not topic_list:
break
for item in topic_list:
title = item.get('topic_name', '') or item.get('title', '')
# 从 oid "1022:100808xxx" 提取 containerid
containerid = ''
oid = item.get('oid', '')
m = re.search(r'100808[0-9a-fA-F]+', oid)
if m:
containerid = m.group(0)
if not containerid:
scheme = item.get('scheme', '')
m = re.search(r'100808[0-9a-fA-F]+', scheme)
if m:
containerid = m.group(0)
if title and containerid:
topics.append({'title': title, 'containerid': containerid})
max_page = d.get('data', {}).get('max_page', 1)
if page >= max_page:
break
page += 1
return topics
def do_signin(sess, xsrf, containerid, topic_title):
"""
签到单个超话
完整参数来自浏览器抓包
GET /p/aj/general/button?ajwvr=6&api=http://i.huati.weibo.com/aj/super/checkin
&texta=签到&textb=已签到&status=0&id={containerid}
&location=page_100808_super_index&...
"""
r = sess.get(
'https://weibo.com/p/aj/general/button',
params={
'ajwvr': '6',
'api': 'http://i.huati.weibo.com/aj/super/checkin',
'texta': '签到',
'textb': '已签到',
'status': '0',
'id': containerid,
'location': 'page_100808_super_index',
'timezone': 'GMT+0800',
'lang': 'zh-cn',
'plat': 'Win32',
'ua': WEIBO_HEADERS['User-Agent'],
'screen': '1920*1080',
'__rnd': str(int(time.time() * 1000)),
},
headers={
'Referer': f'https://weibo.com/p/{containerid}/super_index',
'X-Requested-With': 'XMLHttpRequest',
'X-XSRF-TOKEN': xsrf,
},
timeout=10,
)
try:
d = r.json()
code = str(d.get('code', ''))
msg = d.get('msg', '')
data = d.get('data', {})
if code == '100000':
tip = ''
if isinstance(data, dict):
tip = data.get('alert_title', '') or data.get('tipMessage', '')
return {'status': 'success', 'message': tip or '签到成功', 'data': data}
elif code == '382004':
return {'status': 'already_signed', 'message': msg or '今日已签到'}
elif code == '382003':
return {'status': 'failed', 'message': msg or '非超话成员'}
else:
return {'status': 'failed', 'message': f'code={code}, msg={msg}'}
except Exception as e:
return {'status': 'failed', 'message': f'非 JSON: {r.text[:200]}'}
# ================================================================
# Main
# ================================================================
print("=" * 60)
print("微博超话自动签到 - 完整流程验证")
print("=" * 60)
# Step 1: 获取 cookie
print("\n--- Step 1: 初始化 ---")
cookies, uid, nick = load_cookies()
if not cookies:
cookies, uid, nick = qrcode_login()
# 建立 session
sess = requests.Session()
sess.headers.update(WEIBO_HEADERS)
for k, v in cookies.items():
sess.cookies.set(k, v, domain='.weibo.com')
sess.get('https://weibo.com/', timeout=10)
xsrf = sess.cookies.get('XSRF-TOKEN', '')
print(f" XSRF: {'' if xsrf else '❌ MISSING'}")
# Step 2: 获取超话列表
print(f"\n--- Step 2: 获取超话列表 ---")
topics = get_super_topics(sess, xsrf, uid)
print(f" 找到 {len(topics)} 个超话:")
for i, t in enumerate(topics):
print(f" [{i+1}] {t['title']} ({t['containerid'][:20]}...)")
if not topics:
print(" ❌ 没有找到超话,退出")
sys.exit(1)
# Step 3: 逐个签到
print(f"\n--- Step 3: 签到 ({len(topics)} 个超话) ---")
signed = already = failed = 0
results = []
for i, t in enumerate(topics):
print(f"\n [{i+1}/{len(topics)}] {t['title']}", end=' ... ')
r = do_signin(sess, xsrf, t['containerid'], t['title'])
results.append({**r, 'topic': t['title']})
if r['status'] == 'success':
signed += 1
print(f"{r['message']}")
elif r['status'] == 'already_signed':
already += 1
print(f" {r['message']}")
else:
failed += 1
print(f"{r['message']}")
if i < len(topics) - 1:
time.sleep(1.5) # 防封间隔
# Step 4: 汇总
print(f"\n{'=' * 60}")
print(f"签到完成!")
print(f" ✅ 成功: {signed}")
print(f" 已签: {already}")
print(f" ❌ 失败: {failed}")
print(f" 📊 总计: {len(topics)} 个超话")
print(f"{'=' * 60}")