16.tornado操作之聊天室和爬取图片功能整合

Posted 孤寒者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了16.tornado操作之聊天室和爬取图片功能整合相关的知识,希望对你有一定的参考价值。

本文实现一个新功能,也是在聊天室和爬取图片功能的基础上,实现:在聊天室发送图片链接实现自动下载(即之前的上传图片功能)。
聊天室和爬取图片功能都已实现,所以上述所讲新功能的实现只需要对这俩功能整合一下即可~

  • 也就是使用 AsyncHTTPClient 和 IOLoop.current().spawn_callback调用 /async接口即可。

前面实现聊天室功能时候有两个版本代码(《14.tornado操作之应用Websocket协议实现聊天室功能》,对应这个文章的第3和第4两个部分),所以本文的新功能也对应两个版本代码:

目录:

每篇前言:


1.对应聊天室第3部分代码实现

  • 其实我在聊天室那篇文章中,我使用的代码就是第4部分的,因为极简,可拓展性高,而且代码十分通俗易懂!
  • 所以后续(包括本文新增的这个功能)我重点对我所用的代码版本进行适当的更新迭代~

(1)修改chat.py文件:

from pycket.session import SessionMixin
import tornado.web
from tornado.ioloop import IOLoop

from tornado.httpclient import AsyncHTTPClient


class RoomHandler(AuthBaseHandler):
    """
    聊天室的页面
    """
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        self.render('room.html',messages=ChatWsHandler.history[:10:])


class ChatWsHandler(tornado.websocket.WebSocketHandler, SessionMixin):
    """
    处理和响应 websocket 连接
    """
    waiters = set()  # 等待接收信息的用户
    history = []   # 存放历史信息

    def get_current_user(self):
        return self.session.get('tudo_user',None)

    def open(self,*args,**kwargs):
        # 新的websocket 连接自动调用的操作
        print('new connection:'.format(self))
        ChatWsHandler.waiters.add(self)

    def on_close(self):
        # 关闭一个新的连接
        print('close ws connection:'.format(self))
        ChatWsHandler.waiters.remove(self)

    def on_message(self,message):
        # 将接收的数据转换一下
        print('got message:'.format(message))
        parsed = tornado.escape.json_decode(message)
        # 接收数据
        chat = 
            'id': str(uuid.uuid4()),
            'body': parsed['body']
        
        # 判断用户是否有输入内容和用户是否输入网址以http开头
        if chat['body'] and chat['body'].startswith('http://'):
            # 模拟浏览器发送请求获取数据
            client = AsyncHTTPClient()
            # 获取数据
            save_api_url = 'http://192.168.182.141:8002/s?save_url=&user=&from=room'.format(
                chat['body'],
                self.current_user
            )
            print(save_api_url)
            IOLoop.current().spawn_callback(client.fetch,save_api_url)
            # client.fetch(save_api_url)
            # 告诉用户你发送的url正在处理
            msg = 'user , url  is processing.'.format(self.current_user,chat['body'])
            # 将信息告诉用户,不做全部显示
            chat['body'] = msg
            # 显示内容到页面
            message_html = 
                'html': tornado.escape.to_basestring(
                    self.render_string('message.html', chat=chat)
                ),
                'id': chat['id']
            
            self.write_message(message_html)
        else:
            # 显示聊天内容的页面和连接
            message_html = 
                'html': tornado.escape.to_basestring(
                    self.render_string('message.html',chat=chat)
                ),
                'id': chat['id']
            
            ChatWsHandler.history.append(message_html)
            ChatWsHandler.send_updates(message_html)
            print('got message:'.format(message))

    # 给每个等待的用户发送新的信息
    @classmethod
    def send_updates(cls, message_html):
        for w in ChatWsHandler.waiters:
            w.write_message(message_html)

(2)修改service.py文件:

from .chat import ChatWsHandler
import uuid

class AsyncSaveHandler(AuthBaseHandler):
    """
    使用异步
    """
    def prepare(self):
        print(self.get_argument('save_url','empty'))

    @tornado.gen.coroutine
    def get(self,*args,**kwargs):
        save_url = self.get_argument('save_url',None)
        print(save_url)
        # 获取用户名和接口
        username = self.get_argument('user',None)
        is_from_room = self.get_argument('from',None) =='room'
        print(username)
        print(is_from_room)
        if username and is_from_room:
            resp = yield self.get_rep(save_url)
            ims = UploadImage(self.settings['static_path'],'x.jpg')
            ims.save_upload(resp.body)
            ims.make_thumb()
            # post = add_post(self.current_user,ims.image_url,ims.thumb_url)
            post = add_post(username,ims.image_url,ims.thumb_url)
            # self.redirect('/post/'.format(post.id))
            # 告诉用户你的图片保存完成
            import uuid
            chat = 
                'id': str(uuid.uuid4()),
                'body': 'new picture from : http://192.168.182.141:8002/post/'.format(username,post.id),
            
            message_html = 
                'html': tornado.escape.to_basestring(
                    self.render_string('message.html', chat=chat)
                ),
                'id': chat['id']
            
            #
            ChatWsHandler.send_updates(message_html)
            # self.write(post.id)
        else:
            # 如果不符合
            print('wrong call')
            self.write('wrong call')
    #使用延迟的方式
    @tornado.gen .coroutine
    def get_rep(self,url):
        yield tornado.gen.sleep(5)
        client = AsyncHTTPClient()
        resp = yield client.fetch(url)
        return resp

2. 对应聊天室第4部分代码实现

(1)修改chat.py文件:

import datetime

import tornado.websocket
from tornado.httpclient import AsyncHTTPClient
from tornado.ioloop import IOLoop

from .main import AuthBaseHandler

# 聊天室页面
class RoomHandler(AuthBaseHandler):
    def get(self):
        uname = self.current_user
        self.render('room.html', uname=uname)


# 聊天中转站:websocket
class ChatWsHandler(tornado.websocket.WebSocketHandler, AuthBaseHandler):
    # 在线用户
    online_users = []
    # 存放历史聊天信息
    history = []

    # 连接:当有新用户连接我时,会自动调用
    def open(self, *args, **kwargs):
        # print('有新用户加入聊天室...')
        self.online_users.append(self)
        # 给新用户展示所有历史记录信息
        for i in ChatWsHandler.history:
            self.write_message(i)
        # 添加历史聊天信息之用户登录信息
        message = u"[%s]-[%s]-进入聊天室" % (self.current_user, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        ChatWsHandler.history.append(message)
        # 向所有在线用户发送消息——告诉有新人登录
        for u in self.online_users:
            u.write_message(message)


    # 接收信息:接收前端浏览器发过来的信息
    def on_message(self, message):
        # print("接收到前端用户发过来的信息:", message)
        # 不能发送空信息
        if message:
            # 判断用户是否输入网址以http或https开头
            if message.startswith('https://') or message.startswith('http://'):
                # 模拟浏览器发送请求获取数据
                client = AsyncHTTPClient()
                # 结合异步操作获取数据
                save_api_url = 'http://127.0.0.1:8000/async?save_url=&user=&from=room'.format(
                    message,
                    self.current_user
                )
                IOLoop.current().spawn_callback(client.fetch, save_api_url, request_timeout=30)
                message= u"[%s]于[%s]发送的url:<a href='%s' target='_blank'>%s</a>正在下载中..." % (
                    self.current_user,
                    datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                    message,
                    message
                )
                ChatWsHandler.send_updates(message)
            else:
                message = u"[%s]-[%s]-说:%s" % (self.current_user, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), message)
                # 添加历史聊天信息之用户新发送的聊天信息
                ChatWsHandler.history.append(message)
                # 给每个等待的用户发送新的历史聊天记录信息
                ChatWsHandler.send_updates(message)

    @classmethod
    def send_updates(cls, message):
        """给每个登录的用户发送新信息"""
        for w in ChatWsHandler.online_users:
            w.write_message(message)


    # 关闭:有用户退出聊天室时会自动调用
    def on_close(self):
        # print("有用户已经退出聊天室!!!")
        self.online_users.remove(self)
        message = u"[%s]-[%s]-离开聊天室" % (self.current_user, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        # 向所有在线用户发送消息——告诉有人退出
        for u in self.online_users:
            u.write_message(message)
        # 添加历史聊天信息之用户退出信息
        ChatWsHandler.history.append(message)

(2)修改service.py文件:

import tornado.gen
import tornado.web
from tornado.httpclient import AsyncHTTPClient

class AsyncSaveHandler(AuthBaseHandler):
    """
    异步上传指定url的图片功能
    """
    @tornado.gen.coroutine
    def get(self,*args,**kwargs):
        save_url = self.get_argument('save_url', None)
        username = self.get_argument('user', None)
        is_from_room = self.get_argument('from', None) == 'room'
        # 确保用户登录且源于room页面
        if username != 'None' and is_from_room:
            try:
                resp = yield self.get_rep(save_url)
                upload_im = UploadImage(self.settings['static_path'], '.jpg'.format(uuid4().hex))
                # 1.用户上传图片的保存
                upload_im.save_upload(resp.body)
                # 2.生成用户上传图片对应的缩略图并保存
                upload_im.make_thumb()
                # 3.用户上传图片数据的入库
                post = add_post(username, upload_im.image_url, upload_im.thumb_url)
                message = "新图片保存成功-> <a href='http://43.142.78.214:8000/post/' target='_blank'>http://43.142.78.214:8000/post/</a>".format(post.id, post.id)
                ChatWsHandler.send_updates(message)
            except:
                ChatWsHandler.send_updates('您刚发送的url对应图片因为未知力量保存失败!')
        else:
            # 如果不符合
            ChatWsHandler.send_updates('请登录之后再进行操作!')

    # 使用延迟执行
    @tornado.gen.coroutine
    def get_rep(self,url):
        # yield tornado.gen.sleep(5)
        client = AsyncHTTPClient()
        resp = yield client.fetch(url, request_timeout=30)
        return resp

实现效果:

以上是关于16.tornado操作之聊天室和爬取图片功能整合的主要内容,如果未能解决你的问题,请参考以下文章

用python爬取豆瓣电影信息,输入类别和爬取页数,想怎么爬就怎么爬,哎就是玩!

给裸接口加一道防护,避免恶意盗刷和爬取

CKEditor 版本探测和爬取历史漏洞(整理文)

HtmlParse:一款超轻量级的HTML文件解析和爬取工具

17.tornado操作之屎一样的代码的整合+详细过程

Python-王者荣耀自动刷金币+爬取英雄信息+图片