Python模板-Mako语法介绍

 python  Python模板-Mako语法介绍已关闭评论
9月 052019
 

资源

官网 http://www.makotemplates.org/

文档 http://docs.makotemplates.org/en/latest/

文档翻译 Mako模板入门 http://help.42qu.com/code/mako.html

安装

pip install mako

HelloWorld

from mako.template import Template

mytemplate = Template("hello world!")
print mytemplate.render()

-------------------------

from mako.template import Template
print Template("hello ${data}!").render(data="world")

语法

输出变量 ${x}

数学计算 ${1+1}
the contents within the ${} tag are evaluated by Python directly, so full expressions are OK

filter
${"test"|u}
${"test"|u,trim}
内置filter列表
    u : URL escaping, provided by urllib.quote_plus(string.encode('utf-8'))
    h : HTML escaping, provided by markupsafe.escape(string)
    x : XML escaping
    trim : whitespace trimming, provided by string.strip()
    entity : produces HTML entity references for applicable strings, derived from htmlentitydefs
    unicode (str on Python 3): produces a Python unicode string (this function is applied by default)
    decode.<some encoding> : decode input into a Python unicode with the specified encoding
    n : disable all default filtering; only filters specified in the local expression tag will be applied.

分支
% if x == 5:
    abcd
% endif

循环
% for a in ['1', '2', '3']:
    % if a == '1':
      abc
    % elif a == '2':
      def
    % else:
      gh
    % endif
$ endfor

Python语法
this is a template
<%
    x = db.get_resource('foo')
    y = [z.element for z in x if x.frobnizzle==5]
%>
% for elem in y:
    element: ${elem}
% endfor

换行

加 / 强制不换行


设置变量
% for item in ('apple', 'banana'):
    <%
        isBanana = False
    %>
    % if item == 'banana':
    <%
        isBanana = True
    %>
    %endif
    % if isBanana:
        <span> Bought a banana</span>
    %endif
%endfor

注释

## 这是一个注释.
...text ...

多行
<%doc>
这里是注释
更多注释
</%doc>

模块级别语句

<% %> 的一个变体是 <%! %>,代表模块级别的代码块。其中的代码会在模板的模块级别执行,而不是在模板的 rendering 函数中。

<%!
import mylib
import re

def filter(text):
    return re.sub(r'^@', '', text)
%>

标签

定义了当前模板的总体特性,包括缓存参数,以及模板被调用时期待的参数列表(非必须)
<%page args="x, y, z='default'"/>
<%page cached="True" cache_type="memory"/>


<%include file="header.html"/>
hello world
<%include file="footer.html"/>

%def 标签用于定义包含一系列内容的一个 Python 函数,此函数在当前模板的其他某个地方被调用到
<%def name="myfunc(x)">
this is myfunc, x is ${x}
</%def>
${myfunc(7)}

<%block filter="h">
some <html> stuff.
</%block>
<%block name="header">
    <h2><%block name="title"/></h2>
</%block>

Mako 中的 %namespace 等价于 Python 里的 import 语句。它允许访问其他模板文件的所有 rendering 函数和元数据
<%namespace file="functions.html" import="*"/>

<%inherit file="base.html"/>

处理多行注释:
<%doc>
    these are comments
    more comments
</%doc>

该标签使得 Mako 的词法器对模板指令的常规解析动作停止,并以纯文本的形式返回其整个内容部分
<%text filter="h">
heres some fake mako ${syntax}
<%def name="x()">${x}</%def>
</%text>

有时你想中途停止执行一个模板或者 <%def> 方法,只返回已经收集到的文本信息,可以通过在 Python 代码块中使用 return 语句来完成

% if not len(records):
    No records found.
    <% return %>
% endif

文件template

为提高性能,从文件中加载的 Template, 可以将它产生的模块的源代码以普通 python 模块文件的形式(.py),

缓存到文件系统中。只要加一个参数 module_directory 即可做到这一点:

from mako.template import Template

mytemplate = Template(filename='/docs/mytmpl.txt', module_directory='/tmp/mako_modules')
print mytemplate.render()

当上述代码被 render 的时候,会创建文件 /tmp/mako_modules/docs/mytmpl.txt.py.

下一次 Template 对象被用同样参数调用的时候,就会直接重用该模块文件。

文件TemplateLookup

#有一个对 header.txt 文件的包含引用。而从何处去查找 header.txt, 则由 TemplateLookup 指明,是 "/docs" 目录
from mako.template import Template
from mako.lookup import TemplateLookup

mylookup = TemplateLookup(directories=['/docs'])
mytemplate = Template("""<%include file="header.txt"/> hello world!""", lookup=mylookup)


--------------

#可以直接通过 TemplateLookup 来获取模板对象,利用 TemplateLookup 的 get_template 方法,
#并传递模板的 URI 作为参数
mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
mytemplate = mylookup.get_template("foo.txt")
print mytemplate.render()

-------------
参数
mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace', , collection_size=500)
TemplateLookup 同时也会在内存中缓存一组模板,所以并不是每一次请求都会导致模板的重新编译和模块重新加载。默认 TemplateLookup 的大小没有限制,但你可以通过 collection_size 参数来限制它
以上的 lookup 会持续加载模板到内存中,直到达到 500 的时候,它就会清除掉一定比例的模板缓存项,根据“最近最少访问”原则

另一个 TemplateLookup 相关的标志是  filesystem_checks. 默认为 True,
每一次 get_template() 方法返回模板后,原始的模板文件的 revision time 会和上次加载模板的时间做对比,
如果文件更新,则会加载其内容,并重新编译该模板。
在生产环境下,设置 filesystem_checks 为 False 可以带来一定的性能提升(和具体的文件系统有关)

自己创建context

from mako.template import Template
from mako.runtime import Context
from StringIO import StringIO

mytemplate = Template("hello, ${name}!")
buf = StringIO()
ctx = Context(buf, name="jack")
mytemplate.render_context(ctx)
print buf.getvalue()

其他

1.解决mako中文乱码问题

TemplateLookup(... , output_encoding='utf-8', ...)
Template(..., input_encoding='utf-8')
又在mako的模板文件的首行添加
## -*- encoding:utf8 -*-

单星号与双星号(*和**)在python函数中的应用

 python  单星号与双星号(*和**)在python函数中的应用已关闭评论
9月 042019
 

想不到单星号还能用于解压参数列表!!

在python的函数中经常能看到输入的参数前面有一个或者两个星号:例如

这两种用法其实都是用来将任意个数的参数导入到python函数中。

单星号(*):*args
将所以参数以元组(tuple)的形式导入:
例如:

双星号(**):**kwargs
将参数以字典的形式导入

此外,单星号的另一个用法是解压参数列表:(这种用法让人惊艳!)

当然这两个用法可以同时出现在一个函数中:例如

centos 7.6 下python2.7 安装 MySQL-python问题解决

 python  centos 7.6 下python2.7 安装 MySQL-python问题解决已关闭评论
5月 162019
 

centos7.6 下python2.7版本使用pip install MySQL-python可能出现下面错误:

可能问题一:  ERROR: Complete output from command python setup.py egg_info:
ERROR: sh: mysql_config: 未找到命令

解决办法: yum install mysql-devel

 

再次安装,没问题最好, 如果出现下面问题:

 可能问题二:_mysql.c:29:20: 致命错误:Python.h:没有那个文件或目录
#include “Python.h”

解决办法: yum install python-devel

 

再次安装 : pip install MySQL-python

问题解决!

 

python之turtle库使用介绍

 python  python之turtle库使用介绍已关闭评论
11月 192018
 

turtle库真是太强大了。转自:https://blog.csdn.net/zengxiantao1994/article/details/76588580/

        Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x、纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行的路径上绘制了图形。

turtle绘图的基础知识:
1. 画布(canvas)

        画布就是turtle为我们展开用于绘图区域,我们可以设置它的大小和初始位置。

        设置画布大小

         turtle.screensize(canvwidth=None, canvheight=None, bg=None),参数分别为画布的宽(单位像素), 高, 背景颜色。

        如:turtle.screensize(800,600, “green”)

               turtle.screensize() #返回默认大小(400, 300)

        turtle.setup(width=0.5, height=0.75, startx=None, starty=None),参数:width, height: 输入宽和高为整数时, 表示像素; 为小数时, 表示占据电脑屏幕的比例,(startx, starty): 这一坐标表示矩形窗口左上角顶点的位置, 如果为空,则窗口位于屏幕中心。

        如:turtle.setup(width=0.6,height=0.6)

               turtle.setup(width=800,height=800, startx=100, starty=100)

2. 画笔

2.1 画笔的状态

        在画布上,默认有一个坐标原点为画布中心的坐标轴,坐标原点上有一只面朝x轴正方向小乌龟。这里我们描述小乌龟时使用了两个词语:坐标原点(位置),面朝x轴正方向(方向), turtle绘图中,就是使用位置方向描述小乌龟(画笔)的状态。

2.2 画笔的属性

        画笔(画笔的属性,颜色、画线的宽度等)

        1) turtle.pensize():设置画笔的宽度;

        2) turtle.pencolor():没有参数传入,返回当前画笔颜色,传入参数设置画笔颜色,可以是字符串如”green”, “red”,也可以是RGB 3元组。

        3) turtle.speed(speed):设置画笔移动速度,画笔绘制的速度范围[0,10]整数,数字越大越快。

2.3 绘图命令

         操纵海龟绘图有着许多的命令,这些命令可以划分为3种:一种为运动命令,一种为画笔控制命令,还有一种是全局控制命令。

(1)    画笔运动命令

命令

说明

turtle.forward(distance)

向当前画笔方向移动distance像素长度

turtle.backward(distance)

向当前画笔相反方向移动distance像素长度

turtle.right(degree)

顺时针移动degree°

turtle.left(degree)

逆时针移动degree°

turtle.pendown()

移动时绘制图形,缺省时也为绘制

turtle.goto(x,y)

将画笔移动到坐标为x,y的位置

turtle.penup()

提起笔移动,不绘制图形,用于另起一个地方绘制

turtle.circle()

画圆,半径为正(负),表示圆心在画笔的左边(右边)画圆

setx( )

将当前x轴移动到指定位置

sety( )

将当前y轴移动到指定位置

setheading(angle)

设置当前朝向为angle角度

home()

设置当前画笔位置为原点,朝向东。

dot(r)

绘制一个指定直径和颜色的圆点

 

(2)     画笔控制命令

命令

说明

turtle.fillcolor(colorstring)

绘制图形的填充颜色

turtle.color(color1, color2)

同时设置pencolor=color1, fillcolor=color2

turtle.filling()

返回当前是否在填充状态

turtle.begin_fill()

准备开始填充图形

turtle.end_fill()

填充完成

turtle.hideturtle()

隐藏画笔的turtle形状

turtle.showturtle()

显示画笔的turtle形状

 

(3)    全局控制命令

命令

说明

turtle.clear()

清空turtle窗口,但是turtle的位置和状态不会改变

turtle.reset()

清空窗口,重置turtle状态为起始状态

turtle.undo()

撤销上一个turtle动作

turtle.isvisible()

返回当前turtle是否可见

stamp()

复制当前图形

turtle.write(s [,font=(“font-name”,font_size,”font_type”)])

写文本,s为文本内容,font是字体的参数,分别为字体名称,大小和类型;font为可选项,font参数也是可选项

 

(4)    其他命令

命令

说明

turtle.mainloop()或turtle.done()

启动事件循环 -调用Tkinter的mainloop函数。

必须是乌龟图形程序中的最后一个语句。

turtle.mode(mode=None)

设置乌龟模式(“standard”,“logo”或“world”)并执行重置。如果没有给出模式,则返回当前模式。

模式

初始龟标题

正角度

standard

向右(东)

逆时针

logo

向上(北)

顺时针

turtle.delay(delay=None)

设置或返回以毫秒为单位的绘图延迟。

turtle.begin_poly()

开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。

turtle.end_poly()

停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。

turtle.get_poly()

返回最后记录的多边形。

 

3. 命令详解

        3.1 turtle.circle(radius, extent=None, steps=None)

        描述:以给定半径画圆

        参数:

        radius(半径):半径为正(负),表示圆心在画笔的左边(右边)画圆;

        extent(弧度) (optional);

        steps (optional) (做半径为radius的圆的内切正多边形,多边形边数为steps)。

举例:

circle(50) # 整圆;

circle(50,steps=3) # 三角形;

circle(120, 180) # 半圆

 

实例:

1、太阳花

# coding=utf-8
import turtle
import time

# 同时设置pencolor=color1, fillcolor=color2
turtle.color(“red”, “yellow”)

turtle.begin_fill()
for _ in range(50):
  turtle.forward(200)
  turtle.left(170)
turtle.end_fill()

turtle.mainloop()

2、五角星

# coding=utf-8
import turtle
import time

turtle.pensize(5)
turtle.pencolor(“yellow”)
turtle.fillcolor(“red”)

turtle.begin_fill()
for _ in range(5):
  turtle.forward(200)
  turtle.right(144)
turtle.end_fill()
time.sleep(2)
 
turtle.penup()
turtle.goto(-150,-120)
turtle.color(“violet”)
turtle.write(“Done”, font=(‘Arial’, 40, ‘normal’))

turtle.mainloop()

3、时钟程序

# coding=utf-8
 
import turtle
from datetime import *
 
# 抬起画笔,向前运动一段距离放下
def Skip(step):
    turtle.penup()
    turtle.forward(step)
    turtle.pendown()
 
def mkHand(name, length):
    # 注册Turtle形状,建立表针Turtle
    turtle.reset()
    Skip(-length * 0.1)
    # 开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。
    turtle.begin_poly()
    turtle.forward(length * 1.1)
    # 停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。
    turtle.end_poly()
    # 返回最后记录的多边形。
    handForm = turtle.get_poly()
    turtle.register_shape(name, handForm)
 
def Init():
    global secHand, minHand, hurHand, printer
    # 重置Turtle指向北
    turtle.mode(“logo”)
    # 建立三个表针Turtle并初始化
    mkHand(“secHand”, 135)
    mkHand(“minHand”, 125)
    mkHand(“hurHand”, 90)
    secHand = turtle.Turtle()
    secHand.shape(“secHand”)
    minHand = turtle.Turtle()
    minHand.shape(“minHand”)
    hurHand = turtle.Turtle()
    hurHand.shape(“hurHand”)
   
    for hand in secHand, minHand, hurHand:
        hand.shapesize(1, 1, 3)
        hand.speed(0)
   
    # 建立输出文字Turtle
    printer = turtle.Turtle()
    # 隐藏画笔的turtle形状
    printer.hideturtle()
    printer.penup()
    
def SetupClock(radius):
    # 建立表的外框
    turtle.reset()
    turtle.pensize(7)
    for i in range(60):
        Skip(radius)
        if i % 5 == 0:
            turtle.forward(20)
            Skip(-radius – 20)
           
            Skip(radius + 20)
            if i == 0:
                turtle.write(int(12), align=”center”, font=(“Courier”, 14, “bold”))
            elif i == 30:
                Skip(25)
                turtle.write(int(i/5), align=”center”, font=(“Courier”, 14, “bold”))
                Skip(-25)
            elif (i == 25 or i == 35):
                Skip(20)
                turtle.write(int(i/5), align=”center”, font=(“Courier”, 14, “bold”))
                Skip(-20)
            else:
                turtle.write(int(i/5), align=”center”, font=(“Courier”, 14, “bold”))
            Skip(-radius – 20)
        else:
            turtle.dot(5)
            Skip(-radius)
        turtle.right(6)
        
def Week(t):   
    week = [“星期一”, “星期二”, “星期三”,
            “星期四”, “星期五”, “星期六”, “星期日”]
    return week[t.weekday()]
 
def Date(t):
    y = t.year
    m = t.month
    d = t.day
    return “%s %d%d” % (y, m, d)
 
def Tick():
    # 绘制表针的动态显示
    t = datetime.today()
    second = t.second + t.microsecond * 0.000001
    minute = t.minute + second / 60.0
    hour = t.hour + minute / 60.0
    secHand.setheading(6 * second)
    minHand.setheading(6 * minute)
    hurHand.setheading(30 * hour)
    
    turtle.tracer(False) 
    printer.forward(65)
    printer.write(Week(t), align=”center”,
                  font=(“Courier”, 14, “bold”))
    printer.back(130)
    printer.write(Date(t), align=”center”,
                  font=(“Courier”, 14, “bold”))
    printer.home()
    turtle.tracer(True)
 
    # 100ms后继续调用tick
    turtle.ontimer(Tick, 100)
 
def main():
    # 打开/关闭龟动画,并为更新图纸设置延迟。
    turtle.tracer(False)
    Init()
    SetupClock(160)
    turtle.tracer(True)
    Tick()
    turtle.mainloop()
 
if __name__ == “__main__”:
    main()

效果让人惊叹。

python中 getopt 使用

 python  python中 getopt 使用已关闭评论
4月 242018
 
python中 getopt 模块,
该模块是专门用来处理命令行参数的

函数getopt(args, shortopts, longopts = [])
参数args一般是sys.argv[1:]
shortopts  短格式 (-) 

longopts 长格式(--) 

命令行中输入:
python test.py -i 127.0.0.1 -p 80 55 66

python test.py –ip=127.0.0.1 –port=80 55 66

下面的代码:

try:
options,args = getopt.getopt(sys.argv[1:],”hp:i:”,[“help”,”ip=”,”port=”])
except getopt.GetoptError:
sys.exit()

for name,value in options:
if name in (“-h”,”–help”):
usage()
if name in (“-i”,”–ip”):
print ‘ip is—-‘,value
if name in (“-p”,”–port”)

print 'port is----',value

options,args = getopt.getopt(sys.argv[1:],"hp:i:",["help","ip=","port="])

“hp:i:”
短格式 — h 后面没有冒号:表示后面不带参数,p:和 i:后面有冒号表示后面需要参数

[“help”,”ip=”,”port=”]

长格式 — help后面没有等号=,表示后面不带参数,其他三个有=,表示后面需要参数

返回值 options 是个包含元祖的列表,每个元祖是分析出来的格式信息,比如 [(‘-i’,’127.0.0.1′),(‘-p’,’80’)] ;
 args 是个列表,包含那些没有‘-’或‘–’的参数,比如:[’55’,’66’]

注意:定义命令行参数时,要先定义带’-‘选项的参数,再定义没有‘-’的参数

Python模块搜索路径简介

 python, 开发  Python模块搜索路径简介已关闭评论
2月 142018
 

由于某些原因,在使用 import 时,Python 找不到相应的模块。这时,解释器就会发牢骚 – ImportError。
那么,Python 如何知道在哪里搜索模块的路径呢?
模块搜索路径
当导入名为 hello 的模块时,解释器首先搜索具有该名称的内置模块。如果没有找到,将在变量 sys.path 给出的目录列表中搜索名为 hello.py 的文件。
sys.path 从这些位置初始化:
包含输入脚本的目录(或当前目录,当没有指定文件时)
PYTHONPATH(目录名列表,与 shell 变量 PATH 语法相同)
与安装相关的默认值
>>> import sys
>>> sys.path
[”, ‘/usr/local/lib/python35.zip’, ‘/usr/local/lib/python3.5’, ‘/usr/local/lib/python3.5/plat-linux’,
 ‘/usr/local/lib/python3.5/lib-dynload’, ‘/usr/local/lib/python3.5/site-packages’]
注意: ” 表示当前目录(当前脚本所在的路径)
例如,在 /home/wang/workspace 中创建一个名为 hello.py 的模块,内容如下:
print(‘Hello’)
然后,试图加载该模块:
>>> import os
>>> 
>>> os.getcwd() # 获取当前目录
‘/home/wang’
>>> 
>>> import hello.py

ImportError: No module named ‘hello’
很遗憾,由于 sys.path 中没有包含 /home/wang/workspace 这个路径,所以找不到 hello 模块,从而引发 ImportError。
添加模块搜索路径
为了解决上述问题,需要添加模块搜索路径,可以使用以下几种方式:
1.动态增加路径 
临时生效,对于不经常使用的模块,这通常是最好的方式,因为不必用所有次要模块的路径来污染 PYTHONPATH。
2.修改 PYTHONPATH 变量 
永久生效,对于在许多程序中都使用的模块,可以采用这种方式。这将改变所有 Python 应用的搜索路径,因为启动 Python 时,它会读取这个变量,甚至不同版本的 Python 都会受影响。
3.增加 .pth 文件 
永久生效,这是最简单的、也是推荐的方式。Python 在遍历已知的库文件目录过程中,如果遇到 .pth 文件,便会将其中的路径加入到 sys.path 中,于是 .pth 中所指定的路径就可以被 Python 运行环境找到了。

方法一:动态增加路径
通过 sys 模块的 append() 方法在 Python 环境中增加搜索路径:
>>> import sys
>>> sys.path.append(‘/home/wang/workspace’)
现在,查看搜索路径:
>>> sys.path
[”, ‘/usr/local/lib/python35.zip’, ‘/usr/local/lib/python3.5’, ‘/usr/local/lib/python3.5/plat-linux’,
 ‘/usr/local/lib/python3.5/lib-dynload’, ‘/usr/local/lib/python3.5/site-packages’, ‘/home/wang/workspace’]
>>> 
>>> import hello
Hello
可以看到,路径被成功添加进去了,再次执行导入可以正常使用。

方法二:修改 PYTHONPATH 变量
打开并编辑 bashrc:
$ vim ~/.bashrc
将以下内容附加到文件末尾:
export PYTHONPATH=$PYTHONPATH:/home/wang/workspace
不要忘记重新加载 shell,方法是退出并重新启动,或者在命令行重新加载配置文件:
$ source ~/.bashrc # 或者 . ~/.bashrc

方法三:增加 .pth 文件
查看sys.path中列出的site-packages和dist-packages路径, 比如:在上例中 /usr/local/lib/python3.5/site-packages 下添加一个扩展名为 .pth 的配置文件(例如:extras.pth),内容为要添加的路径:
/home/wang/workspace

使用Gevent编写Python并发程序

 python  使用Gevent编写Python并发程序已关闭评论
1月 242018
 

转自:http://www.missshi.cn/api/view/blog/59a6b2e8e519f50d040000fe

众所周知,Python是非常擅长网络爬虫的。

而对于一个大规模的网络爬虫而言,使用常规的Python编程会使得效率极其低效。

本文主要讲解如何在Python中利用Gevent来大幅提高程序运行的效率。

让我们从一个标准的Python顺序执行代码开始吧!

一段正常运行的Python代码如下:

  1. import requests
  2. import time
  3.  
  4. def request_url(url):
  5.     """
  6.     # 访问一个url并得到响应结果
  7.     :param url:
  8.     :return:
  9.     """
  10.     response = requests.get(url)
  11.     return response.content
  12.  
  13. if __name__ == "__main__":
  14.     # 准备一个待访问的url列表,该列表共包含4 * 10 = 40个url
  15.     url_list = ['https://github.com/',
  16.                 'http://www.missshi.cn:8888/',
  17.                 'https://www.python.org/',
  18.                 'https://www.yahoo.com/'] * 10
  19.     response_list = []
  20.     begin_time = time.time()  #记录当前时间
  21.     for url in url_list:
  22.         print url
  23.         response_content = request_url(url)
  24.         response_list.append(response_content)
  25.     end_time = time.time()  #记录结束时间
  26.     used_time = end_time - begin_time  #计算消耗时间
  27.     print used_time

运行该程序时,我们可以发现它会依次遍历url_list中的每一个url。

在上一个请求得到响应后,再去发送下一个请求。

在我本地调试时,访问40个url的总耗时为33.207s。

而这其中,绝大部分的时间都是在等待接口的响应结果。

Gevent又称之为协程,它是一个有助于大幅度提高网络传输应用型服务的性能。

Gevent的主要实现原理是在运行一个任务时,如果遇到IO或网络相关的操作,会在发送请求后切换到别的任务去处理,而不是在原任务中等待接收响应。这样一来,对于一个大量网络请求的任务而言,它可能起到很好的并发效果。

首先,我们通过一个简单的示例程序了解一下Gevent库的使用。

  1. import gevent
  2.  
  3. def function1(str1, str2):
  4.     print "************"
  5.     print str1
  6.     print str2
  7.  
  8. if __name__ == "__main__":
  9.     task_list = [] #准备一个任务列表
  10.     for i in range(5):
  11.         str1 = "string1_" + str(i)
  12.         str2 = "string2_" + str(i)
  13.         task_list.append(gevent.spawn(function1, str1, str2))  #向任务列表中添加任务
  14.     result = gevent.joinall(task_list)

对于gevent而言,我们需要准备一个任务列表。

任务列表中每一个元素都是一个gevent.spawn()对象。

其中,gevent.spawn()函数可以接收一至多个参数。

第一个参数为任务需要执行的函数,后续的参数为函数对应的输入参数。

最终,当我们得到完成的任务列表后,可以调用gevent.joinall()来执行该列表中的任务。

运行该程序,我们可以得到如下结果:

  1. ************
  2. string1_0
  3. string2_0
  4. ************
  5. string1_1
  6. string2_1
  7. ************
  8. string1_2
  9. string2_2
  10. ************
  11. string1_3
  12. string2_3
  13. ************
  14. string1_4
  15. string2_4

通过观察结果,我们不难发现,该程序仍然是顺序执行的所有的任务,而没有在不同的任务中进行切换。

那么是什么原因呢?

1. 没有包含IO或网络操作,因此没有自动触发切换任务。

2. 也没有手工触发切换进程。

首先,我们先来学习如何手工触发切换任务:

只需要添加一行代码gevent.sleep()后,得到的代码如下:

  1. import gevent
  2.  
  3. def function1(str1, str2):
  4.     print "************"
  5.     print str1
  6.     gevent.sleep()  #添加一行代码
  7.     print str2
  8.  
  9. if __name__ == "__main__":
  10.     task_list = []
  11.     for i in range(5):
  12.         str1 = "string1_" + str(i)
  13.         str2 = "string2_" + str(i)
  14.         task_list.append(gevent.spawn(function1, str1, str2))
  15.     result = gevent.joinall(task_list)

重新运行程序后观察结果:

  1. ************
  2. string1_0
  3. ************
  4. string1_1
  5. ************
  6. string1_2
  7. ************
  8. string1_3
  9. ************
  10. string1_4
  11. string2_0
  12. string2_1
  13. string2_2
  14. string2_3
  15. string2_4

观察结果后,我们可以发现程序在运行到gevent.sleep()后,不会继续在当前任务中执行,而是切换至别的任务中运行。

当然,在应用代码中,我们很少会手工触发gevent.sleep()来切换任务。

而是通过引入一些相关的函数,可以自动起到在面临网络请求的任务时,自动切换任务。

具体的实现方法我们根据如下代码来进行讲解:

  1. import gevent
  2. import requests
  3. import time
  4.  
  5. def request_url(url):
  6.     """
  7.     # 访问一个url并得到响应结果
  8.     :param url:
  9.     :return:
  10.     """
  11.     from gevent import monkey
  12.     monkey.patch_socket()  #引入猴子补丁
  13.     print url
  14.     response = requests.get(url)
  15.     print "response of url:", url
  16.     return response.content
  17.  
  18. if __name__ == "__main__":
  19.     url_list = ['https://github.com/',
  20.                 'http://www.missshi.cn:8888/',
  21.                 'https://www.python.org/',
  22.                 'https://www.yahoo.com/'] * 10
  23.     task_list = []
  24.     response_list = []
  25.     begin_time = time.time()
  26.     for url in url_list:
  27.         task_list.append(gevent.spawn(request_url, url))
  28.     result = gevent.joinall(task_list)
  29.     end_time = time.time()
  30.     used_time = end_time - begin_time
  31.     print used_time

需要注意的是,当我们引入猴子补丁后,会对已经以后的方法进行改写。

因此,不建议在全局范围内引入猴子补丁,最好是在哪部分为并发执行函数,则在哪部分引入猴子补丁。

在引入猴子补丁后,当运行到网络请求时,则会切换至其他任务继续执行,而不是在当前任务中继续等待。

最后,我们来讲解一下针对任务列表中的任务,在执行完成后如何获取并发任务的返回值。

  1. if __name__ == "__main__":
  2.     url_list = ['https://github.com/',
  3.                 'http://www.missshi.cn:8888/',
  4.                 'https://www.python.org/',
  5.                 'https://www.yahoo.com/'] * 10
  6.     task_list = []
  7.     response_list = []
  8.     begin_time = time.time()
  9.     for url in url_list:
  10.         task_list.append(gevent.spawn(request_url, url))
  11.     result = gevent.joinall(task_list)
  12.     response_list = [element.value for element in result]  #从result中获取每个请求的Response
  13.     end_time = time.time()
  14.     used_time = end_time - begin_time
  15.     print used_time

对于gevent.joinall()函数而言,得到的结果是一个迭代器。

其中,迭代器中每一个元素都包含一个属性value,其对应值为每个任务函数的返回值。

Python中第三方库Requests库的用法

 python  Python中第三方库Requests库的用法已关闭评论
10月 092017
 

python中第三方库Requests库的使用,来自:http://www.jb51.net/article/108168.htm

一、Requests库的安装

利用 pip 安装,如果你安装了pip包(一款Python包管理工具,不知道可以百度哟),或者集成环境,比如Python(x,y)或者anaconda的话,就可以直接使用pip安装Python的库。

$ pip install requests

安装完成之后,下面来看一下基本的方法:

#get请求方法
 >>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
#打印get请求的状态码
 >>> r.status_code
200
#查看请求的数据类型,可以看到是json格式,utf-8编码
 >>> r.headers['content-type']
'application/json; charset=utf8'
 >>> r.encoding
'utf-8'
#打印请求到的内容
 >>> r.text
u'{"type":"User"...'
#输出json格式数据
 >>> r.json()
 {u'private_gists': 419, u'total_private_repos': 77, ...}

下面看一个小栗子:

#小例子
import requests

r = requests.get('http://www.baidu.com')
print type(r)
print r.status_code
print r.encoding
print r.text
print r.cookies
'''请求了百度的网址,然后打印出了返回结果的类型,状态码,编码方式,Cookies等内容 输出:'''
<class 'requests.models.Response'>
200
UTF-8
<RequestsCookieJar[]>

二、http基本请求

requests库提供了http所有的基本请求方式。例如:

r = requests.post("http://httpbin.org/post")
r = requests.put("http://httpbin.org/put")
r = requests.delete("http://httpbin.org/delete")
r = requests.head("http://httpbin.org/get")
r = requests.options(http://httpbin.org/get)

基本GET请求

r = requests.get("http://httpbin.org/get")
#如果想要加参数,可以利用 params 参数:
import requests
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print r.url

#输出:http://httpbin.org/get?key2=value2&key1=value1

如果想请求JSON文件,可以利用 json() 方法解析,例如自己写一个JSON文件命名为a.json,内容如下:

["foo", "bar", {
"foo": "bar"
}]
#利用如下程序请求并解析:
import requests
r = requests.get("a.json")
print r.text
print r.json()
'''运行结果如下,其中一个是直接输出内容,另外一个方法是利用 json() 方法 解析,感受下它们的不同:'''
["foo", "bar", {
"foo": "bar"
}]
[u'foo', u'bar', {u'foo': u'bar'}]

如果想获取来自服务器的原始套接字响应,可以取得 r.raw 。 不过需要在初始请求中设置 stream=True。

r = requests.get('https://github.com/timeline.json', stream=True)
r.raw
#输出
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'

这样就获取了网页原始套接字内容。

如果想添加 headers,可以传 headers 参数:

import requests

payload = {'key1': 'value1', 'key2': 'value2'}
headers = {'content-type': 'application/json'}
r = requests.get("http://httpbin.org/get", params=payload, headers=headers)
print r.url
#通过headers参数可以增加请求头中的headers信息

三、基本POST请求

对于 POST 请求来说,我们一般需要为它增加一些参数。那么最基本的传参方法可以利用 data 这个参数。

import requests

payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)
print r.text
#运行结果如下:
{
"args": {}, 
"data": "", 
"files": {}, 
"form": {
"key1": "value1", 
"key2": "value2"
}, 
"headers": {
"Accept": "*/*", 
"Accept-Encoding": "gzip, deflate", 
"Content-Length": "23", 
"Content-Type": "application/x-www-form-urlencoded", 
"Host": "http://httpbin.org", 
"User-Agent": "python-requests/2.9.1"
}, 
"json": null, 
"url": "http://httpbin.org/post"
}

可以看到参数传成功了,然后服务器返回了我们传的数据。

有时候我们需要传送的信息不是表单形式的,需要我们传JSON格式的数据过去,所以我们可以用 json.dumps() 方法把表单数据序列化。

import json
import requests

url = 'http://httpbin.org/post'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload))
print r.text

#运行结果:
{
"args": {}, 
"data": "{\"some\": \"data\"}", 
"files": {}, 
"form": {}, 
"headers": {
"Accept": "*/*", 
"Accept-Encoding": "gzip, deflate", 
"Content-Length": "16", 
"Host": "http://httpbin.org", 
"User-Agent": "python-requests/2.9.1"
}, 
"json": {
"some": "data"
}, 
"url": "http://httpbin.org/post"
}

通过上述方法,我们可以POST JSON格式的数据

如果想要上传文件,那么直接用 file 参数即可:

#新建一个 test.txt 的文件,内容写上 Hello World!
import requests

url = 'http://httpbin.org/post'
files = {'file': open('test.txt', 'rb')}
r = requests.post(url, files=files)
print r.text

{
"args": {}, 
"data": "", 
"files": {
"file": "Hello World!"
}, 
"form": {}, 
"headers": {
"Accept": "*/*", 
"Accept-Encoding": "gzip, deflate", 
"Content-Length": "156", 
"Content-Type": "multipart/form-data; boundary=7d8eb5ff99a04c11bb3e862ce78d7000", 
"Host": "http://httpbin.org", 
"User-Agent": "python-requests/2.9.1"
}, 
"json": null, 
"url": "http://httpbin.org/post"
}

这样我们便成功完成了一个文件的上传。

requests 是支持流式上传的,这允许你发送大的数据流或文件而无需先把它们读入内存。要使用流式上传,仅需为你的请求体提供一个类文件对象即可,非常方便:

with open('massive-body') as f:
requests.post('http://some.url/streamed', data=f)

四、Cookies

如果一个响应中包含了cookie,那么我们可以利用 cookies 变量来拿到:

import requests

url = 'Example Domain'
r = requests.get(url)
print r.cookies
print r.cookies['example_cookie_name']

以上程序仅是样例,可以用 cookies 变量来得到站点的 cookies

另外可以利用 cookies 变量来向服务器发送 cookies 信息:

import requests

url = 'http://httpbin.org/cookies'
cookies = dict(cookies_are='working')
r = requests.get(url, cookies=cookies)
print r.text
#输出:
'{"cookies": {"cookies_are": "working"}}'

五、超时配置

可以利用 timeout 变量来配置最大请求时间

requests.get(‘Build software better, together', timeout=0.001)

注:timeout 仅对连接过程有效,与响应体的下载无关。

也就是说,这个时间只限制请求的时间。即使返回的 response 包含很大内容,下载需要一定时间。

六、会话对象

在以上的请求中,每次请求其实都相当于发起了一个新的请求。也就是相当于我们每个请求都用了不同的浏览器单独打开的效果。也就是它并不是指的一个会话,即使请求的是同一个网址。比如:

import requests

requests.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = requests.get("http://httpbin.org/cookies")
print(r.text)
#结果是:
{
"cookies": {}
}

很明显,这不在一个会话中,无法获取 cookies,那么在一些站点中,我们需要保持一个持久的会话怎么办呢?就像用一个浏览器逛淘宝一样,在不同的选项卡之间跳转,这样其实就是建立了一个长久会话。

解决方案如下:

import requests

s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get("http://httpbin.org/cookies")
print(r.text)
#在这里我们请求了两次,一次是设置 cookies,一次是获得 cookies
{
"cookies": {
"sessioncookie": "123456789"
}
}

发现可以成功获取到 cookies 了,这就是建立一个会话到作用。

那么既然会话是一个全局的变量,那么我们肯定可以用来全局的配置了。

import requests

s = requests.Session()
s.headers.update({'x-test': 'true'})
r = s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
print r.text
'''通过 s.headers.update 方法设置了 headers 的变量。然后我们又在请求中 设置了一个 headers,那么会出现什么结果?很简单,两个变量都传送过去了。 运行结果:'''
{
"headers": {
"Accept": "*/*", 
"Accept-Encoding": "gzip, deflate", 
"Host": "http://httpbin.org", 
"User-Agent": "python-requests/2.9.1", 
"X-Test": "true", 
"X-Test2": "true"
}
}

如果get方法传的headers 同样也是 x-test 呢?

r = s.get('http://httpbin.org/headers', headers={'x-test': 'true'})

#它会覆盖掉全局的配置:
{
"headers": {
"Accept": "*/*", 
"Accept-Encoding": "gzip, deflate", 
"Host": "http://httpbin.org", 
"User-Agent": "python-requests/2.9.1", 
"X-Test": "true"
}
}

如果不想要全局配置中的一个变量了呢?很简单,设置为 None 即可。

r = s.get('http://httpbin.org/headers', headers={'x-test': None})
{
"headers": {
"Accept": "*/*", 
"Accept-Encoding": "gzip, deflate", 
"Host": "http://httpbin.org", 
"User-Agent": "python-requests/2.9.1"
}
}

以上就是 session 会话的基本用法。

七、SSL证书验证

现在随处可见 https 开头的网站,Requests可以为HTTPS请求验证SSL证书,就像web浏览器一样。要想检查某个主机的SSL证书,你可以使用 verify 参数,因为前段时间12306 证书不是无效的嘛,来测试一下:

import requests

r = requests.get('https://kyfw.12306.cn/otn/', verify=True)
print r.text
#结果:
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)

来试下 github 的:

import requests

r = requests.get('Build software better, together', verify=True)
print r.text

嗯,正常请求,由于内容太多,我就不粘贴输出了。

如果我们想跳过刚才 12306 的证书验证,把 verify 设置为 False 即可:

import requests

r = requests.get('https://kyfw.12306.cn/otn/', verify=False)
print r.text

发现就可以正常请求了。在默认情况下 verify 是 True,所以如果需要的话,需要手动设置下这个变量。

八、代理

如果需要使用代理,你可以通过为任意请求方法提供 proxies 参数来配置单个请求。

import requests

proxies = {
"https": "http://41.118.132.69:4433"
}
r = requests.post("http://httpbin.org/post", proxies=proxies)
print r.text
#也可以通过环境变量 HTTP_PROXY 和 HTTPS_PROXY 来配置代理
export HTTP_PROXY="http://10.10.1.10:3128"
	

export HTTPS_PROXY=http://10.10.1.10:1080


使用python的urllib, urllib2, httplib 实现get,post请求数据的简单例子

 python  使用python的urllib, urllib2, httplib 实现get,post请求数据的简单例子已关闭评论
9月 132017
 



使用python的urllib, urllib2, httplib 实现get,post请求数据的简单例子 ,转自:http://blog.csdn.net/mack415858775/article/details/39696107



测试用CGI,名字为test.py,放在apache的cgi-bin目录下:

#!/usr/bin/python
import cgi
def main(): 
    print “Content-type: text/html\n”
    form = cgi.FieldStorage()
    if form.has_key(“ServiceCode”) and form[“ServiceCode”].value != “”:
        print “<h1> Hello”,form[“ServiceCode”].value,”</h1>” 
    else:   
        print “<h1> Error! Please enter first name.</h1>” 
main()

 

python发送post和get请求

get请求:

使用get方式时,请求数据直接放在url中。
方法一、
import urllib
import urllib2

url = “http://192.168.81.16/cgi-bin/python_test/test.py?ServiceCode=aaaa

req = urllib2.Request(url)
print req

res_data = urllib2.urlopen(req)
res = res_data.read()
print res

方法二、
import httplib

url = “http://192.168.81.16/cgi-bin/python_test/test.py?ServiceCode=aaaa

conn = httplib.HTTPConnection(“192.168.81.16”)
conn.request(method=”GET”,url=url) 

response = conn.getresponse()
res= response.read()
print res

post请求:

使用post方式时,数据放在data或者body中,不能放在url中,放在url中将被忽略。
方法一、
import urllib
import urllib2

test_data = {‘ServiceCode’:’aaaa’,’b’:’bbbbb’}
test_data_urlencode = urllib.urlencode(test_data)

requrl = “http://192.168.81.16/cgi-bin/python_test/test.py

req = urllib2.Request(url = requrl,data =test_data_urlencode)
print req

res_data = urllib2.urlopen(req)
res = res_data.read()
print res


方法二、
import urllib
import httplib 
test_data = {‘ServiceCode’:’aaaa’,’b’:’bbbbb’}
test_data_urlencode = urllib.urlencode(test_data)

requrl = “http://192.168.81.16/cgi-bin/python_test/test.py
headerdata = {“Host”:”192.168.81.16″}

conn = httplib.HTTPConnection(“192.168.81.16”)

conn.request(method=”POST”,url=requrl,body=test_data_urlencode,headers = headerdata) 

response = conn.getresponse()

res= response.read()

print res
对python中json的使用不清楚,所以临时使用了urllib.urlencode(test_data)方法;

 

模块urllib,urllib2,httplib的区别
        httplib实现了http和https的客户端协议,但是在python中,模块urllib和urllib2对httplib进行了更上层的封装。
 

介绍下例子中用到的函数:
1、HTTPConnection函数

httplib.HTTPConnection(host[,port[,stict[,timeout]]])
这个是构造函数,表示一次与服务器之间的交互,即请求/响应
host        标识服务器主机(服务器IP或域名)
port         默认值是80
strict        模式是False,表示无法解析服务器返回的状态行时,是否抛出BadStatusLine异常
例如:
         conn = httplib.HTTPConnection(“192.168.81.16″,80)          与服务器建立链接。

 
2、HTTPConnection.request(method,url[,body[,header]])函数
这个是向服务器发送请求
method           请求的方式,一般是post或者get,

例如:

         method=”POST”或method=”Get”
url                  请求的资源,请求的资源(页面或者CGI,我们这里是CGI)

例如:

        url=”http://192.168.81.16/cgi-bin/python_test/test.py”      请求CGI

        或者

        url=”http://192.168.81.16/python_test/test.html”                请求页面
body               需要提交到服务器的数据,可以用json,也可以用上面的格式,json需要调用json模块
headers         请求的http头headerdata = {“Host”:”192.168.81.16″}
例如:
test_data = {‘ServiceCode’:’aaaa’,’b’:’bbbbb’}
test_data_urlencode = urllib.urlencode(test_data)
requrl = “http://192.168.81.16/cgi-bin/python_test/test.py
headerdata = {“Host”:”192.168.81.16″}
conn = httplib.HTTPConnection(“192.168.81.16″,80)
conn.request(method=”POST”,url=requrl,body=test_data_urlencode,headers = headerdata)  
conn在使用完毕后,应该关闭,conn.close()


3、HTTPConnection.getresponse()函数
     这个是获取http响应,返回的对象是HTTPResponse的实例。

 


4、HTTPResponse介绍:
HTTPResponse的属性如下:
read([amt])                              获取响应消息体,amt表示从响应流中读取指定字节的数据,没有指定时,将全部数据读出;
getheader(name[,default])      获得响应的header,name是表示头域名,在没有头域名的时候,default用来指定返回值
getheaders()                           以列表的形式获得header
例如:

date=response.getheader(‘date’);
print date
resheader=”
resheader=response.getheaders();
print resheader

列形式的响应头部信息:

[(‘content-length’, ‘295’), (‘accept-ranges’, ‘bytes’), (‘server’, ‘Apache’), (‘last-modified’, ‘Sat, 31 Mar 2012 10:07:02 GMT’), (‘connection’, ‘close’), (‘etag’, ‘”e8744-127-4bc871e4fdd80″‘), (‘date’, ‘Mon, 03 Sep 2012 10:01:47 GMT’), (‘content-type’, ‘text/html’)] 

date=response.getheader(‘date’);
print date

取出响应头部的date的值。

详解Python中的下划线

 python  详解Python中的下划线已关闭评论
7月 052017
 

重新温习下下划线, 转自:http://python.jobbole.com/81129/

本文将讨论Python中下划线(_)字符的使用方法。我们将会看到,正如Python中的很多事情,下划线的不同用法大多数(并非所有)只是常用惯例而已。

单下划线(_)

通常情况下,会在以下3种场景中使用:

1、在解释器中:在这种情况下,“_”代表交互式解释器会话中上一条执行的语句的结果。这种用法首先被标准CPython解释器采用,然后其他类型的解释器也先后采用。

2、作为一个名称:这与上面一点稍微有些联系,此时“_”作为临时性的名称使用。这样,当其他人阅读你的代码时将会知道,你分配了一个特定的名称,但是并不会在后面再次用到该名称。例如,下面的例子中,你可能对循环计数中的实际值并不感兴趣,此时就可以使用“_”。

3、国际化:也许你也曾看到”_“会被作为一个函数来使用。这种情况下,它通常用于实现国际化和本地化字符串之间翻译查找的函数名称,这似乎源自并遵循相应的C约定。例如,在Django文档“转换”章节中,你将能看到如下代码:

可以发现,场景二和场景三中的使用方法可能会相互冲突,所以我们需要避免在使用“_”作为国际化查找转换功能的代码块中同时使用“_”作为临时名称。

名称前的单下划线(如:_shahriar)

程序员使用名称前的单下划线,用于指定该名称属性为“私有”。这有点类似于惯例,为了使其他人(或你自己)使用这些代码时将会知道以“_”开头的名称只供内部使用。正如Python文档中所述:

以下划线“_”为前缀的名称(如_spam)应该被视为API中非公开的部分(不管是函数、方法还是数据成员)。此时,应该将它们看作是一种实现细节,在修改它们时无需对外部通知。

正如上面所说,这确实类似一种惯例,因为它对解释器来说确实有一定的意义,如果你写了代码“from <模块/包名> import *”,那么以“_”开头的名称都不会被导入,除非模块或包中的“__all__”列表显式地包含了它们。了解更多请查看“Importing * in Python”。

名称前的双下划线(如:__shahriar)

名称(具体为一个方法名)前双下划线(__)的用法并不是一种惯例,对解释器来说它有特定的意义。Python中的这种用法是为了避免与子类定义的名称冲突。Python文档指出,“__spam”这种形式(至少两个前导下划线,最多一个后续下划线)的任何标识符将会被“_classname__spam”这种形式原文取代,在这里“classname”是去掉前导下划线的当前类名。例如下面的例子:

正如所预料的,“_internal_use”并未改变,而“__method_name”却被变成了“_ClassName__method_name”。此时,如果你创建A的一个子类B,那么你将不能轻易地覆写A中的方法“__method_name”。

这里的功能几乎和Java中的final方法和C++类中标准方法(非虚方法)一样。

名称前后的双下划线(如:__init__)

这种用法表示Python中特殊的方法名。其实,这只是一种惯例,对Python系统来说,这将确保不会与用户自定义的名称冲突。通常,你将会覆写这些方法,并在里面实现你所需要的功能,以便Python调用它们。例如,当定义一个类时,你经常会覆写“__init__”方法。

虽然你也可以编写自己的特殊方法名,但不要这样做。

其实,很容易摆脱这种类型的命名,而只让Python内部定义的特殊名称遵循这种约定。