使用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生成器实现微线程编程的教程
Apr 13 Python
用python实现简单EXCEL数据统计的实例
Jan 24 Python
django开发之settings.py中变量的全局引用详解
Mar 29 Python
python中利用xml.dom模块解析xml的方法教程
May 24 Python
python统计字母、空格、数字等字符个数的实例
Jun 29 Python
django框架事务处理小结【ORM 事务及raw sql,customize sql 事务处理】
Jun 27 Python
pycharm修改文件的默认打开方式的步骤
Jul 29 Python
详解Python中的正斜杠与反斜杠
Aug 09 Python
Python列表list常用内建函数实例小结
Oct 22 Python
浅谈tensorflow之内存暴涨问题
Feb 05 Python
python给视频添加背景音乐并改变音量的具体方法
Jul 19 Python
Python自动登录QQ的实现示例
Aug 28 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
Thinkphp模板中使用自定义函数的方法
2012/09/23 PHP
迅速确定php多维数组的深度的方法
2014/01/07 PHP
学习php设计模式 php实现建造者模式
2015/12/07 PHP
PHP截取发动短信内容的方法
2017/07/04 PHP
javascript 鼠标拖动图标技术
2010/02/07 Javascript
利用JQuery和JS实现奇偶行背景颜色自定义效果
2012/11/19 Javascript
js中的布尔运算符使用介绍
2013/11/20 Javascript
javascript模拟实现C# String.format函数功能代码
2013/11/25 Javascript
JavaScript获取路径设计源码
2014/05/22 Javascript
jQuery中fadeOut()方法用法实例
2014/12/24 Javascript
jQuery中removeProp()方法用法实例
2015/01/05 Javascript
基于jQuery实现的扇形定时器附源码下载
2015/10/20 Javascript
使用json来定义函数,在里面可以定义多个函数的实现方法
2016/10/28 Javascript
图文讲解vue的v-if使用方法
2019/02/11 Javascript
node.js express框架简介与实现
2019/07/23 Javascript
js实现选项卡效果
2020/03/07 Javascript
解决vue字符串换行问题(绝对管用)
2020/08/06 Javascript
[01:00:25]NB vs Secret 2018国际邀请赛小组赛BO1 B组加赛 8.19
2018/08/21 DOTA
[49:08]FNATIC vs Infamous 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/18 DOTA
python中查找excel某一列的重复数据 剔除之后打印
2013/02/10 Python
python中List的sort方法指南
2014/09/01 Python
Python中的True,False条件判断实例分析
2015/01/12 Python
Python实现队列的方法
2015/05/26 Python
Python利用splinter实现浏览器自动化操作方法
2018/05/11 Python
Python实现字符串中某个字母的替代功能
2019/10/21 Python
世界领先的以旅馆为主的在线预订平台:Hostelworld
2016/10/09 全球购物
.NET初级开发工程师面试题(包括Javascript)
2012/08/22 面试题
工地安全检查制度
2014/02/04 职场文书
安全生产网格化管理实施方案
2014/03/01 职场文书
教师求职自荐信
2014/03/09 职场文书
三好学生个人先进事迹材料
2014/05/17 职场文书
村级四风对照检查材料
2014/08/24 职场文书
学习朴航瑛老师爱岗敬业先进事迹思想汇报
2014/09/17 职场文书
困难补助申请报告
2015/05/19 职场文书
工作年限证明范本
2015/06/15 职场文书
MySQL中TIMESTAMP类型返回日期时间数据中带有T的解决
2022/12/24 MySQL