在 Tweepy 和 Tornado WebSocket 中的类之间传递数据

Posted

技术标签:

【中文标题】在 Tweepy 和 Tornado WebSocket 中的类之间传递数据【英文标题】:Passing data between classes in Tweepy and Tornado WebSocket 【发布时间】:2012-09-18 17:01:34 【问题描述】:

我有两个主要模块,Tornado WebSocket 和 Tweepy Streaming,我正试图让它们相互交谈。

在下面的StdOutListener Tweepy 类中的on_status 下(标有<--),我想调用更高的WSHandler.on_message Tornado 类,数据从on_status 传递。

但是,我无法这样做,因为我收到与未定义实例等相关的错误消息,代码如下。非常感谢任何帮助!

(此外,我设法同时运行两个模块的唯一非阻塞方式是使用线程,因为 IOLoop.add_callback 不会阻止 StdOutListener 阻塞。我很想知道原因或如果建议使用此实现。谢谢!)

import os.path
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import threading
import time
import datetime

# websocket
class FaviconHandler(tornado.web.RequestHandler):
    def get(self):
        self.redirect('/static/favicon.ico')

class WebHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("websockets.html")

class WSHandler(tornado.websocket.WebSocketHandler):
    def open(self): 
        cb = tornado.ioloop.PeriodicCallback(self.spew, 1000, io_loop=main_loop)
        cb.start()
        print 'new connection'
        self.write_message("Hi, client: connection is made ...")

    def on_message(self, message):
        print 'message received: \"%s\"' % message
        self.write_message("Echo: \"" + message + "\"")
        if (message == "green"):
            self.write_message("green!")

    def on_close(self):
        print 'connection closed'

    def spew(self):
        msg = 'spew!'
        print(msg)
        self.on_message(msg)

handlers = [
    (r"/favicon.ico", FaviconHandler),
    (r'/static/(.*)', tornado.web.StaticFileHandler, 'path': 'static'),
    (r'/', WebHandler),
    (r'/ws', WSHandler),
]

settings = dict(
    template_path=os.path.join(os.path.dirname(__file__), "static"),
)

application = tornado.web.Application(handlers, **settings)


# tweepy
from tweepy.streaming import StreamListener
from tweepy import OAuthHandler
from tweepy import Stream
import simplejson as json


# new stream listener 
class StdOutListener(StreamListener, WSHandler):
    """ A listener handles tweets are the received from the stream. 
    This is a basic listener that just prints received tweets to stdout.

    """

    # tweet handling
    def on_status(self, status):
        print('@%s: %s' % (status.user.screen_name, status.text))
        WSHandler.on_message(status.text) # <--- THIS is where i want to send a msg to WSHandler.on_message

    # limit handling
    def on_limit(self, track):
        return

    # error handling
    def on_error(self, status):
        print status


def OpenStream():
    consumer_key="[redacted]"
    consumer_secret="[redacted]"
    access_token="[redacted]"
    access_token_secret="[redacted]"
    keyword = 'whatever'

    l = StdOutListener()
    auth = OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_token_secret)
    stream = Stream(auth, l, gzip=True) 
    stream.filter(track=[keyword])



if __name__ == "__main__":
    threading.Thread(target=OpenStream).start()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    main_loop = tornado.ioloop.IOLoop.instance()
#   main_loop.add_callback(OpenStream)
    main_loop.start()

【问题讨论】:

【参考方案1】:

on_message 是实例方法,而不是类方法。您需要在实例上调用它,如下所示:

handler = WSHandler()
handler.on_message('hello world')

但是,您不能只这样做,因为需要通过浏览器连接创建实例才能实际发送和接收消息。

您可能想要保留一个打开的连接列表 (the Tornado websocket demo is a good example of this):

class WSHandler(tornado.websocket.WebSocketHandler):
    connections = []

    def open(self):
        self.connections.append(self)

    ....

    def on_close(self):
        self.connections.remove(self)

然后,在StdOutListener.on_status 中,您可以执行以下操作:

for connection in WSHandler.connections:
    connection.write_message(status.text)

【讨论】:

以上是关于在 Tweepy 和 Tornado WebSocket 中的类之间传递数据的主要内容,如果未能解决你的问题,请参考以下文章

twitter bot 和 python 的 Tweepy 问题

如何在 Python 上使用 Tweepy 创建 Twitter 线程

如何使用 Tweepy 获取 Twitter 生物信息

tweepy 文档 [关闭]

使用 tweepy 流式传输用户的时间线和过滤的推文

尝试使用 Tweepy/Twitters Streaming API 和 psycopg2 来填充 PostgreSQL 数据库。很近,一条线