Skip to content

Commit d1e7988

Browse files
committed
fix: add get_comments and get_post_by_id to FetchLayerClient
1 parent 618360d commit d1e7988

1 file changed

Lines changed: 70 additions & 4 deletions

File tree

utils/reddit_json_client.py

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ async def _make_request(self, url: str, retry_on_403: bool = True) -> Dict[str,
244244
response = await session.get(url, headers=headers, timeout=15, http_version=http_version)
245245
# HTTP/3 成功,重置失败计数
246246
if self.http3_failed_count > 0:
247-
logger.info(f"✅ HTTP/3 恢复正常,重置失败计数")
247+
logger.info("✅ HTTP/3 恢复正常,重置失败计数")
248248
self.http3_failed_count = 0
249249
except Exception as e:
250250
# HTTP/3 失败,尝试降级到 HTTP/2
@@ -256,7 +256,7 @@ async def _make_request(self, url: str, retry_on_403: bool = True) -> Dict[str,
256256
logger.warning(f"🚫 HTTP/3 连续失败 {self.http3_disable_threshold} 次,切换到 HTTP/2")
257257

258258
# 降级到 HTTP/2 重试
259-
logger.info(f"🔄 降级到 HTTP/2 重试...")
259+
logger.info("🔄 降级到 HTTP/2 重试...")
260260
response = await session.get(url, headers=headers, timeout=15)
261261
else:
262262
# 当前浏览器不支持 HTTP/3,直接使用 HTTP/2
@@ -269,7 +269,7 @@ async def _make_request(self, url: str, retry_on_403: bool = True) -> Dict[str,
269269
if response.status_code in (429, 403):
270270
# 403 先尝试轮换浏览器重试,重试失败再设冷却期
271271
if response.status_code == 403 and retry_on_403 and self.rotate_browser:
272-
logger.warning(f"⚠️ 收到 403 响应,尝试轮换浏览器重试...")
272+
logger.warning("⚠️ 收到 403 响应,尝试轮换浏览器重试...")
273273
await self._rotate_browser()
274274
return await self._make_request(url, retry_on_403=False)
275275

@@ -504,7 +504,7 @@ def __init__(self, api_key: str):
504504
async def get_post_by_url(self, url: str) -> Optional[RedditPost]:
505505
"""通过 URL 获取帖子"""
506506
import httpx
507-
from datetime import datetime, timezone
507+
from datetime import datetime
508508

509509
try:
510510
async with httpx.AsyncClient(timeout=15) as client:
@@ -641,6 +641,72 @@ async def get_top_posts(self, subreddit: Optional[str] = None, time_filter: str
641641
async def get_new_posts(self, subreddit: Optional[str] = None, limit: int = 10) -> List[RedditPost]:
642642
return await self._get_community_posts(subreddit, "new", None, limit)
643643

644+
async def get_post_by_id(self, post_id: str) -> Optional[RedditPost]:
645+
"""通过 ID 获取帖子(构建 permalink 后调用 get_post_by_url)"""
646+
clean_id = post_id.replace('t3_', '')
647+
url = f"https://www.reddit.com/comments/{clean_id}/"
648+
return await self.get_post_by_url(url)
649+
650+
async def get_comments(self, post_id: str, limit: int = 10, sort: str = 'top') -> List[RedditComment]:
651+
"""通过 post endpoint 获取评论(FetchLayer 返回完整评论树)"""
652+
import httpx
653+
from datetime import datetime
654+
655+
clean_id = post_id.replace('t3_', '')
656+
url = f"https://www.reddit.com/comments/{clean_id}/"
657+
658+
try:
659+
async with httpx.AsyncClient(timeout=15) as client:
660+
response = await client.post(
661+
f"{self.BASE_URL}/post",
662+
headers=self._headers,
663+
json={"url": url}
664+
)
665+
response.raise_for_status()
666+
data = response.json()
667+
668+
if data.get("error") or data.get("blocked"):
669+
logger.error(f"FetchLayer 获取评论失败: {data.get('error') or data.get('blockReason')}")
670+
return []
671+
672+
raw_comments = data.get("comments", [])
673+
674+
# 只取顶层评论(depth=0 或 parentFullname 为 None)
675+
top_level = [c for c in raw_comments if c.get("depth", 0) == 0 or c.get("parentFullname") is None]
676+
677+
if sort == 'top':
678+
top_level.sort(key=lambda c: c.get("score") or 0, reverse=True)
679+
680+
comments = []
681+
for c in top_level[:limit]:
682+
created_utc = 0.0
683+
created_at = c.get("createdAt")
684+
if created_at:
685+
try:
686+
dt = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
687+
created_utc = dt.timestamp()
688+
except Exception:
689+
pass
690+
691+
body = c.get("bodyText", "")
692+
if not body:
693+
continue
694+
695+
comments.append(RedditComment(
696+
id=c.get("id", ""),
697+
author=c.get("author", "[deleted]"),
698+
body=body,
699+
score=c.get("score") or 0,
700+
created_utc=created_utc,
701+
))
702+
703+
logger.info(f"✅ FetchLayer 获取到 {len(comments)} 条评论")
704+
return comments
705+
706+
except Exception as e:
707+
logger.error(f"FetchLayer 获取评论失败 (post_id={post_id}): {e}")
708+
return []
709+
644710
async def close(self):
645711
pass
646712

0 commit comments

Comments
 (0)