返回 douyin-downloader
post_strategy.py
根目录 / core / user_modes / post_strategy.py
1 from __future__ import annotations
2
3 from typing import Any, Dict, List
4
5 from core.user_modes.base_strategy import BaseUserModeStrategy
6 from utils.logger import setup_logger
7
8 logger = setup_logger("PostUserModeStrategy")
9
10
11 class PostUserModeStrategy(BaseUserModeStrategy):
12 mode_name = "post"
13 api_method_name = "get_user_post"
14
15 async def collect_items(self, sec_uid: str, user_info: Dict[str, Any]) -> List[Dict[str, Any]]:
16 fetcher = getattr(self.downloader.api_client, self.api_method_name, None)
17 if not callable(fetcher):
18 logger.error("API client missing get_user_post")
19 return []
20
21 aweme_list: List[Dict[str, Any]] = []
22 max_cursor = 0
23 has_more = True
24 pagination_restricted = False
25
26 number_limit = int(self.downloader.config.get("number", {}).get(self.mode_name, 0) or 0)
27 media_filter_enabled = self._media_type_filter_enabled()
28
29 self.downloader._progress_update_step("拉取作品列表", "分页抓取中")
30
31 while has_more:
32 await self.downloader.rate_limiter.acquire()
33 request_cursor = max_cursor
34 page_data = await fetcher(sec_uid, request_cursor, 20)
35 page = self._normalize_page_data(page_data)
36 page_items = self.select_items(page)
37
38 if not page_items:
39 if page.get("status_code") == 0:
40 pagination_restricted = True
41 logger.warning(
42 "User post page empty at cursor=%s (status_code=0); "
43 "will attempt browser fallback",
44 request_cursor,
45 )
46 break
47
48 page_items = self._filter_pinned_items(page_items)
49 aweme_list.extend(page_items)
50
51 self.downloader._progress_update_step("拉取作品列表", f"已抓取 {len(aweme_list)} 条")
52
53 has_more = bool(page.get("has_more", False))
54 max_cursor = int(page.get("max_cursor", 0) or 0)
55 if has_more and max_cursor == request_cursor:
56 logger.warning(
57 "max_cursor did not advance (%s), stop paging to avoid loop",
58 max_cursor,
59 )
60 pagination_restricted = True
61 break
62
63 if number_limit > 0:
64 if media_filter_enabled:
65 if len(self._filter_by_media_type(aweme_list)) >= number_limit:
66 break
67 elif len(aweme_list) >= number_limit:
68 aweme_list = aweme_list[:number_limit]
69 break
70
71 if pagination_restricted:
72 self.downloader._progress_update_step("拉取作品列表", "分页受限,尝试浏览器回补")
73 await self.downloader._recover_user_post_with_browser(sec_uid, user_info, aweme_list)
74 if not aweme_list:
75 raise RuntimeError(
76 "抖音接口未返回作品列表(可能触发了反爬限制),"
77 "请稍后重试或尝试重新登录抖音刷新 Cookie"
78 )
79
80 return aweme_list
81
81 lines PYTHON