You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Tweepy捕获Twitter流API时WantReadError无法捕获的问题

解决Tweepy流API中OpenSSL异常捕获与自动重启问题

这个问题的核心是:你遇到的OpenSSL.SSL.WantReadError是在Tweepy的后台工作线程中抛出的,而不是在创建Stream对象的主线程里,所以你之前在twitterStream = tweepy.Stream(...)外面加的try-except根本捕获不到它。下面是具体的解决方案,包含异常捕获、自动重启和递增退避逻辑:

第一步:导入必要模块

首先要引入OpenSSL模块,这样才能明确捕获那个特定异常,同时解决IDE的"undefined name"报错:

import tweepy
import OpenSSL
import time
import logging

# 配置日志,方便追踪问题
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

第二步:自定义StreamListener(保留你的业务逻辑)

先确保你的自定义监听器正常工作,比如:

class MyStreamListener(tweepy.StreamListener):
    def on_status(self, status):
        # 替换成你处理推文的逻辑
        logger.info(f"收到推文:{status.text[:50]}...")
    
    def on_error(self, status_code):
        logger.error(f"API错误,状态码:{status_code}")
        # 429是限流,返回False会断开连接,交给外层逻辑重启
        if status_code == 429:
            return False
        return True

方案一:阻塞模式下的外层循环捕获(简单直接)

如果使用is_async=False(默认就是这个值,Stream会阻塞主线程运行),你可以在外层写一个无限循环,每次尝试启动流,捕获所有异常后重启,同时实现递增退避:

def start_stream_with_backoff(auth, listener):
    backoff_time = 1  # 初始等待时间
    max_backoff = 30  # 最大等待时间,避免无限递增
    
    while True:
        try:
            logger.info("正在启动Twitter流...")
            stream = tweepy.Stream(auth=auth, listener=listener)
            # 替换成你的过滤条件,比如track、follow等
            stream.filter(track=["python"], is_async=False)
        except OpenSSL.SSL.WantReadError as e:
            logger.error(f"捕获到WantReadError:{e},即将重启流...")
        except Exception as e:
            logger.error(f"发生未预期错误:{e},即将重启流...")
        finally:
            # 递增退避:每次等待时间翻倍,不超过最大值
            logger.info(f"等待{backoff_time}秒后重启...")
            time.sleep(backoff_time)
            backoff_time = min(backoff_time * 2, max_backoff)

调用这个函数启动流:

if __name__ == "__main__":
    # 替换成你的Twitter API密钥
    auth = tweepy.OAuthHandler("你的CONSUMER_KEY", "你的CONSUMER_SECRET")
    auth.set_access_token("你的ACCESS_TOKEN", "你的ACCESS_TOKEN_SECRET")
    
    listener = MyStreamListener()
    start_stream_with_backoff(auth, listener)

方案二:异步模式下重写Stream的_run方法(更灵活)

如果需要用is_async=True让流在后台线程运行,你需要重写Tweepy的Stream类的_run方法,在子线程内部捕获异常并处理重启:

class RestartableStream(tweepy.Stream):
    def __init__(self, auth, listener, backoff_time=1, max_backoff=30):
        super().__init__(auth=auth, listener=listener)
        self.backoff_time = backoff_time
        self.max_backoff = max_backoff
        self.logger = logging.getLogger(__name__)
    
    def _run(self):
        while True:
            try:
                # 调用父类的_run方法,也就是原来的流运行逻辑
                super()._run()
            except OpenSSL.SSL.WantReadError as e:
                self.logger.error(f"线程内捕获到WantReadError:{e},即将重启流...")
            except Exception as e:
                self.logger.error(f"线程内发生未预期错误:{e},即将重启流...")
            finally:
                # 同样应用递增退避
                self.logger.info(f"等待{self.backoff_time}秒后重启...")
                time.sleep(self.backoff_time)
                self.backoff_time = min(self.backoff_time * 2, self.max_backoff)

使用这个自定义Stream类:

if __name__ == "__main__":
    auth = tweepy.OAuthHandler("你的CONSUMER_KEY", "你的CONSUMER_SECRET")
    auth.set_access_token("你的ACCESS_TOKEN", "你的ACCESS_TOKEN_SECRET")
    
    listener = MyStreamListener()
    stream = RestartableStream(auth=auth, listener=listener)
    stream.filter(track=["python"], is_async=True)
    
    # 如果需要主线程保持运行,可以加个无限循环
    while True:
        time.sleep(3600)

关键说明

  • 为什么之前的try-except没用?因为错误发生在Stream启动后的后台线程中,而不是创建Stream对象的瞬间,所以必须在异常发生的线程上下文里捕获,或者用外层循环包裹阻塞式的filter()调用。
  • 递增退避逻辑:避免在网络不稳定时频繁请求Twitter API,防止被限流或拉黑,等待时间从1秒开始翻倍,直到30秒后保持最大值。
  • 日志记录:一定要保留日志,方便你追踪每次重启的原因和时间,排查问题。

内容的提问来源于stack exchange,提问作者user1235777

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:31:34