使用Python的Tornado框架实现一个Web端图书展示页面


Posted in Python onJuly 11, 2016

首先,为什么选择Tornado:
1.高性能的网络库,这可以和gevent,twisted,libevent等做对。
提供了异步io支持,超时事件处理,在此基础上提供了tcpserver,httpclient,尤其是curlhttpclient,
在现有http客户端中肯定排第一。可以用来做爬虫,游戏服务器,据我所知业界已有使用tornado作为游戏服务器

2.web框架,这可以和django,flask对。
提供了路由,模板等web框架必备组件。与其他区别是tornado是异步的,天然适合长轮训,
这也是friendfeed发明tornado的原因,当前flask也可以支持,但必须借助gevent等

3.较为完备的http服务器,这点可以和nginx,apache对比,
但只支持http1.0,所以使用nginx做前段不仅是为了更好利用多核,也是让其支持http1.1

4.完备的wsgi服务器,这可以和gunicore,gevent wsgi server做对比,
也就是说可以让flask运行在tornado之上,让tornado加速flask

5.提供了完备的websocket支持,这让html5的游戏等提供了便利。
像知乎长轮训就是使用了websocket,但websocket手机支持的不是很好,
前段时间不得不使用定时ajax发送大量请求,期待手机浏览器赶快奋起直追

使用tornado创建一个简单的图书介绍页
好了,言归正传,下面我们来看一下这个图书介绍页的代码实现:
1.创建一个web服务的入口文件 blockmain.py

#coding:utf-8
import tornado.web
import tornado.httpserver
import tornado.ioloop
import tornado.options
import os.path
import json
import urllib2

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

class MainHandler(tornado.web.RequestHandler):
  def get(self):
    self.render(
      "index.html",
      page_title = "Burt's Books ¦ Home",
      header_text = "Welcome to Burt's Books!",
      books = ['细说php','python','PHP','小时代']
    )


class HelloModule(tornado.web.UIModule):
  def render(self):
    return'<h1>I am yyx and this is an information from module hello!</h1>'

class BookModule(tornado.web.UIModule):
  def render(self,bookname):
    doubanapi = r'https://api.douban.com/v2/book/'
    searchapi = r'https://api.douban.com/v2/book/search?q='
    searchurl = searchapi+bookname
    searchresult = urllib2.urlopen(searchurl).read()
    bookid = json.loads(searchresult)['books'][0]['id']
    bookurl = doubanapi+bookid
    injson = urllib2.urlopen(bookurl).read()
    bookinfo = json.loads(injson)
    return self.render_string('modules/book.html',book = bookinfo)

  def embedded_javascript(self):
    return "document.write(\"hi!\")"

  def embedded_css(self):
    return '''.book {background-color:#F5F5F5}
         .book_body{color:red}
    '''

  def html_body(self):
    return '<script>document.write("Hello!")</script>'

if __name__ == "__main__":
  tornado.options.parse_command_line()
  app = tornado.web.Application(
    handlers = [
      (r'/',MainHandler),

    ],
    template_path = os.path.join(os.path.dirname(__file__),'templates'),
    static_path = os.path.join(os.path.dirname(__file__),'static'),
    debug = True,
    ui_modules={'Hello':HelloModule,'Book':BookModule}


    )
  http_server = tornado.httpserver.HTTPServer(app)
  http_server.listen(options.port)
  tornado.ioloop.IOLoop.instance().start()

说明一下,一些基本的MVC概念:
tornado也是通过pathinfo模式来匹配用户的输入来获得参数,然后再调用相应的处理函数,它是通过为各种匹配模式设定相应的class类来处理,比如我这里就是通过class MainHandler来处理来自/的get请求
MainHandler把请求render渲染到index.html,参数在index.html中通过{{参数}}来调用

2.建立相应的模板,先创建一个基础的父类main.html模板,创建templates目录,在它下面创建main.html,这个模板只是定义了最基础的网页框架,里面的具体内容由继承于它的子类来具体实现

<html>
<head>
  <title>{{ page_title }}</title>
  <link rel="stylesheet" href="{{ static_url("css/style.css") }}" />
</head>
<body>
  <div id="container">
    <header>
      {% block header %}<h1>Burt's Books</h1>{% end %}
    </header>
    <div id="main">
      <div id="content">
        {% block body %}{% end %}
      </div>
    </div>
    <footer>
      {% set mailLink = '<a href="mailto:contact@burtsbooks.com">Contact Us</a>' %}
      {% set script = '<script>alert("hello")</script>' %}
      {% block footer %}

        <p>
          For more information about our selection, hours or events, please email us at{% raw mailLink %}

          <!-- {% raw script %} 这里将原样输出,也就是会弹一个框--> 
        </p>
      {% end %}
    </footer>
  </div>
  <script src="{{ static_url("js/script.js") }}"></script>
  </body>
</html>

这里是定义了一个主框架,其中里面的{% block header %}<h1>Burt's Books</h1>{% end %}是为了子类模板的继承的块(block),当子类继承了这个main.html,具体这个块里写什么内容由子类来实现,不实现的话就使用父类的默认 值,如是这里的<h1>Burt's Books</h1>,MainHandler类是render到一个index.html,那么接下来写一个index.html来继承这 个父类

{% extends "main.html" %}

{% block header %}
  <h1>{{ header_text }}</h1>
{% end %}

{% block body %}
  <div id="hello">
    <p>Welcome to Burt's Books!</p>
    {% module Hello() %}

    {% for book in books %}
      {% module Book(book) %}
    {% end %}
    <p>...</p>
  </div>
{% end %}

简单简洁吧,这也是使用了继承的好处,不用再重复写父类的东西,只要实现父类的block内容即可
MainHandler类里的render方法中的参数

page_title = "Burt's Books | Home",
header_text = "Welcome to Burt's Books!",
books = ['细说php','python','PHP','小时代']

将会通过参数传送到这里来
tornado的模板里可以使用python的代码,加上{% %}当使用if for while等要使用{% end %}结尾
代码中{% module Book(book) %} 将会调用入口服务文件中的定义和'Book'所对应的模块
ui_modules={'Hello':HelloModule,'Book':BookModule} 也就是BookModule,查看上面的BookModule定义

class BookModule(tornado.web.UIModule):
  def render(self,bookname):
    doubanapi = r'https://api.douban.com/v2/book/'
    searchapi = r'https://api.douban.com/v2/book/search?q='
    searchurl = searchapi+bookname
    searchresult = urllib2.urlopen(searchurl).read()
    bookid = json.loads(searchresult)['books'][0]['id']
    bookurl = doubanapi+bookid
    injson = urllib2.urlopen(bookurl).read()
    bookinfo = json.loads(injson)
    return self.render_string('modules/book.html',book = bookinfo)

BookModule 继承自tornado.web.UIModule,UI模块的使用是最后render_string()方法来把一个对象渲染到一个模板中去,我这里简单 的使用了豆瓣的图书api,先通过search来查询一下包含关键词的图书信息,返回第一条图书的id,再使用book api来查询该图书的具体信息,将这个具体图书的信息render到对应的模板
在templates 目录下创建modules目录,再下创建一个book.html,这里是具体的book要显示的内容框架

<div class="book">
  <h3 class="book_title">{{ book["title"] }}</h3>
  <a href="{{book['alt']}}" target="_blank"><p>点击查看详情</p></a>
  {% if book["subtitle"] != "" %}
    <h4 class="book_subtitle">{{ book["subtitle"] }}</h4>
  {% end %}
  <img src="{{ book["images"]["large"] }}" class="book_image"/>
  <div class="book_details">
    <div class="book_date_released">Released: {{ book["pubdate"]}}</div>    
    <h5>Description:</h5>
    <div class="book_body">{% raw book["summary"] %}</div>
  </div>
</div>

最后的文件目录结构应该是这样的

├── blockmain.py
└── templates
  ├── index.html
  ├── main.html
  └── modules
    └── book.html

程序的执行是这样的:
先通过路径‘/'来使用MainHandler类访问index.html---->index.html继承自 main.html---->index.html中的{% module Book(book) %}反过来查找blockmain.py中的Book对应的ui_modules---->ui_modules中将查询得到的book对象内容渲 染到modules下的book.html中,这样就把完整的内容呈现出来了,没有做前端…… 通过python blockmain.py启动服务,通过http://localhost:8000 来访问得到如下的网页

使用Python的Tornado框架实现一个Web端图书展示页面

Python 相关文章推荐
python实现k-means聚类算法
Feb 23 Python
pandas 取出表中一列数据所有的值并转换为array类型的方法
Apr 11 Python
Django实现登录随机验证码的示例代码
Jun 20 Python
详解python调用cmd命令三种方法
Jul 08 Python
使用 python pyautogui实现鼠标键盘控制功能
Aug 04 Python
django将数组传递给前台模板的方法
Aug 06 Python
Python对列表的操作知识点详解
Aug 20 Python
详解Django将秒转换为xx天xx时xx分
Sep 27 Python
Python线程条件变量Condition原理解析
Jan 20 Python
windows10环境下用anaconda和VScode配置的图文教程
Mar 30 Python
django queryset相加和筛选教程
May 18 Python
Python使用Opencv打开笔记本电脑摄像头报错解问题及解决
Jun 21 Python
Windows中使用wxPython和py2exe开发Python的GUI程序的实例教程
Jul 11 #Python
Python的requests网络编程包使用教程
Jul 11 #Python
Python的SQLalchemy模块连接与操作MySQL的基础示例
Jul 11 #Python
Python中的异常处理相关语句基础学习笔记
Jul 11 #Python
Python编写简单的HTML页面合并脚本
Jul 11 #Python
Python中super()函数简介及用法分享
Jul 11 #Python
Swift中的协议(protocol)学习教程
Jul 08 #Python
You might like
网页游戏开发入门教程三(简单程序应用)
2009/11/02 PHP
php中$_GET与$_POST过滤sql注入的方法
2014/11/03 PHP
php接口数据加密、解密、验证签名
2015/03/12 PHP
Ubuntu中启用php的mail()函数并解决发送邮件速度慢问题
2015/03/27 PHP
phpinfo() 中 Local Value(局部变量)Master Value(主变量) 的区别
2016/02/03 PHP
PHP 数组基本操作方法详解
2016/06/17 PHP
PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
2017/09/16 PHP
PHP7 mongoDB扩展使用的方法分享
2019/05/02 PHP
PHP配合fiddler抓包抓取微信指数小程序数据的实现方法分析
2020/01/02 PHP
基于Jquery的简单图片切换效果
2011/01/06 Javascript
用jQuery模拟select下拉框的简单示例代码
2014/01/26 Javascript
ie下$.getJSON出现问题的解决方法
2014/02/12 Javascript
easyui window refresh 刷新两次的解决方法(推荐)
2016/05/18 Javascript
BootStrap中Datetimepicker和uploadify插件应用实例小结
2016/05/26 Javascript
assert()函数用法总结(推荐)
2017/01/25 Javascript
解析vue中的$mount
2017/12/21 Javascript
JavaScript设计模式之缓存代理模式原理与简单用法示例
2018/08/07 Javascript
this在vue和小程序中的使用详解
2019/01/28 Javascript
javascript创建元素和删除元素实例小结
2019/06/19 Javascript
[03:05]《我与DAC》之xiao8:DAC与BG
2018/03/27 DOTA
[48:31]DOTA2-DPC中国联赛 正赛 Dynasty vs XG BO3 第一场 2月2日
2021/03/11 DOTA
python 字典(dict)遍历的四种方法性能测试报告
2014/06/25 Python
python删除指定类型(或非指定)的文件实例详解
2015/07/06 Python
Python 内置函数complex详解
2016/10/23 Python
python matlibplot绘制多条曲线图
2021/02/19 Python
Pytorch 中retain_graph的用法详解
2020/01/07 Python
Python基于xlutils修改表格内容过程解析
2020/07/28 Python
TripAdvisor西班牙官方网站:全球领先的旅游网站
2018/01/10 全球购物
三维科技面试题
2013/07/27 面试题
国际贸易专业推荐信
2013/11/15 职场文书
农民工工资承诺书范文
2014/03/31 职场文书
交警个人先进事迹材料
2014/05/11 职场文书
授权委托书格式
2014/07/31 职场文书
安全例会汇报材料
2014/08/23 职场文书
建筑安全员岗位职责
2015/02/15 职场文书
一文搞懂如何实现Go 超时控制
2021/03/30 Python