使用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编程中对文件和存储器的读写示例
Jan 25 Python
使用Python来开发Markdown脚本扩展的实例分享
Mar 04 Python
让python 3支持mysqldb的解决方法
Feb 14 Python
Python自动发邮件脚本
Mar 31 Python
基于scrapy的redis安装和配置方法
Jun 13 Python
Python数据类型之Number数字操作实例详解
May 08 Python
Python matplotlib实时画图案例
Apr 23 Python
Django与pyecharts结合的实例代码
May 13 Python
基于python实现破解滑动验证码过程解析
May 28 Python
哪种Python框架适合你?简单介绍几种主流Python框架
Aug 04 Python
Django正则URL匹配实现流程解析
Nov 13 Python
实例详解Python的进程,线程和协程
Mar 13 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
PHP5中使用PDO连接数据库的方法
2010/08/01 PHP
PHP数字和字符串ID互转函数(类似优酷ID)
2014/06/30 PHP
php实现微信小程序授权登录功能(实现流程)
2019/11/13 PHP
一页面多XMLHttpRequest对象
2007/01/22 Javascript
jquery 学习笔记 传智博客佟老师附详细注释
2020/09/12 Javascript
window.showModalDialog参数传递中含有特殊字符的处理方法
2013/06/06 Javascript
Tab切换组件(选项卡功能)实例代码
2013/11/21 Javascript
jQuery实现查找最近父节点的方法
2016/06/23 Javascript
js实现炫酷的左右轮播图
2017/01/18 Javascript
EasyUI Datebox 日期验证之开始日期小于结束时间
2017/05/19 Javascript
微信小程序picker组件下拉框选择input输入框的实例
2017/09/20 Javascript
浅谈js的解析顺序 作用域 严格模式
2017/10/23 Javascript
浅谈JsonObject中的key-value数据解析排序问题
2017/12/06 Javascript
tween.js缓动补间动画算法示例
2018/02/13 Javascript
详解webpack-dev-server使用方法
2018/09/14 Javascript
Vue插值、表达式、分隔符、指令知识小结
2018/10/12 Javascript
vue中promise的使用及异步请求数据的方法
2018/11/08 Javascript
[03:09]2014DOTA2国际邀请赛 Mushi前队友送上祝福
2014/07/12 DOTA
python抓取网页内容示例分享
2014/02/24 Python
遍历python字典几种方法总结(推荐)
2016/09/11 Python
Python的mysql数据库的更新如何实现
2017/07/31 Python
Python参数类型以及常见的坑详解
2019/07/08 Python
python PyAutoGUI 模拟鼠标键盘操作和截屏功能
2019/08/04 Python
Python分析最近大火的网剧《隐秘的角落》
2020/07/02 Python
基于HTML5 Canvas 实现弹出框效果
2017/06/05 HTML / CSS
泰海淘:泰国king Power王权免税集团旗下跨境海淘综合型电商
2020/07/26 全球购物
iHerb俄罗斯:维生素、补品和天然产品
2020/07/09 全球购物
介绍一下Ruby中的对象,属性和方法
2012/07/11 面试题
广告设计专业自荐信范文
2013/11/14 职场文书
护理专业应届毕业生推荐信
2013/11/15 职场文书
英语系毕业生求职信
2014/07/13 职场文书
2014公司党员自我评价范文
2014/09/11 职场文书
业绩倒数第一的检讨书
2014/09/24 职场文书
考试作弊检讨书
2015/01/27 职场文书
公司欠款证明
2015/06/24 职场文书
关于Javascript闭包与应用的详解
2021/04/22 Javascript