Tweepy Connection broken:IncompleteRead - 处理异常的最佳方法?或者,线程可以帮助避免吗?

时间:2017-12-30 14:13:17

标签: python multithreading exception-handling tweepy

我使用tweepy来处理大型Twitter流(跟随4,000多个帐户)。我添加到流中的帐户越多,我就越有可能收到此错误:

Traceback (most recent call last):
  File "myscript.py", line 2103, in <module>
main()
  File "myscript.py", line 2091, in main
    twitter_stream.filter(follow=USERS_TO_FOLLOW_STRING_LIST,     stall_warnings=True)
  File "C:\Python27\lib\site-packages\tweepy\streaming.py", line 445, in filter
self._start(async)
  File "C:\Python27\lib\site-packages\tweepy\streaming.py", line 361, in _start
self._run()
  File "C:\Python27\lib\site-packages\tweepy\streaming.py", line 294, in _run
raise exception
requests.packages.urllib3.exceptions.ProtocolError: ('Connection broken:     IncompleteRead(0 bytes read, 2000 more expected)', IncompleteRead(0 bytes read, 2000 more expected))

显然,这是一个厚厚的火焰 - 从经验来看,它的厚,无法处理。基于研究stackoverflow上的这个错误以及经验趋势,我添加的帐户越多,这个异常发生得越快,我的假设是这是我的错误&#39; 。我对每条推文的处理时间过长和/或我的firehose太厚了。我知道了。

但是尽管有这样的设置,我仍然有两个问题,我似乎无法找到可靠的答案。
1.有没有办法简单地处理&#39;这个例外,接受我会遗漏一些推文,但保持脚本运行?我想也许它错过了一条推文(或许多推文&#39;,但如果我可以在没有100%我想要的推文的情况下生活,那么脚本/流仍然可以继续,准备随时抓住下一条推文。< / p>

我已尝试过此异常处理,建议在stackoverflow上的类似问题中使用此异常处理:         来自urllib3.exceptions导入ProtocolError

    while True:
        try:
            twitter_stream.filter(follow=USERS_TO_FOLLOW_STRING_LIST, stall_warnings=True)

        except ProtocolError:
            continue

但不幸的是,对我来说(也许我错误地实施了它,但我认为我没有这样做),但是没有用。我得到了与之前有或没有建议的异常处理代码相同的错误。

  1. 我从来没有在我的python代码中实现队列和/或线程。这是我尝试实施的好时机吗?我不了解队列/线程的一切,但我想象......
  2. 我是否可以在一个线程上将推文写入 - 原始 - 预处理 - 内存,数据库或其他内容?然后,有一个第二个线程准备好处理这些推文,一旦它准备好了吗?我想是这样的,至少,我将推文的后期处理作为我正在阅读的firehose带宽的限制因素。然后,如果我仍然得到错误,我可以减少我关注的人等等。

    我已经看过一些线程教程,但可能值得一提的是,这是否有效?&#39;用...这个tweepy / twitter / etc / complex。我对我所遇到的问题或线程可能有什么帮助的理解并不自信,所以我想可以就是否确实能帮到我这里提出建议。

    如果这个想法有效,是否有一些简单的示例代码可以帮助我指出正确的方向?

3 个答案:

答案 0 :(得分:0)

我想通过最终完成我的第一个队列/线程实现来解决这个问题。我没有足够的知识来了解最好的方法,但我认为这种方式确实有效。使用下面的代码,我现在建立了一个新推文队列,可以按照我的意愿处理它们,而不是落后并丢失与tweepy的连接。

ngFor

我确实继续挖掘一下IncompleteRead错误,我尝试使用url libs和http libs进行了更多的Exception处理解决方案,但我一直在努力。我认为除了保持连接之外,排队的东西可能会有一些好处(对于一个,不会丢失数据)。

希望这对某人有帮助。哈哈。

答案 1 :(得分:0)

非常感谢您,我正面临这样的问题,并尝试了各种解决方案。之所以发生这种情况,是因为除了通过API进行流式传输外,我还对数据进行了大量处理,这使我失去了连接。我只是做了一些调整,我不得不在 init 方法中添加super()。 init (),因为我正在使用on_status并且导入队列必须为小写。 另一件事,我没有制作do_whatever,而是将self.q.get()放入了一段时间。 无论如何,效果很好,再次感谢。

最终代码:

from queue import Queue
from threading import Thread

class Listener(tweepy.StreamListener):

    def __init__(self, q = Queue()):
        super().__init__()
        self.q = q
        for i in range(4):
            t = Thread(target=self.do_stuff)
            t.daemon = True
            t.start()

    def on_status(self, status):
        <my code here>

    def do_stuff(self):
        while True:
            self.q.get()
            self.q.task_done()

答案 2 :(得分:0)

对我来说,这样的事情有效: 使用调度程序,您可以间隔运行尝试重新连接的方法。请注意,使用参数stall_warnings=True 可以减少很多错误。 Twitter API 检测到多次重新连接尝试并对您进行速率限制,因此重新连接的最佳机会是实施退避策略。使用下面的方法,所有类型的断开连接都被处理,所以如果只需要检测特定的错误,则需要修改。如果在同一个客户端类中使用了多个流,则必须相应地调整调度程序和 ID。此外,您必须在解决方案中包含您自己的 MyStreamListener(tweepy.StreamListener) 类实现。

from apscheduler.schedulers.asyncio import AsyncIOScheduler
import logging
import asyncio

class MyClient():
    def __init__():
        self.scheduler = AsyncIOScheduler(event_loop=asyncio.get_event_loop())
        self.stream = None
        self.stream_listener = None
        self.userIDToFollow = 123456789 # insert here twitter id of the user
        logging.basicConfig(level=logging.INFO)

    def start_stream(self):
        try:
            self.stream_listener = MyStreamListener()
            self.stream = tweepy.Stream(auth=self.api.auth, listener=self.stream_listener)
            self.stream.filter(follow=[str(self.userIDToFollow)], is_async=True, stall_warnings=True)
            self.scheduler.add_job(self.keep_stream_alive, 'interval', minutes=5, max_instances=1, replace_existing=True, id='keep_stream_alive')
            logging.info("Stream started successfully!")
        except Exception as e:
            self.stop_stream() # for cleanup purposes
            logging.error(e) # feel free to log more

    def stop_stream(self):
        try:
            self.stream.disconnect()
            self.stream_listener = None
            self.scheduler.remove_job('keep_stream_alive')
            logging.info("Stream stopped successfully!")
        except Exception as e:
            logging.error(e)

    async def keep_stream_alive(self):
        try:
            if not self.stream.running:
                for i in range(5, 100, 5): # basic backoff strategy, feel free to implement yours
                    logging.error("Stream disconnected!")
                    logging.info("Sleeping for " + str(i) + " seconds...")
                    time.sleep(i)
                    logging.info("Attempting to reconnect...")
                    self.start_stream()
                    if self.stream.running:
                        break
                if self.stream.running is False:
                    # Reconnection not possible - Stopped trying
                    logging.error("Reconnection not possible - Stopped trying")
            else:
                logging.info("Stream is still running.")
        except Exception as e:
            logging.error(e)