Phase1: 效果数据真实化
- 替换scheduler.py中假随机数metrics_sync为知乎API自动获取 - 新增 POST /api/metrics/zhihu-fetch 知乎公开数据API端点 - metrics.html新增「数据录入」tab:手动录入表单+已有数据列表+知乎自动获取 - gitignore清理已跟踪的生成文件(outlines/research/images/cache)
This commit is contained in:
@@ -4,6 +4,9 @@ from sqlalchemy import func, desc
|
||||
from typing import List, Optional
|
||||
from datetime import datetime, timedelta, date
|
||||
import logging
|
||||
import re
|
||||
import requests as http_requests
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..database import get_db
|
||||
from ..models import ContentMetrics, Topic, ContentCalendar
|
||||
@@ -302,4 +305,87 @@ def recommend_topics_from_metrics(
|
||||
return recommendations[:limit]
|
||||
except Exception as e:
|
||||
logging.getLogger(__name__).exception(f"推荐选题失败: {e}")
|
||||
return []
|
||||
return []
|
||||
|
||||
|
||||
_ZHIHU_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
|
||||
|
||||
def _extract_zhihu_post_id(url: str) -> str:
|
||||
m = re.search(r'zhuanlan\.zhihu\.com/p/(\d+)', url)
|
||||
if m:
|
||||
return m.group(1)
|
||||
m = re.search(r'zhihu\.com/question/\d+/answer/(\d+)', url)
|
||||
if m:
|
||||
return m.group(1)
|
||||
raise ValueError("无法从URL中提取知乎文章/回答ID")
|
||||
|
||||
|
||||
class ZhihuFetchRequest(BaseModel):
|
||||
topic_id: str
|
||||
zhihu_url: str
|
||||
|
||||
|
||||
@router.post("/zhihu-fetch")
|
||||
def fetch_zhihu_metrics(
|
||||
data: ZhihuFetchRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(get_current_user)
|
||||
):
|
||||
"""从知乎专栏/回答公开API自动获取阅读/点赞/评论数据"""
|
||||
topic = db.query(Topic).filter(Topic.id == data.topic_id).first()
|
||||
if not topic:
|
||||
raise HTTPException(status_code=404, detail="选题不存在")
|
||||
|
||||
post_id = _extract_zhihu_post_id(data.zhihu_url)
|
||||
api_url = f"https://zhuanlan.zhihu.com/api/posts/{post_id}"
|
||||
|
||||
try:
|
||||
resp = http_requests.get(api_url, headers={"User-Agent": _ZHIHU_UA}, timeout=15)
|
||||
if resp.status_code == 404:
|
||||
api_url = f"https://www.zhihu.com/api/v4/answers/{post_id}"
|
||||
resp = http_requests.get(api_url, headers={"User-Agent": _ZHIHU_UA}, timeout=15)
|
||||
if resp.status_code != 200:
|
||||
raise HTTPException(status_code=502, detail=f"知乎API返回 {resp.status_code}")
|
||||
|
||||
raw = resp.json()
|
||||
platform = "zhihu"
|
||||
|
||||
existing = db.query(ContentMetrics).filter(
|
||||
ContentMetrics.topic_id == data.topic_id,
|
||||
ContentMetrics.platform == platform
|
||||
).first()
|
||||
|
||||
metric_data = {
|
||||
"views": raw.get("voteup_count", raw.get("views_count", 0)),
|
||||
"likes": raw.get("voteup_count", 0),
|
||||
"favorites": raw.get("favorite_count", 0),
|
||||
"comments": raw.get("comment_count", raw.get("comments_count", 0)),
|
||||
"shares": raw.get("share_count", 0) or raw.get("shared_count", 0),
|
||||
"publish_url": data.zhihu_url,
|
||||
"data_snapshot": raw,
|
||||
}
|
||||
|
||||
if existing:
|
||||
for k, v in metric_data.items():
|
||||
setattr(existing, k, v)
|
||||
existing.last_fetched = datetime.now()
|
||||
db.commit()
|
||||
db.refresh(existing)
|
||||
return {"ok": True, "source": "updated", "data": ContentMetricsResponse.model_validate(existing)}
|
||||
else:
|
||||
metric = ContentMetrics(
|
||||
topic_id=data.topic_id,
|
||||
platform=platform,
|
||||
**metric_data,
|
||||
last_fetched=datetime.now()
|
||||
)
|
||||
db.add(metric)
|
||||
db.commit()
|
||||
db.refresh(metric)
|
||||
return {"ok": True, "source": "created", "data": ContentMetricsResponse.model_validate(metric)}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=502, detail=f"获取知乎数据失败: {str(e)}")
|
||||
Reference in New Issue
Block a user