Files
weibo_signin/debug_full_signin.py

277 lines
9.6 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
完整签到流程验证脚本
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}")