使用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 相关文章推荐
精确查找PHP WEBSHELL木马的方法(1)
Apr 12 Python
python 3利用BeautifulSoup抓取div标签的方法示例
May 28 Python
Python多线程爬虫实战_爬取糗事百科段子的实例
Dec 15 Python
Python操作mongodb数据库的方法详解
Dec 08 Python
python栈的基本定义与使用方法示例【初始化、赋值、入栈、出栈等】
Oct 24 Python
基于python读取.mat文件并取出信息
Dec 16 Python
基于Django实现日志记录报错信息
Dec 17 Python
Python标准库itertools的使用方法
Jan 17 Python
Django基于客户端下载文件实现方法
Apr 21 Python
python 将视频 通过视频帧转换成时间实例
Apr 23 Python
python实点云分割k-means(sklearn)详解
May 28 Python
Python基于httpx模块实现发送请求
Jul 07 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
浅析php单例模式
2014/11/25 PHP
页面利用渐进式JPEG来提升用户体验度
2014/12/01 PHP
PHPStrom 新建FTP项目以及在线操作教程
2016/10/16 PHP
php+redis消息队列实现抢购功能
2018/02/08 PHP
jQuery 使用个人心得
2009/02/26 Javascript
node.js中的socket.io入门实例
2014/04/26 Javascript
jQuery中innerHeight()方法用法实例
2015/01/19 Javascript
javascript实现table表格隔行变色的方法
2015/05/13 Javascript
jQuery基于ajax实现带动画效果无刷新柱状图投票代码
2015/08/10 Javascript
form表单转Json提交的方法(推荐)
2016/09/23 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
2017/01/04 Javascript
利用node.js写一个爬取知乎妹纸图的小爬虫
2017/05/03 Javascript
Angular 4.X开发实践中的踩坑小结
2017/07/04 Javascript
promise处理多个相互依赖的异步请求(实例讲解)
2017/08/03 Javascript
在JS循环中使用async/await的方法
2018/10/12 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变rgba的a值实现)
2019/01/24 Javascript
详解vue引入子组件方法
2019/02/12 Javascript
基于Vue 撸一个指令实现拖拽功能
2019/10/09 Javascript
Django之模型层多表操作的实现
2019/01/08 Python
django多对多表的创建,级联删除及手动创建第三张表
2019/07/25 Python
numpy矩阵数值太多不能全部显示的解决
2020/05/14 Python
python将字典内容写入json文件的实例代码
2020/08/12 Python
Numpy中np.random.rand()和np.random.randn() 用法和区别详解
2020/10/23 Python
纯CSS3实现自定义Tooltip边框涂鸦风格的教程
2014/11/05 HTML / CSS
工程师求职简历的自我评价分享
2013/10/10 职场文书
党员培训思想汇报
2014/01/07 职场文书
列车长先进事迹材料
2014/01/25 职场文书
教堂婚礼主持词
2014/03/14 职场文书
学校清明节活动总结
2014/07/04 职场文书
国际贸易求职信
2014/07/05 职场文书
2015年农村党员干部主题教育活动总结
2015/03/25 职场文书
拾金不昧通报表扬范文
2015/05/05 职场文书
大学生团支书竞选稿
2015/11/21 职场文书
2016年第十四个公民道德宣传日活动总
2016/04/01 职场文书
python代码实现备忘录案例讲解
2021/07/26 Python
Python中Matplotlib的点、线形状、颜色以及绘制散点图
2022/04/07 Python