扫码登录,获取cookies
This commit is contained in:
@@ -3,14 +3,23 @@ Weibo API Client
|
||||
Handles all interactions with Weibo.com, including login, sign-in, and data fetching
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import httpx
|
||||
import asyncio
|
||||
import logging
|
||||
import random
|
||||
from typing import Dict, Any, Optional, List
|
||||
from typing import Dict, Any, Optional, List, Tuple
|
||||
|
||||
# Add parent directory to path for imports
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../.."))
|
||||
|
||||
from shared.crypto import decrypt_cookie, derive_key
|
||||
from shared.config import shared_settings
|
||||
|
||||
from app.config import settings
|
||||
from app.models.signin_models import WeiboAccount, WeiboSuperTopic
|
||||
from app.services.antibot import antibot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,21 +27,35 @@ class WeiboClient:
|
||||
"""Client for interacting with Weibo API"""
|
||||
|
||||
def __init__(self):
|
||||
self.base_headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
|
||||
"Connection": "keep-alive",
|
||||
"Referer": "https://weibo.com/"
|
||||
}
|
||||
# Use antibot module for dynamic headers
|
||||
self.base_headers = antibot.build_headers()
|
||||
|
||||
async def verify_cookies(self, account: WeiboAccount) -> bool:
|
||||
"""Verify if Weibo cookies are still valid"""
|
||||
try:
|
||||
# Decrypt cookies
|
||||
cookies = self._decrypt_cookies(account.encrypted_cookies, account.iv)
|
||||
# Decrypt cookies using shared crypto module
|
||||
cookies_dict = self._decrypt_cookies(account.encrypted_cookies, account.iv)
|
||||
|
||||
async with httpx.AsyncClient(cookies=cookies, headers=self.base_headers) as client:
|
||||
if not cookies_dict:
|
||||
logger.error(f"Failed to decrypt cookies for account {account.weibo_user_id}")
|
||||
return False
|
||||
|
||||
# Get proxy (with fallback to direct connection)
|
||||
proxy = await antibot.get_proxy()
|
||||
|
||||
# Use dynamic headers with random User-Agent
|
||||
headers = antibot.build_headers()
|
||||
|
||||
# Add random delay before request
|
||||
delay = antibot.get_random_delay()
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
cookies=cookies_dict,
|
||||
headers=headers,
|
||||
proxies=proxy,
|
||||
timeout=10.0
|
||||
) as client:
|
||||
response = await client.get("https://weibo.com/mygroups", follow_redirects=True)
|
||||
|
||||
if response.status_code == 200 and "我的首页" in response.text:
|
||||
@@ -62,13 +85,34 @@ class WeiboClient:
|
||||
logger.error(f"Error fetching super topics: {e}")
|
||||
return []
|
||||
|
||||
async def sign_super_topic(self, account: WeiboAccount, topic: WeiboSuperTopic, task_id: str) -> bool:
|
||||
async def sign_super_topic(
|
||||
self,
|
||||
account: WeiboAccount,
|
||||
topic: WeiboSuperTopic,
|
||||
task_id: str
|
||||
) -> Tuple[bool, Optional[Dict[str, Any]], Optional[str]]:
|
||||
"""
|
||||
Execute sign-in for a single super topic
|
||||
Returns: (success, reward_info, error_message)
|
||||
"""
|
||||
try:
|
||||
# Decrypt cookies
|
||||
cookies = self._decrypt_cookies(account.encrypted_cookies, account.iv)
|
||||
# Decrypt cookies using shared crypto module
|
||||
cookies_dict = self._decrypt_cookies(account.encrypted_cookies, account.iv)
|
||||
|
||||
if not cookies_dict:
|
||||
error_msg = "Failed to decrypt cookies"
|
||||
logger.error(error_msg)
|
||||
return False, None, error_msg
|
||||
|
||||
# Get proxy (with fallback to direct connection)
|
||||
proxy = await antibot.get_proxy()
|
||||
|
||||
# Use dynamic headers with random User-Agent
|
||||
headers = antibot.build_headers()
|
||||
|
||||
# Add random delay before request (anti-bot protection)
|
||||
delay = antibot.get_random_delay()
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
# Prepare request payload
|
||||
payload = {
|
||||
@@ -78,7 +122,7 @@ class WeiboClient:
|
||||
"location": "page_100808_super_index",
|
||||
"refer_flag": "100808_-_1",
|
||||
"refer_lflag": "100808_-_1",
|
||||
"ua": self.base_headers["User-Agent"],
|
||||
"ua": headers["User-Agent"],
|
||||
"is_new": "1",
|
||||
"is_from_ad": "0",
|
||||
"ext": "mi_898_1_0_0"
|
||||
@@ -104,33 +148,44 @@ class WeiboClient:
|
||||
|
||||
if response_data.get("code") == "100000":
|
||||
logger.info(f"Successfully signed topic: {topic.title}")
|
||||
return True
|
||||
reward_info = response_data.get("data", {}).get("reward", {})
|
||||
return True, reward_info, None
|
||||
elif response_data.get("code") == "382004":
|
||||
logger.info(f"Topic {topic.title} already signed today")
|
||||
return True # Treat as success
|
||||
return True, None, "Already signed"
|
||||
else:
|
||||
logger.error(f"Failed to sign topic {topic.title}: {response_data.get('msg')}")
|
||||
return False
|
||||
error_msg = response_data.get("msg", "Unknown error")
|
||||
logger.error(f"Failed to sign topic {topic.title}: {error_msg}")
|
||||
return False, None, error_msg
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Exception signing topic {topic.title}: {e}")
|
||||
return False
|
||||
error_msg = f"Exception signing topic {topic.title}: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
return False, None, error_msg
|
||||
|
||||
def _decrypt_cookies(self, encrypted_cookies: str, iv: str) -> Dict[str, str]:
|
||||
"""
|
||||
Decrypt cookies using AES-256-GCM
|
||||
In a real system, this would use a proper crypto library
|
||||
Decrypt cookies using AES-256-GCM from shared crypto module.
|
||||
Returns dict of cookie key-value pairs.
|
||||
"""
|
||||
try:
|
||||
# Mock implementation - return dummy cookies
|
||||
return {
|
||||
"SUB": "_2A25z...",
|
||||
"SUBP": "0033Wr...",
|
||||
"ALF": "16...",
|
||||
"SSOLoginState": "16...",
|
||||
"SCF": "...",
|
||||
"UN": "testuser"
|
||||
}
|
||||
# Derive encryption key from shared settings
|
||||
key = derive_key(shared_settings.COOKIE_ENCRYPTION_KEY)
|
||||
|
||||
# Decrypt using shared crypto module
|
||||
plaintext = decrypt_cookie(encrypted_cookies, iv, key)
|
||||
|
||||
# Parse cookie string into dict
|
||||
# Expected format: "key1=value1; key2=value2; ..."
|
||||
cookies_dict = {}
|
||||
for cookie_pair in plaintext.split(";"):
|
||||
cookie_pair = cookie_pair.strip()
|
||||
if "=" in cookie_pair:
|
||||
key, value = cookie_pair.split("=", 1)
|
||||
cookies_dict[key.strip()] = value.strip()
|
||||
|
||||
return cookies_dict
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to decrypt cookies: {e}")
|
||||
return {}
|
||||
|
||||
Reference in New Issue
Block a user