tmwgsicp-wechat-download-api/routes/search.py

133 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2026 tmwgsicp
# Licensed under the GNU Affero General Public License v3.0
# See LICENSE file in the project root for full license text.
# SPDX-License-Identifier: AGPL-3.0-only
"""
搜索路由 - FastAPI版本
"""
import os
from fastapi import APIRouter, Query, Request
from pydantic import BaseModel
from typing import Optional, List
import time
import httpx
from utils.auth_manager import auth_manager
from utils.image_proxy import proxy_image_url
router = APIRouter()
def get_base_url(request: Request) -> str:
"""
获取服务的基础 URL优先使用环境变量 SITE_URL
支持反向代理(检测 X-Forwarded-Proto 和 X-Forwarded-Host
"""
site_url = os.getenv("SITE_URL", "").strip()
if site_url:
return site_url.rstrip("/")
proto = request.headers.get("X-Forwarded-Proto", "http")
host = request.headers.get("X-Forwarded-Host") or request.headers.get("Host", "localhost:5000")
return f"{proto}://{host}"
class Account(BaseModel):
"""公众号模型"""
id: str
name: str
round_head_img: str
class SearchResponse(BaseModel):
"""搜索响应模型"""
success: bool
data: Optional[dict] = None
error: Optional[str] = None
@router.get("/searchbiz", response_model=SearchResponse, summary="搜索公众号")
async def search_accounts(query: str = Query(..., description="公众号名称或关键词", alias="query"), request: Request = None):
"""
按关键词搜索微信公众号,获取 FakeID。
**查询参数:**
- **query** (必填): 搜索关键词(公众号名称)
**返回字段:**
- `list[]`: 匹配的公众号列表,每项包含 `fakeid`、`nickname`、`alias`、`round_head_img`
- `total`: 匹配数量
"""
credentials = auth_manager.get_credentials()
if not credentials:
return SearchResponse(
success=False,
error="服务器未登录,请先访问管理页面扫码登录"
)
token = credentials.get("token")
cookie = credentials.get("cookie")
try:
# 调用微信搜索公众号API
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.get(
"https://mp.weixin.qq.com/cgi-bin/searchbiz",
params={
"action": "search_biz",
"token": token,
"lang": "zh_CN",
"f": "json",
"ajax": 1,
"random": time.time(),
"query": query,
"begin": 0,
"count": 5
},
headers={
"Cookie": cookie,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
)
result = response.json()
if result.get("base_resp", {}).get("ret") == 0:
accounts = result.get("list", [])
# 获取 base_url 用于图片代理
base_url = get_base_url(request) if request else ""
# 格式化返回数据
formatted_accounts = []
for acc in accounts:
# 将头像 URL 转换为代理链接
round_head_img = proxy_image_url(acc.get("round_head_img", ""), base_url)
formatted_accounts.append({
"fakeid": acc.get("fakeid", ""),
"nickname": acc.get("nickname", ""),
"alias": acc.get("alias", ""),
"round_head_img": round_head_img,
"service_type": acc.get("service_type", 0)
})
return SearchResponse(
success=True,
data={
"list": formatted_accounts,
"total": len(formatted_accounts)
}
)
else:
return SearchResponse(
success=False,
error=f"搜索失败: {result.get('base_resp', {}).get('err_msg', '未知错误')}"
)
except Exception as e:
print(f"❌ 搜索公众号失败: {str(e)}")
return SearchResponse(
success=False,
error=f"搜索请求失败: {str(e)}"
)