diff --git a/docs/guide/apps/douyin/index.md b/docs/guide/apps/douyin/index.md index 7472351..c5bf92a 100644 --- a/docs/guide/apps/douyin/index.md +++ b/docs/guide/apps/douyin/index.md @@ -469,23 +469,43 @@ outline: deep | user_id| str | 用户ID | | sec_user_id| str | 用户ID | | offset| int | 页码,初始为0 | -| count| int | 页数,初始为20 | +| min_time | int | 最早关注时间戳,秒级,初始为0 | +| max_time | int | 最晚关注时间戳,秒级,初始为0 | +| count| int | 每页关注用户数,初始为20 | | source_type| int | 排序类型,初始为4 | -| min_time | int | 最早关注时间戳,初始为0 | -| max_time | int | 最晚关注时间戳,初始为0 | | max_counts| float | 最大列表数,初始为None | | 返回 | 类型 | 说明 | | :--- | :--- | :--- | | UserFollowingFilter | AsyncGenerator | 关注用户数据过滤器,包含关注用户数据的_to_raw、_to_dict、_to_list方法 | -<<< @/snippets/douyin/user-following.py{18-20,22-29} +#### 偏移量 (**offset**): -::: tip 提示 -- `source_type` 的参数控制排序类型,`4` 为综合排序,`1` 为最近关注 `3` 为最早关注。 -- 当选择 `source_type` 不为 `4` 时,需要`min_time` 和 `max_time` 参数选择时间范围。 +- 当 `source_type` 为 `1` 和 `3` 时,`offset` 参数无效。 +- 当 `source_type` 为 `4` 时,`offset` 参数有效。 + +#### 时间范围 (**min_time**/**max_time**): + +- 如果未传递 `max_time` 和 `min_time` 参数,`F2` 将自动处理时间范围,确保数据完整性。 +- 若需要自定义时间范围,可通过手动设置 `max_time` 和 `min_time` 参数实现。 + +#### 关注用户数 (**count**): + +- `count` 参数控制每页关注用户数,不建议设置过大,建议使用默认值。 + +#### 排序类型 (**source_type**): + +- `1` 表示按最近关注排序。 +- `3` 表示按最早关注排序。 +- `4` 表示按综合排序。 + +::: tip :bulb: 但需注意 +- 只能获取到用户**公开状态**的关注用户数据。 +- 时间间隔过长可能导致数据不完整,不建议采用自定义时间范围,仅适用于获取特定时间段前或后的数据场景。 ::: +<<< @/snippets/douyin/user-following.py{18-20,22-31} + ### 粉丝用户数据 🟢 异步方法,用于获取指定用户的粉丝列表。 diff --git a/docs/snippets/douyin/user-following.py b/docs/snippets/douyin/user-following.py index 5bd723a..25893a7 100644 --- a/docs/snippets/douyin/user-following.py +++ b/docs/snippets/douyin/user-following.py @@ -20,12 +20,14 @@ async def main(): # sec_user_id = "MS4wLjABAAAAGPm-wPeGQuziCu5z6KerQA7WmSTnS99c8lU8WLToB0BsN02mqbPxPuxwDjKf7udZ" # 隐私设置的账号 # 至少提供 user_id 或 sec_user_id 中的一个参数 + # source_type 选择排序方式,1:按照最近关注排序,3:按照最早关注排序,4:按照综合排序 # 根据 max_time 和 min_time 区间获取关注用户列表 async for following in DouyinHandler(kwargs).fetch_user_following( user_id=user_id, sec_user_id=sec_user_id, # max_time=1668606509, # min_time=0, + source_type=4, ): if following.status_code != 0: logger.error( diff --git a/f2/apps/douyin/handler.py b/f2/apps/douyin/handler.py index a9e0032..6bb77c7 100644 --- a/f2/apps/douyin/handler.py +++ b/f2/apps/douyin/handler.py @@ -1498,10 +1498,10 @@ async def fetch_user_following( user_id: str = "", sec_user_id: str = "", offset: int = 0, - count: int = 20, - source_type: int = 4, min_time: int = 0, max_time: int = 0, + count: int = 20, + source_type: int = 4, max_counts: float = float("inf"), ) -> AsyncGenerator[UserFollowingFilter, Any]: """ @@ -1509,12 +1509,12 @@ async def fetch_user_following( Args: user_id: str: 用户ID - sec_user_id: str: 用户ID + sec_user_id: str: 用户sec_user_id offset: int: 起始页 + min_time: int: 最小时间戳,秒级,初始为0 + max_time: int: 最大时间戳,秒级,初始为0 count: int: 每页关注用户数 - source_type: int: 排序类型 - min_time: int: 最小时间戳 - max_time: int: 最大时间戳 + source_type: int: 排序类型,1: 按最近关注排序,3: 按最早关注排序,4: 按综合排序 Return: following: AsyncGenerator[UserFollowingFilter, Any]: 关注用户数据过滤器,包含关注用户数据的_to_raw、_to_dict、_to_list方法 """ @@ -1522,10 +1522,16 @@ async def fetch_user_following( if not user_id and not sec_user_id: raise ValueError(_("至少提供 user_id 或 sec_user_id 中的一个参数")) + source_type_map = { + 1: _("按最近关注排序"), + 3: _("按最早关注排序"), + 4: _("按综合排序"), + } max_counts = max_counts or float("inf") users_collected = 0 logger.info(_("处理用户:{0} 的关注用户").format(sec_user_id)) + logger.info(_("当前排序类型:{0}").format(source_type_map.get(source_type))) while users_collected < max_counts: current_request_size = min(count, max_counts - users_collected) @@ -1533,16 +1539,18 @@ async def fetch_user_following( logger.debug( _("最大数量:{0} 每次请求数量:{1}").format(count, current_request_size) ) + logger.debug(_("当前请求的 max_time:{0}".format(max_time))) + logger.debug(_("当前请求的 min_time:{0}".format(min_time))) async with DouyinCrawler(self.kwargs) as crawler: params = UserFollowing( - offset=offset, - count=current_request_size, user_id=user_id, sec_user_id=sec_user_id, - source_type=source_type, + offset=offset, min_time=min_time, max_time=max_time, + count=current_request_size, + source_type=source_type, ) response = await crawler.fetch_user_following(params) following = UserFollowingFilter(response) @@ -1552,8 +1560,8 @@ async def fetch_user_following( logger.info(_("用户:{0} 所有关注用户采集完毕").format(sec_user_id)) break - logger.info(_("当前请求的offset:{0}").format(offset)) - logger.info(_("处理了 {0} 个关注用户").format(offset + 1)) + logger.info(_("当前请求的 offset:{0}").format(offset)) + logger.info(_("处理了 {0} 个关注用户").format(len(following.sec_uid))) logger.debug( _("用户ID:{0} 用户昵称:{1} 用户作品数:{2} 额外内容:{3}").format( following.sec_uid, @@ -1565,7 +1573,14 @@ async def fetch_user_following( # 更新已经处理的用户数量 (Update the number of users processed) users_collected += len(following.sec_uid) - offset = following.offset + + # 使用逻辑映射表更新offset、max_time、min_time + logicmap = { + 1: (0, following.min_time, 0), # 按最近关注排序 + 3: (0, 0, following.max_time), # 按最早关注排序 + 4: (following.offset, 0, 0), # 按综合排序 + } + offset, max_time, min_time = logicmap.get(source_type) # 避免请求过于频繁 logger.info(_("等待 {0} 秒后继续").format(self.kwargs.get("timeout", 5)))