snscrape按日爬取Twitter主题推文仅获当日末段数据问题求解
问题根源
你拿到的推文全部集中在每日23:57左右,是两个问题导致的:
- snscrape的Twitter搜索默认按发布时间倒序返回结果,直接截取前100条,拿到的必然是距离
until参数指定时间最近的内容,也就是当天最晚发布的一批推文 - 原代码存在缩进错误,爬取逻辑的for循环没有写在日期遍历的循环内部,实际执行逻辑和按天爬取的预期不符
方案1:按小时均匀采样(时段分布最均匀)
这个方案将单日拆分为24个独立的1小时时间窗口,每个窗口单独爬取固定数量的推文,彻底避免时段聚集。如果要实现你提到的每小时10条的采样粒度,只需要把daily_target参数改成240即可,示例默认按你原本单日100条的需求配置,每小时分配4-5条爬取配额,保证全天均匀分布。
import pandas as pd import snscrape.modules.twitter as sntwitter from datetime import datetime, timedelta # 爬取参数配置 start_date = datetime(2022, 5, 1) # 爬取起始日期 total_days = 31 # 总爬取天数 daily_target = 100 # 单日目标爬取量,要实现每小时10条就把这个值改成240 hourly_target = daily_target // 24 tweets_list = [] for day_offset in range(total_days): current_date = start_date + timedelta(days=day_offset) print(f"正在爬取日期:{current_date.date()}") collected_today = 0 # 遍历当天24个小时窗口 for hour in range(24): window_start = current_date + timedelta(hours=hour) window_end = window_start + timedelta(hours=1) # 构造带时分秒的精确检索条件 query = f'bitcoin since:{window_start.strftime("%Y-%m-%dT%H:%M:%S")} until:{window_end.strftime("%Y-%m-%dT%H:%M:%S")}' hour_collected = 0 for tweet in sntwitter.TwitterSearchScraper(query).get_items(): if hour_collected >= hourly_target: break tweets_list.append([tweet.date, tweet.content]) hour_collected += 1 collected_today +=1 # 最后一个窗口补爬,凑够当日目标数量 if hour == 23 and collected_today < daily_target: for tweet in sntwitter.TwitterSearchScraper(query).get_items(): if collected_today >= daily_target: break tweets_list.append([tweet.date, tweet.content]) collected_today +=1 tweets_df = pd.DataFrame(tweets_list, columns=['Datetime', 'Text'])
方案2:全时段随机抽样
如果不需要严格按小时均匀分布,想要实现全天随机取样,可以把单日拆成更细的时间窗口,随机抽取窗口爬取,样本会随机覆盖全天各个时段,效率也比爬取全量当日推文后抽样更高。
import pandas as pd import snscrape.modules.twitter as sntwitter from datetime import datetime, timedelta import random # 爬取参数配置 start_date = datetime(2022, 5, 1) total_days = 31 daily_target = 100 window_minutes = 10 # 按10分钟拆分时间窗口,单日共144个窗口 tweets_list = [] for day_offset in range(total_days): current_date = start_date + timedelta(days=day_offset) print(f"正在爬取日期:{current_date.date()}") # 生成当日所有时间窗口,随机选daily_target个窗口爬取 total_windows = 24 * 60 // window_minutes selected_windows = random.sample(range(total_windows), daily_target) for win_idx in selected_windows: window_start = current_date + timedelta(minutes=win_idx * window_minutes) window_end = window_start + timedelta(minutes=window_minutes) query = f'bitcoin since:{window_start.strftime("%Y-%m-%dT%H:%M:%S")} until:{window_end.strftime("%Y-%m-%dT%H:%M:%S")}' # 每个选中的窗口取1条推文 for tweet in sntwitter.TwitterSearchScraper(query).get_items(): tweets_list.append([tweet.date, tweet.content]) break tweets_df = pd.DataFrame(tweets_list, columns=['Datetime', 'Text'])
注意事项
- 代码里的时间默认用UTC时区计算,如果需要对齐国内时区,给时间对象加上8小时偏移即可
- 如果个别时间窗口内比特币相关推文数量不足,代码会自动跳过,不会卡住,最终爬取总量可能和目标值有极小幅偏差,如果偏差明显可以把时间窗口粒度调得更细
- 爬取过程中建议在每个请求间隔加1-2秒的随机延时,避免触发平台的访问频率限制
内容的提问来源于stack exchange,提问作者Jacopo Giannetti
相关产品推荐
相关产品推荐

