跳至工具栏

Python3 实例

Python3 实例

以下实例在 Python3.4.3 版本下测试通过:

  • Python Hello World 实例
  • Python 数字求和
  • Python 平方根
  • Python 二次方程
  • Python 计算三角形的面积
  • Python 随机数生成
  • Python 摄氏温度转华氏温度
  • Python 交换变量
  • Python if 语句
  • Python 判断字符串是否为数字
  • Python 判断奇数偶数
  • Python 判断闰年
  • Python 获取最大值函数
  • Python 质数判断
  • Python 阶乘实例
  • Python 九九乘法表
  • Python 斐波那契数列
  • Python 阿姆斯特朗数
  • Python 十进制转二进制、八进制、十六进制
  • Python ASCII码与字符相互转换
  • Python 最大公约数算法
  • Python 最小公倍数算法
  • Python 简单计算器实现
  • Python 生成日历
  • Python 使用递归斐波那契数列
  • Python 文件 IO
  • Python 字符串判断
  • Python 字符串大小写转换
  • Python 计算每个月天数
  • Python 获取昨天日期
  • Python list 常用操作

python3 字典

Python3 字典

字典是另一种可变容器模型,且可存储任意类型对象。
字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({ })中 ,格式如下所示:

  d ={key1 : value1, key2 : value2}

键必须是唯一的,但值则不必。
值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。
一个简单的字典实例:

  
dict ={'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'  }

也可如此创建字典:

  dict1 ={ 'abc': 456
  };

 dict2 ={ 'abc': 123, 98.6: 37
  };


访问字典里的值

把相应的键放入到方括号中,如下实例:

实例

#!/usr/bin/python3 dict ={Name: Runoob, Age: 7, Class: First } print (dict[‘Name’]: , dict[Name]) print (dict[‘Age’]: , dict[Age])

以上实例输出结果:

  dict['Name']:  Runoob  dict['Age']:  7

如果用字典里没有的键访问数据,会输出错误如下:

实例

#!/usr/bin/python3 dict ={Name: Runoob, Age: 7, Class: First };

print (dict[‘Alice’]: , dict[Alice])

以上实例输出结果:

  Traceback (most recent call last):
    File "test.py", line 5, in <module>     
print ("dict['Alice']: ", dict['Alice'])  KeyError: 'Alice'

 


修改字典

向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:

实例

#!/usr/bin/python3 dict ={Name: Runoob, Age: 7, Class: First } dict[Age] = 8;


# 更新 Age
dict[School] = 教程
# 添加信息
print (dict[‘Age’]: , dict[Age]) print (dict[‘School’]: , dict[School])

以上实例输出结果:

  dict['Age']:  8  dict['School']:  教程

 


删除字典元素

能删单一的元素也能清空字典,清空只需一项操作。
显示删除一个字典用del命令,如下实例:

实例

#!/usr/bin/python3 dict ={Name: Runoob, Age: 7, Class: First } del dict[Name]
# 删除键 ‘Name’
dict.clear()
# 清空字典
del dict
# 删除字典
print (dict[‘Age’]: , dict[Age]) print (dict[‘School’]: , dict[School])

但这会引发一个异常,因为用执行 del 操作后字典不再存在:

  Traceback (most recent call last):
    File "test.py", line 9, in <module>     
print ("dict['Age']: ", dict['Age'])  
TypeError: 'type' object is not subscriptable

注:del() 方法后面也会讨论。
 

字典键的特性

字典值可以是任何的 python 对象,既可以是标准的对象,也可以是用户定义的,但键不行。
两个重要的点需要记住:
1)不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住,如下实例:

实例

#!/usr/bin/python3 dict ={Name: Runoob, Age: 7, Name: 小菜鸟 } print (dict[‘Name’]: , dict[Name])

以上实例输出结果:

  dict['Name']:  小菜鸟

2)键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行,如下实例:

实例

#!/usr/bin/python3 dict ={[Name]: Runoob, Age: 7 } print (dict[‘Name’]: , dict[Name])

以上实例输出结果:

  Traceback (most recent call last):
    File "test.py", line 3, in <module>     
dict ={['Name']: 'Runoob', 'Age': 7  }  
TypeError: unhashable type: 'list'

 


字典内置函数&

方法

Python字典包含了以下内置函数:

序号 函数及描述 实例
1 len(dict)
计算字典元素个数,即键的总数。
  
>>>
dict ={'Name': 'Runoob', 'Age': 7, 'Class': 'First'  }  
>>>len(dict)  3
2 str(dict)
输出字典,以可打印的字符串表示。
  
>>>
dict ={'Name': 'Runoob', 'Age': 7, 'Class': 'First'  }  
>>>str(dict)  "{'Name': 'Runoob', 'Class': 'First', 'Age': 7  }"
3 type(variable)
返回输入的变量类型,如果变量是字典就返回字典类型。
  
>>>
dict ={'Name': 'Runoob', 'Age': 7, 'Class': 'First'  }  
>>>type(dict)  <class 'dict'>

Python字典包含了以下内置方法:

序号 函数及描述
1 radiansdict.clear()
删除字典内所有元素
2 radiansdict.copy()
返回一个字典的浅复制
3 radiansdict.fromkeys()
创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值
4 radiansdict.get(key, default=None)
返回指定键的值,如果值不在字典中返回default值
5 key in dict
如果键在字典dict里返回true,否则返回false
6 radiansdict.items()
以列表返回可遍历的(键, 值) 元组数组
7 radiansdict.keys()
返回一个迭代器,可以使用 list() 来转换为列表
8 radiansdict.setdefault(key, default=None)
和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
9 radiansdict.update(dict2)
把字典dict2的键/值对更新到dict里
10 radiansdict.values()
返回一个迭代器,可以使用 list() 来转换为列表
11 pop(key[,default])
删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
12 popitem()
随机返回并删除字典中的一对键和值(一般删除末尾对)。

Python3 日期和时间

Python3 日期和时间

Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能。

Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间。

时间间隔是以秒为单位的浮点小数。

每个时间戳都以自从1970年1月1日午夜(历元)经过了多长时间来表示。

Python 的 time 模块下有很多函数可以转换常见日期格式。如函数time.time()用于获取当前时间戳, 如下实例:

#!/usr/bin/python3
import
time; # 引入time模块

ticks
= time.time()
print ("当前时间戳为:", ticks)

以上实例输出结果:

当前时间戳为: 1459996086.7115328

时间戳单位最适于做日期运算。但是1970年之前的日期就无法以此表示了。太遥远的日期也不行,UNIX和Windows只支持到2038年。


什么是时间元组?

很多Python函数用一个元组装起来的9组数字处理时间:

序号 字段
0 4位数年 2008
1 1 到 12
2 1到31
3 小时 0到23
4 分钟 0到59
5 0到61 (60或61 是闰秒)
6 一周的第几日 0到6 (0是周一)
7 一年的第几日 1到366 (儒略历)
8 夏令时 -1, 0, 1, -1是决定是否为夏令时的旗帜

上述也就是struct_time元组。这种结构具有如下属性:

序号 属性
0 tm_year 2008
1 tm_mon 1 到 12
2 tm_mday 1 到 31
3 tm_hour 0 到 23
4 tm_min 0 到 59
5 tm_sec 0 到 61 (60或61 是闰秒)
6 tm_wday 0到6 (0是周一)
7 tm_yday 一年中的第几天,1 到 366
8 tm_isdst 是否为夏令时,值有:1(夏令时)、0(不是夏令时)、-1(未知),默认 -1


获取当前时间

从返回浮点数的时间辍方式向时间元组转换,只要将浮点数传递给如localtime之类的函数。

#!/usr/bin/python3
import time

localtime
= time.localtime(time.time())
print
("本地时间为 :", localtime)

以上实例输出结果:

本地时间为 : time.struct_time(tm_year=2016, tm_mon=4, tm_mday=7, tm_hour=10, tm_min=28, tm_sec=49, tm_wday=3, tm_yday=98, tm_isdst=0)


获取格式化的时间

你可以根据需求选取各种格式,但是最简单的获取可读的时间模式的函数是asctime():

#!/usr/bin/python3
import
time

localtime
= time.asctime( time.localtime(time.time()) )
print
("本地时间为 :", localtime)

以上实例输出结果:

本地时间为 : Thu Apr  7 10:29:13 2016

格式化日期

我们可以使用 time 模块的 strftime 方法来格式化日期,:

time.strftime(format[, t])
#!/usr/bin/python3
import
time

# 格式化成2016-03-20 11:45:39形式

print
(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

# 格式化成Sat Mar 28 22:24:24 2016形式
print (time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()))

# 将格式字符串转换为时间戳

a
= "Sat Mar 28 22:24:24 2016"
print (time.mktime(time.strptime(a,"%a %b %d %H:%M:%S %Y")))

以上实例输出结果:

2016-04-07 10:29:46
Thu Apr 07 10:29:46
2016
1459175064.0

python中时间日期格式化符号:

  • %y 两位数的年份表示(00-99)
  • %Y 四位数的年份表示(000-9999)
  • %m 月份(01-12)
  • %d 月内中的一天(0-31)
  • %H 24小时制小时数(0-23)
  • %I 12小时制小时数(01-12)
  • %M 分钟数(00=59)
  • %S 秒(00-59)
  • %a 本地简化星期名称
  • %A 本地完整星期名称
  • %b 本地简化的月份名称
  • %B 本地完整的月份名称
  • %c 本地相应的日期表示和时间表示
  • %j 年内的一天(001-366)
  • %p 本地A.M.或P.M.的等价符
  • %U 一年中的星期数(00-53)星期天为星期的开始
  • %w 星期(0-6),星期天为星期的开始
  • %W 一年中的星期数(00-53)星期一为星期的开始
  • %x 本地相应的日期表示
  • %X 本地相应的时间表示
  • %Z 当前时区的名称
  • %% %号本身

获取某月日历

Calendar模块有很广泛的方法用来处理年历和月历,例如打印某月的月历:

#!/usr/bin/python3

import calendar
cal
= calendar.month(2016, 1)
print ("以下输出2016年1月份的日历:")
print (cal)

以上实例输出结果:

以下输出20161月份的日历:
    
January
2016
Mo
Tu We Th Fr Sa Su
1 2 3
4
5 6 7 8 9 10
11
12 13 14 15 16 17
18
19 20 21 22 23 24
25
26 27 28 29 30 31


Time 模块

Time 模块包含了以下内置函数,既有时间处理相的,也有转换时间格式的:

序号 函数及描述 实例
1 time.altzone
返回格林威治西部的夏令时地区的偏移秒数。如果该地区在格林威治东部会返回负值(如西欧,包括英国)。对夏令时启用地区才能使用。

以下实例展示了 altzone()函数的使用方法:


>>> import time
>>> print ("time.altzone %d " % time.altzone)
time.altzone -28800
2 time.asctime([tupletime])
接受时间元组并返回一个可读的形式为”Tue Dec 11 18:07:14 2008″(2008年12月11日 

周二18时07分14秒)的24个字符的字符串。

以下实例展示了 asctime()函数的使用方法:


>>> import time
>>> t = time.localtime()
>>> print ("time.asctime(t): %s " % time.asctime(t))
time.asctime(t): Thu Apr 7 10:36:20 2016
3 time.clock()
用以浮点数计算的秒数返回当前的CPU时间。用来衡量不同程序的耗时,比time.time()更有用。
实例
4 time.ctime([secs])
作用相当于asctime(localtime(secs)),未给参数相当于asctime()

以下实例展示了 ctime()函数的使用方法:


>>> import time
>>> print ("time.ctime() : %s" % time.ctime())
time
.ctime() : Thu Apr 7 10:51:58 2016
5 time.gmtime([secs])
接收时间辍(1970纪元后经过的浮点秒数)并返回格林威治天文时间下的时间元组t。注:t.tm_isdst始终为0

以下实例展示了 gmtime()函数的使用方法:


>>> import time
>>> print ("gmtime :", time.gmtime(1455508609.34375))
gmtime
: time.struct_time(tm_year=2016, tm_mon=2, tm_mday=15, tm_hour=3, tm_min=56, tm_sec=49, tm_wday=0, tm_yday=46, tm_isdst=0)
6 time.localtime([secs]
接收时间辍(1970纪元后经过的浮点秒数)并返回当地时间下的时间元组t(t.tm_isdst可取0或1,取决于当地当时是不是夏令时)。

以下实例展示了 localtime()函数的使用方法:


>>> import time
>>>
print ("localtime(): ", time.localtime(1455508609.34375))
localtime(): time.struct_time(tm_year=2016, tm_mon=2, tm_mday=15, tm_hour=11, tm_min=56, tm_sec=49, tm_wday=0, tm_yday=46, tm_isdst=0)
7 time.mktime(tupletime)
接受时间元组并返回时间辍(1970纪元后经过的浮点秒数)。
实例
8 time.sleep(secs)
推迟调用线程的运行,secs指秒数。

以下实例展示了 sleep()函数的使用方法:

#!/usr/bin/python3
import
time

print
("Start : %s" % time.ctime())
time.sleep( 5 )
print
("End : %s" % time.ctime())
9 time.strftime(fmt[,tupletime])
接收以时间元组,并返回以可读字符串表示的当地时间,格式由fmt决定。

以下实例展示了 strftime()函数的使用方法:


>>> import time
>>> print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
2016
-04-07 11:18:05
10 time.strptime(str,fmt=’%a %b %d %H:%M:%S %Y’)
根据fmt的格式把一个时间字符串解析为时间元组。

以下实例展示了 strftime()函数的使用方法:


>>> import time
>>> struct_time = time.strptime("30 Nov 00", "%d %b %y")
>>> print ("返回元组: ", struct_time)
返回元组:
time.struct_time(tm_year=2000, tm_mon=11, tm_mday=30, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=335, tm_isdst=-1)
11 time.time( )
返回当前时间的时间戳(1970纪元后经过的浮点秒数)。

以下实例展示了 time()函数的使用方法:


>>> import time
>>>
print(time.time())
1459999336.1963577
12 time.tzset()
根据环境变量TZ重新初始化时间相关设置。
实例

Time模块包含了以下2个非常重要的属性:

序号 属性及描述
1 time.timezone
属性time.timezone是当地时区(未启动夏令时)距离格林威治的偏移秒数(>0,美洲;

<=0大部分欧洲,亚洲,非洲)。

2 time.tzname
属性time.tzname包含一对根据情况的不同而不同的字符串,分别是带夏令时的本地时区名称,和不带的。


日历(Calendar)模块

此模块的函数都是日历相关的,例如打印某月的字符月历。

星期一是默认的每周第一天,星期天是默认的最后一天。更改设置需调用calendar.setfirstweekday()函数。模块包含了以下内置函数:

序号 函数及描述
1 calendar.calendar(year,w=2,l=1,c=6)
返回一个多行字符串格式的year年年历,3个月一行,间隔距离为c。 每日宽度间隔为w字符。每行长度为21* W+18+2* C。l是每星期行数。
2 calendar.firstweekday( )
返回当前每周起始日期的设置。默认情况下,首次载入calendar模块时返回0,即星期一。
3 calendar.isleap(year)
是闰年返回True,否则为false。
4 calendar.leapdays(y1,y2)
返回在Y1,Y2两年之间的闰年总数。
5 calendar.month(year,month,w=2,l=1)
返回一个多行字符串格式的year年month月日历,两行标题,一周一行。每日宽度间隔为w字符。每行的长度为7* w+6。l是每星期的行数。
6 calendar.monthcalendar(year,month)
返回一个整数的单层嵌套列表。每个子列表装载代表一个星期的整数。Year年month月外的日期都设为0;

范围内的日子都由该月第几日表示,从1开始。

7 calendar.monthrange(year,month)
返回两个整数。第一个是该月的星期几的日期码,第二个是该月的日期码。日从0(星期一)到6(星期日);

月从1到12。

8 calendar.prcal(year,w=2,l=1,c=6)
相当于 print calendar.calendar(year,w,l,c).
9 calendar.prmonth(year,month,w=2,l=1)
相当于 print calendar.calendar(year,w,l,c)。
10 calendar.setfirstweekday(weekday)
设置每周的起始日期码。0(星期一)到6(星期日)。
11 calendar.timegm(tupletime)
和time.gmtime相反:接受一个时间元组形式,返回该时刻的时间辍(1970纪元后经过的浮点秒数)。
12 calendar.weekday(year,month,day)
返回给定日期的日期码。0(星期一)到6(星期日)。月份为 1(一月) 到 12(12月)。


其他相关模块和函数

在Python中,其他处理日期和时间的模块还有:

  • time 模块
  • datetime模块

Python3 JSON 数据解析

Python3 JSON 数据解析

JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。

Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数:

  • json.dumps(): 对数据进行编码。
  • json.loads(): 对数据进行解码。

在json的编解码过程中,python 的原始类型与json类型会相互转换,具体的转化对照如下:

Python 编码为 JSON 类型转换对应表:

Python JSON
dict object
list, tuple array
str string
int,float, int- &

float-derived Enums

number
True true
False false
None null

JSON 解码为 Python 类型转换对应表:

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

json.dumps 与 json.loads 实例

以下实例演示了 Python 数据结构转换为JSON:


#!/usr/bin/python3
import json 
# Python 字典类型转换为 JSON 对象 data ={
    'no': 1,
     'name': 'W3CSchool',
     'url': 'http://www.soxitoday.com'
  }  json_str = json.dumps(data) 
print ("Python 原始数据:", repr(data)) 
print ("JSON 对象:", json_str) 

执行以上代码输出结果为:

 Python 原始数据:{'url': 'http://www.soxitoday.com', 'no': 1, 'name': 'W3CSchool'
  } JSON 对象:{"url": "http://www.soxitoday.com", "no": 1, "name": "W3CSchool"  } 

通过输出的结果可以看出,简单类型通过编码后跟其原始的repr()输出结果非常相似。

接着以上实例,我们可以将一个JSON编码的字符串转换回一个Python数据结构:


#!/usr/bin/python3
import json 
# Python 字典类型转换为 JSON 对象 data1 ={
    'no': 1,
     'name': 'W3CSchool',
     'url': 'http://www.soxitoday.com'
  }  json_str = json.dumps(data1) 
print ("Python 原始数据:", repr(data1)) 
print ("JSON 对象:", json_str) 
# 将 JSON 对象转换为 Python 字典 data2 = json.loads(json_str) 
print ("data2['name']: ", data2['name']) 
print ("data2['url']: ", data2['url']) 

执行以上代码输出结果为:

 ython 原始数据:{'name': 'W3CSchool', 'no': 1, 'url': 'http://www.soxitoday.com'
  } JSON 对象:{"name": "W3CSchool", "no": 1, "url": "http://www.soxitoday.com"  } data2['name']:  W3CSchool data2['url']:  http://www.soxitoday.com 

如果你要处理的是文件而不是字符串,你可以使用 json.dump()json.load() 来编码和解码JSON数据。例如:


# 写入 JSON 数据 with open('data.json', 'w') as f:
     json.dump(data, f) 
# 读取数据 with open('data.json', 'r') as f:
     data = json.load(f) 

更多资料请参考:https://docs.py
thon.org/3/library/json.html

Python3 XML解析

Python3 XML解析


什么是XML?

XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习XML教程

XML 被设计用来传输和存储数据。

XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。

它也是元标记语言,即定义了用于定义其他与特定领域有关的、语义的、结构化的标记语言的句法语言。


python对XML的解析

常见的XML编程接口有DOM和SAX,这两种接口处理XML文件的方式不同,当然使用场合也不同。

python有三种方法解析XML,SAX,DOM,以及ElementTree:

1.SAX (simple API for XML )

python 标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。

2.DOM(Document Object Model)

将XML数据在内存中解析成一个树,通过对树的操作来操作XML。

本章节使用到的XML实例文件movies.xml内容如下:

<collection shelf="New Arrivals">
<movie title="Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title="Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
<movie title="Trigun">
<type>Anime, Action</type>
<format>DVD</format>
<episodes>4</episodes>
<rating>PG</rating>
<stars>10</stars>
<description>Vash the Stampede!</description>
</movie>
<movie title="Ishtar">
<type>Comedy</type>
<format>VHS</format>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom</description>
</movie>
</collection>

python使用SAX解析xml

SAX是一种基于事件驱动的API。

利用SAX解析XML文档牵涉到两个部分:解析器和事件处理器。

解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件;

而事件处理器则负责对事件作出相应,对传递的XML数据进行处理。

Python3 多线程

Python3 多线程

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  • 程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

  • 线程可以被抢占(中断)。
  • 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) — 这就是线程的退让。

线程可以分为:

  • 内核线程:由操作系统内核创建和撤销。
  • 用户线程:不需要内核支持而在用户程序中实现的线程。

Python3 线程中常用的两个模块为:

  • _thread
  • threading(推荐使用)

thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用”thread” 模块。为了兼容性,Python3 将 thread 重命名为 “_thread”。

开始学习Python线程

Python中使用线程有两种方式:函数或者用类来包装线程对象。

函数式:调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下:

 _thread.start_new_thread ( function, args[, kwargs] ) 

参数说明:

  • function – 线程函数。
  • args – 传递给线程函数的参数,他必须是个tuple类型。
  • kwargs – 可选参数。

实例:


#!/usr/bin/python3
import _thread
import time 
# 为线程定义一个函数 def print_time( threadName, delay):
    count = 0
    while count <5:
      time.sleep(delay)
       count += 1
       
print ("%s: %s" % ( threadName, time.ctime(time.time()) )) 
# 创建两个线程 try:
    _thread.start_new_thread( print_time, ("Thread-1", 2, ) )
    _thread.start_new_thread( print_time, ("Thread-2", 4, ) ) except:
    
print ("Error: 无法启动线程")  while 1:
    pass 

执行以上程序输出结果如下:

 Thread-1: Wed Apr  6 11:36:31 2016 Thread-1: Wed Apr  6 11:36:33 2016 Thread-2: Wed Apr  6 11:36:33 2016 Thread-1: Wed Apr  6 11:36:35 2016 Thread-1: Wed Apr  6 11:36:37 2016 Thread-2: Wed Apr  6 11:36:37 2016 Thread-1: Wed Apr  6 11:36:39 2016 Thread-2: Wed Apr  6 11:36:41 2016 Thread-2: Wed Apr  6 11:36:45 2016 Thread-2: Wed Apr  6 11:36:49 2016 

执行以上程后可以按下 ctrl-c to 退出。


线程模块

Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。

_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。

threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。

  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

使用 threading 模块创建线程

我们可以通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:


#!/usr/bin/python3
import threading
import time  exitFlag = 0
  class myThread (threading.Thread):
   
  def __init__(self, threadID, name, counter):
 
   threading.Thread.__init__(self)
 
   self.threadID = threadID
 
   self.name = name
 
   self.counter = counter
   
  def run(self):
 
   
print ("开始线程:" + self.name)
 
   print_time(self.name, self.counter, 5)
 
   
print ("退出线程:" + self.name)
  def print_time(threadName, delay, counter):
     while counter:
 
   if exitFlag:
 
   threadName.exit()
 
  time.sleep(delay)
 
   
print ("%s: %s" % (threadName, time.ctime(time.time())))
 
   counter -= 1 
# 创建新线程 thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) 
# 开启新线程 thread1.start() thread2.start() thread1.join() thread2.join() 
print ("退出主线程") 

以上程序执行结果如下;

 开始线程:Thread-1 开始线程:Thread-2 Thread-1: Wed Apr  6 11:46:46 2016 Thread-1: Wed Apr  6 11:46:47 2016 Thread-2: Wed Apr  6 11:46:47 2016 Thread-1: Wed Apr  6 11:46:48 2016 Thread-1: Wed Apr  6 11:46:49 2016 Thread-2: Wed Apr  6 11:46:49 2016 Thread-1: Wed Apr  6 11:46:50 2016 退出线程:Thread-1 Thread-2: Wed Apr  6 11:46:51 2016 Thread-2: Wed Apr  6 11:46:53 2016 Thread-2: Wed Apr  6 11:46:55 2016 退出线程:Thread-2 退出主线程 

线程同步

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是0,线程”set”从后向前把所有元素改成1,而线程”print”负责从前往后读取列表并打印。

那么,可能线程”set”开始改的时候,线程”print”便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如”set”要访问共享数据时,必须先获得锁定;如果已经有别的线程比如”print”获得锁定了,那么就让线程”set”暂停,也就是同步阻塞;等到线程”print”访问完毕,释放锁以后,再让线程”set”继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

实例:


#!/usr/bin/python3
import threading
import time
  class myThread (threading.Thread):
   
  def __init__(self, threadID, name, counter):
 
   threading.Thread.__init__(self)
 
   self.threadID = threadID
 
   self.name = name
 
   self.counter = counter
   
  def run(self):
 
   
print ("开启线程: " + self.name)
 
  
# 获取锁,用于线程同步
 
   threadLock.acquire()
 
   print_time(self.name, self.counter, 3)
 
  
# 释放锁,开启下一个线程
 
   threadLock.release()
  def print_time(threadName, delay, counter):
     while counter:
 
  time.sleep(delay)
 
   
print ("%s: %s" % (threadName, time.ctime(time.time())))
 
   counter -= 1  threadLock = threading.Lock() threads = [] 
# 创建新线程 thread1 = myThread(1, "Thread-1", 1) thread2 = myThread(2, "Thread-2", 2) 
# 开启新线程 thread1.start() thread2.start() 
# 添加线程到线程列表 threads.append(thread1) threads.append(thread2) 
# 等待所有线程完成 for t in threads:
     t.join() 
print ("退出主线程") 

执行以上程序,输出结果为:

 开启线程: Thread-1 开启线程: Thread-2 Thread-1: Wed Apr  6 11:52:57 2016 Thread-1: Wed Apr  6 11:52:58 2016 Thread-1: Wed Apr  6 11:52:59 2016 Thread-2: Wed Apr  6 11:53:01 2016 Thread-2: Wed Apr  6 11:53:03 2016 Thread-2: Wed Apr  6 11:53:05 2016 退出主线程 

线程优先级队列( Queue)

Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列 PriorityQueue。

这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。

Queue 模块中的常用方法:

  • Queue.qsize() 返回队列的大小
  • Queue.empty() 如果队列为空,返回True,反之False
  • Queue.full() 如果队列满了,返回True,反之False
  • Queue.full 与 maxsize 大小对应
  • Queue.get([block[, timeout]])获取队列,timeout等待时间
  • Queue.get_nowait() 相当Queue.get(False)
  • Queue.put(item) 写入队列,timeout等待时间
  • Queue.put_nowait(item) 相当Queue.put(item, False)
  • Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
  • Queue.join() 实际上意味着等到队列为空,再执行别的操作

实例:


#!/usr/bin/python3
import queue
import threading
import time  exitFlag = 0
  class myThread (threading.Thread):
   
  def __init__(self, threadID, name, q):
 
   threading.Thread.__init__(self)
 
   self.threadID = threadID
 
   self.name = name
 
   self.q = q
   
  def run(self):
 
   
print ("开启线程:" + self.name)
 
   process_data(self.name, self.q)
 
   
print ("退出线程:" + self.name)
  def process_data(threadName, q):
     while not exitFlag:
 
   queueLock.acquire()
 
   if not workQueue.empty():
 
   data = q.get()
 
   queueLock.release()
 
   
print ("%s processing %s" % (threadName, data))
 
   else:
 
   queueLock.release()
 
  time.sleep(1)  threadList = ["Thread-1", "Thread-2", "Thread-3"] nameList = ["One", "Two", "Three", "Four", "Five"] queueLock = threading.Lock() workQueue = queue.Queue(10) threads = [] threadID = 1 
# 创建新线程 for tName in threadList:
     thread = myThread(threadID, tName, workQueue)
     thread.start()
     threads.append(thread)
     threadID += 1 
# 填充队列 queueLock.acquire() for word in nameList:
     workQueue.put(word) queueLock.release() 
# 等待队列清空 while not workQueue.empty():
     pass 
# 通知线程是时候退出 exitFlag = 1 
# 等待所有线程完成 for t in threads:
     t.join() 
print ("退出主线程") 

以上程序执行结果:

 开启线程:Thread-1 开启线程:Thread-2 开启线程:Thread-3 Thread-3 processing One Thread-1 processing Two Thread-2 processing Three Thread-3 processing Four Thread-1 processing Five 退出线程:Thread-3 退出线程:Thread-2 退出线程:Thread-1 退出主线程 

Python3 SMTP发送邮件

Python3 SMTP发送邮件

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。

python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装。

Python创建 SMTP 对象语法如下:

import smtplib  smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] ) 

参数说明:

  • host: SMTP 服务器主机。 你可以指定主机的ip地址或者域名如:w3cschool.cn,这个是可选参数。
  • port: 如果你提供了 host 参数, 你需要指定 SMTP 服务使用的端口号,一般情况下SMTP端口号为25。
  • local_hostname: 如果SMTP在你的本机上,你只需要指定服务器地址为 localhost 即可。

Python SMTP对象使用sendmail方法发送邮件,语法如下:

SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options] 

参数说明:

  • from_addr: 邮件发送者地址。
  • to_addrs: 字符串列表,邮件发送地址。
  • msg: 发送消息

这里要注意一下第三个参数,msg是字符串,表示邮件。我们知道邮件一般由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意msg的格式。这个格式就是smtp协议中定义的格式。

实例

以下是一个使用Python发送邮件简单的实例:

#!/usr/bin/python3
import smtplib from email.mime.text
import MIMEText from email.header
import Header  sender = 'from@w3cschool.cn' receivers = ['429240967@qq.com'] 
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱 
# 三个参数:第一个为文本内容,第二个 plain 设置文本格式,第三个 utf-8 设置编码 message = MIMEText('Python 邮件发送测试...', 'plain', 'utf-8') message['From'] = Header("W3Cschool教程", 'utf-8') message['To'] =  Header("测试", 'utf-8')  subject = 'Python SMTP 邮件测试' message['Subject'] = Header(subject, 'utf-8')   try:
     smtpObj = smtplib.SMTP('localhost')
     smtpObj.sendmail(sender, receivers, message.as_string())
     
print ("邮件发送成功") except smtplib.SMTPException:
     
print ("Error: 无法发送邮件") 

我们使用三个引号来设置邮件信息,标准邮件需要三个头部信息: From, To, 和 Subject ,每个信息直接使用空行分割。

我们通过实例化 smtplib 模块的 SMTP 对象 smtpObj 来连接到 SMTP 访问,并使用 sendmail 方法来发送信息。

执行以上程序,如果你本机安装sendmail,就会输出:

$ python3 test.py
  邮件发送成功 

查看我们的收件箱(一般在垃圾箱),就可以查看到邮件信息:

Python3 SMTP发送邮件

如果我们本机没有 sendmail 访问,也可以使用其他服务商的 SMTP 访问(QQ、网易、Google等)。

#!/usr/bin/python3
import smtplib from email.mime.text
import MIMEText from email.header
import Header 
# 第三方 SMTP 服务 mail_host="smtp.XXX.com" 
#设置服务器 mail_user="XXXX"
   
#用户名 mail_pass="XXXXXX"  
#口令
    sender = 'from@w3cschool.cn' receivers = ['429240967@qq.com'] 
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱  message = MIMEText('Python 邮件发送测试...', 'plain', 'utf-8') message['From'] = Header("W3Cschool教程", 'utf-8') message['To'] =  Header("测试", 'utf-8')  subject = 'Python SMTP 邮件测试' message['Subject'] = Header(subject, 'utf-8')   try:
     smtpObj = smtplib.SMTP()
      smtpObj.connect(mail_host, 25)
   
# 25 为 SMTP 端口号
     smtpObj.login(mail_user,mail_pass)
     smtpObj.sendmail(sender, receivers, message.as_string())
     
print ("邮件发送成功") except smtplib.SMTPException:
     
print ("Error: 无法发送邮件") 

使用Python发送HTML格式的邮件

Python发送HTML格式的邮件与发送纯文本消息的邮件不同之处就是将MIMEText中_subtype设置为html。具体代码如下:

#!/usr/bin/python3
import smtplib from email.mime.text
import MIMEText from email.header
import Header  sender = 'from@w3cschool.cn' receivers = ['429240967@qq.com'] 
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱  mail_msg = """ <p>Python 邮件发送测试...</p>
<p>
<a href="http://www.soxitoday.com">这是一个链接</a>
</p>""" message = MIMEText(mail_msg, 'html', 'utf-8') message['From'] = Header("W3Cschool教程", 'utf-8') message['To'] =  Header("测试", 'utf-8')  subject = 'Python SMTP 邮件测试' message['Subject'] = Header(subject, 'utf-8')   try:
     smtpObj = smtplib.SMTP('localhost')
     smtpObj.sendmail(sender, receivers, message.as_string())
     
print ("邮件发送成功") except smtplib.SMTPException:
     
print ("Error: 无法发送邮件") 

执行以上程序,如果你本机安装sendmail,就会输出:

$ python3 test.py
  邮件发送成功 

查看我们的收件箱(一般在垃圾箱),就可以查看到邮件信息:

Python3 SMTP发送邮件


Python 发送带附件的邮件

发送带附件的邮件,首先要创建MIMEMultipart()实例,然后构造附件,如果有多个附件,可依次构造,最后利用smtplib.smtp发送。

#!/usr/bin/python3
import smtplib from email.mime.text
import MIMEText from email.mime.multipart
import MIMEMultipart from email.header
import Header  sender = 'from@w3cschool.cn' receivers = ['429240967@qq.com'] 
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱 
#创建一个带附件的实例 message = MIMEMultipart() message['From'] = Header("W3Cschool教程", 'utf-8') message['To'] =  Header("测试", 'utf-8') subject = 'Python SMTP 邮件测试' message['Subject'] = Header(subject, 'utf-8') 
#邮件正文内容 message.attach(MIMEText('这是W3Cschool教程Python 邮件发送测试……', 'plain', 'utf-8')) 
# 构造附件1,传送当前目录下的 test.txt 文件 att1 = MIMEText(open('test.txt', 'rb').read(), 'base64', 'utf-8') att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字 att1["Content-Disposition"] = 'attachment;


filename="test.txt"' message.attach(att1) 
# 构造附件2,传送当前目录下的 w3cschool.txt 文件 att2 = MIMEText(open('w3cschool.txt', 'rb').read(), 'base64', 'utf-8') att2["Content-Type"] = 'application/octet-stream' att2["Content-Disposition"] = 'attachment;


filename="w3cschool.txt"' message.attach(att2)  try:
     smtpObj = smtplib.SMTP('localhost')
     smtpObj.sendmail(sender, receivers, message.as_string())
     
print ("邮件发送成功") except smtplib.SMTPException:
     
print ("Error: 无法发送邮件") 
$ python3 test.py
  邮件发送成功 

查看我们的收件箱(一般在垃圾箱),就可以查看到邮件信息:

Python3 SMTP发送邮件


在 HTML 文本中添加图片

邮件的 HTML 文本中一般邮件服务商添加外链是无效的,正确添加突破的实例如下所示:

#!/usr/bin/python3
import smtplib from email.mime.image
import MIMEImage from email.mime.multipart
import MIMEMultipart from email.mime.text
import MIMEText from email.header
import Header  sender = 'from@w3cschool.cn' receivers = ['429240967@qq.com'] 
# 接收邮件,可设置为你的QQ邮箱或者其他邮箱  msgRoot = MIMEMultipart('related') msgRoot['From'] = Header("W3Cschool教程", 'utf-8') msgRoot['To'] =  Header("测试", 'utf-8') subject = 'Python SMTP 邮件测试' msgRoot['Subject'] = Header(subject, 'utf-8')  msgAlternative = MIMEMultipart('alternative') msgRoot.attach(msgAlternative)   mail_msg = """ <p>Python 邮件发送测试...</p>
<p>
<a href="http://www.soxitoday.com">W3Cschool教程链接</a>
</p>
<p>图片演示:</p>
<p>
<img src="cid:image1">
</p>""" msgAlternative.attach(MIMEText(mail_msg, 'html', 'utf-8')) 
# 指定图片为当前目录 fp = open('test.png', 'rb') msgImage = MIMEImage(fp.read()) fp.close() 
# 定义图片 ID,在 HTML 文本中引用 msgImage.add_header('Content-ID', '<image1>') msgRoot.attach(msgImage)  try:
     smtpObj = smtplib.SMTP('localhost')
     smtpObj.sendmail(sender, receivers, msgRoot.as_string())
     
print ("邮件发送成功") except smtplib.SMTPException:
     
print ("Error: 无法发送邮件") 
$ python3 test.py
  邮件发送成功 

查看我们的收件箱(如果在垃圾箱可能需要移动到收件箱才可正常显示),就可以查看到邮件信息:

Python3 SMTP发送邮件

更多内容请参阅:https://docs.py
thon.org/3/library/email-examples.html。

Python3 网络编程

Python3 网络编程

Python 提供了两个级别访问的网络服务。:

  • 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
  • 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。

什么是 Socket?

Socket又称”套接字”,应用程序通常通过”套接字”向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。


socket()函数

Python 中,我们用 socket()函数来创建套接字,语法格式如下:

socket.socket([family[, type[, proto]]]) 

参数

  • family: 套接字家族可以使AF_UNIX或者AF_INET
  • type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAMSOCK_DGRAM
  • protocol: 一般不填默认为0.

Socket 对象(内建)方法

函数 描述
服务器端套接字
s.bind() 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。
s.listen() 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。
s.accept() 被动接受TCP客户端连接,(阻塞式)等待连接的到来
客户端套接字
s.connect() 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。
s.send() 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。
s.sendall() 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
s.recvform() 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
s.sendto() 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。
s.close() 关闭套接字
s.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
s.getsockname() 返回套接字自己的地址。通常是一个元组(ipaddr,port)
s.setsockopt(level,optname,value) 设置给定套接字选项的值。
s.getsockopt(level,optname[.buflen]) 返回套接字选项的值。
s.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())
s.gettimeout() 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。
s.fileno() 返回套接字的文件描述符。
s.setblocking(flag) 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。
s.makefile() 创建一个与该套接字相关连的文件

简单实例

服务端

我们使用 socket 模块的 socket 函数来创建一个 socket 对象。socket 对象可以通过调用其他函数来设置一个 socket 服务。

现在我们可以通过调用 bind(hostname, port) 函数来指定服务的 port(端口)

接着,我们调用 socket 对象的 accept 方法。该方法等待客户端的连接,并返回 connection 对象,表示已连接到客户端。

完整代码如下:

#!/usr/bin/python3
# 文件名:server.py
 
# 导入 socket、sys 模块
import socket
import sys 
# 创建 socket 对象 serversocket = socket.socket(
 
   socket.AF_INET, socket.SOCK_STREAM)  
# 获取本地主机名 host = socket.gethostname()  port = 9999 
# 绑定端口 serversocket.bind((host, port)) 
# 设置最大连接数,超过后排队 serversocket.listen(5)  while True:
    
# 建立客户端连接
     clientsocket,addr = serversocket.accept()
 

print("连接地址: %s" % str(addr))
 
    msg='欢迎访问W3Cschool教程!'+ "rn"
     clientsocket.send(msg.encode('utf-8'))
     clientsocket.close() 

客户端

接下来我们写一个简单的客户端实例连接到以上创建的服务。端口号为 12345。

socket.connect(hosname, port ) 方法打开一个 TCP 连接到主机为 hostname 端口为 port 的服务商。连接后我们就可以从服务端后期数据,记住,操作完成后需要关闭连接。

完整代码如下:

#!/usr/bin/python3
# 文件名:client.py
 
# 导入 socket、sys 模块
import socket
import sys 
# 创建 socket 对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
# 获取本地主机名 host = socket.gethostname()  
# 设置端口好 port = 9999 
# 连接服务,指定主机和端口 s.connect((host, port)) 
# 接收小于 1024 字节的数据 msg = s.recv(1024)  s.close()  
print (msg.decode('utf-8')) 

现在我们打开连个终端,第一个终端执行 server.py
文件:

$ python3 server.py

第二个终端执行 client.py
文件:

$ python3 client.py
  欢迎访问W3Cschool教程!  

这是我们再打开第一个终端,就会看到有以下信息输出:

连接地址: ('192.168.0.118', 33397) 

Python Internet 模块

以下列出了 Python 网络编程的一些重要模块:

协议 功能用处 端口号 Python 模块
HTTP 网页访问 80 httplib, urllib, xmlrpclib
NNTP 阅读和张贴新闻文章,俗称为”帖子” 119 nntplib
FTP 文件传输 20 ftplib, urllib
SMTP 发送邮件 25 smtplib
POP3 接收邮件 110 poplib
IMAP4 获取邮件 143 imaplib
Telnet 命令行 23 telnetlib
Gopher 信息查找 70 gopherlib, urllib

更多内容可以参阅官网的 Python Socket Library and Modules。

Python3 MySQL 数据库连接

Python3 MySQL 数据库连接

本文我们为大家介绍 Python3 使用 PyMySQL 连接数据库,并实现简单的增删改查。

什么是 PyMySQL?

PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。

PyMySQL 遵循 Python 数据库 API v2.0 规范,并包含了 pure-Python MySQL 客户端库。


PyMySQL 安装

在使用 PyMySQL 之前,我们需要确保 PyMySQL 已安装。

PyMySQL 下载地址:https://github.com/PyMySQL/PyMySQL。

如果还未安装,我们可以使用以下命令安装最新版的 PyMySQL:

$ pip install PyMySQL 

如果你的系统不支持 pip 命令,可以使用以下方式安装:

1、使用 git 命令下载安装包安装(你也可以手动下载):

$ git clone https://github.com/PyMySQL/PyMySQL $ cd PyMySQL/ $ python3 setup.py
 install 

2、如果需要制定版本号,可以使用 curl 命令来安装:

$
# X.X 为 PyMySQL 的版本号 $ curl -L https://github.com/PyMySQL/PyMySQL/tarball/pymysql-X.X | tar xz $ cd PyMySQL* $ python3 setup.py
 install $
# 现在你可以删除 PyMySQL* 目录 

注意:请确保您有root权限来安装上述模块。

|

安装的过程中可能会出现"ImportError: No module named setuptools"的错误提示,意思是你没有安装setuptools,你可以访问https://pypi.py thon.org/pypi/setuptools 找到各个系统的安装方法。

Linux 系统安装实例:

$ wget https://bootstrap.py
pa.io/ez_setup.py
 $ python3 ez_setup.py
 

|


数据库连接

连接数据库前,请先确认以下事项:

  • 您已经创建了数据库 TESTDB.
  • 在TESTDB数据库中您已经创建了表 EMPLOYEE
  • EMPLOYEE表字段为 FIRST_NAME, LAST_NAME, AGE, SEX 和 INCOME。
  • 连接数据库TESTDB使用的用户名为 “testuser” ,密码为 “test123”,你可以可以自己设定或者直接使用root用户名及其密码,Mysql数据库用户授权请使用Grant命令。
  • 在你的机子上已经安装了 Python MySQLdb 模块。
  • 如果您对sql语句不熟悉,可以访问我们的 SQL教程

实例:

以下实例链接Mysql的TESTDB数据库:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用 cursor() 方法创建一个游标对象 cursor cursor = db.cursor() 
# 使用 execute()  方法执行 SQL 查询  cursor.execute("SELECT VERSION()") 
# 使用 fetchone() 方法获取单条数据. data = cursor.fetchone()  
print ("Database version : %s " % data) 
# 关闭数据库连接 db.close() 

执行以上脚本输出结果如下:

Database version : 5.5.20-log 

创建数据库表

如果数据库连接存在我们可以使用execute()方法来为数据库创建表,如下所示创建表EMPLOYEE:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用 cursor() 方法创建一个游标对象 cursor cursor = db.cursor() 
# 使用 execute() 方法执行 SQL,如果表存在则删除 cursor.execute("DROP TABLE IF EXISTS EMPLOYEE") 
# 使用预处理语句创建表 sql = """CREATE TABLE EMPLOYEE (
 
    FIRST_NAME  CHAR(20) NOT NULL,
 
    LAST_NAME  CHAR(20),
 
    AGE INT,
 
  SEX CHAR(1),
 
    INCOME FLOAT )"""  cursor.execute(sql) 
# 关闭数据库连接 db.close() 

数据库插入操作

以下实例使用执行 SQL INSERT 语句向表 EMPLOYEE 插入记录:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用cursor()方法获取操作游标  cursor = db.cursor() 
# SQL 插入语句 sql = """INSERT INTO EMPLOYEE(FIRST_NAME,
 
    LAST_NAME, AGE, SEX, INCOME)
 
    VALUES ('Mac', 'Mohan', 20, 'M', 2000)""" try:
   
# 执行sql语句
    cursor.execute(sql)
   
# 提交到数据库执行
    db.commit() except:
   
# 如果发生错误则回滚
    db.rollback() 
# 关闭数据库连接 db.close() 

以上例子也可以写成如下形式:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用cursor()方法获取操作游标  cursor = db.cursor() 
# SQL 插入语句 sql = "INSERT INTO EMPLOYEE(FIRST_NAME,
 
   LAST_NAME, AGE, SEX, INCOME)
 
   VALUES ('%s', '%s', '%d', '%c', '%d' )" %
 
   ('Mac', 'Mohan', 20, 'M', 2000) try:
   
# 执行sql语句
    cursor.execute(sql)
   
# 执行sql语句
    db.commit() except:
   
# 发生错误时回滚
    db.rollback() 
# 关闭数据库连接 db.close() 

以下代码使用变量向SQL语句中传递参数:

.................................. user_id = "test123" password = "password"  con.execute('insert into Login values("%s", "%s")' %
 
     (user_id, password)) .................................. 

数据库查询操作

Python查询Mysql使用 fetchone() 方法获取单条数据, 使用fetchall() 方法获取多条数据。

  • fetchone(): 该方法获取下一个查询结果集。结果集是一个对象
  • fetchall(): 接收全部的返回结果行.
  • rowcount: 这是一个只读属性,并返回执行execute()方法后影响的行数。

实例:

查询EMPLOYEE表中salary(工资)字段大于1000的所有数据:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用cursor()方法获取操作游标  cursor = db.cursor() 
# SQL 查询语句 sql = "SELECT * FROM EMPLOYEE
 
   WHERE INCOME >'%d'" % (1000) try:
   
# 执行SQL语句
    cursor.execute(sql)
   
# 获取所有记录列表
    results = cursor.fetchall()
    for row in results:
       fname = row[0]
       lname = row[1]
       age = row[2]
       sex = row[3]
       income = row[4]
 
 
# 打印结果
       
print ("fname=%s,lname=%s,age=%d,sex=%s,income=%d" %
 
     (fname, lname, age, sex, income )) except:
    
print ("Error: unable to fecth data") 
# 关闭数据库连接 db.close() 

以上脚本执行结果如下:

fname=Mac, lname=Mohan, age=20, sex=M, income=2000 

数据库更新操作

更新操作用于更新数据表的的数据,以下实例将 TESTDB表中的 SEX 字段全部修改为 ‘M’,AGE 字段递增1:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用cursor()方法获取操作游标  cursor = db.cursor() 
# SQL 更新语句 sql = "UPDATE EMPLOYEE SET AGE = AGE + 1
 


     WHERE SEX = '%c'" % ('M') try:
   
# 执行SQL语句
    cursor.execute(sql)
   
# 提交到数据库执行
    db.commit() except:
   
# 发生错误时回滚
    db.rollback() 
# 关闭数据库连接 db.close() 

删除操作

删除操作用于删除数据表中的数据,以下实例演示了删除数据表 EMPLOYEE 中 AGE 大于 20 的所有数据:

#!/usr/bin/python3
import pymysql 
# 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) 
# 使用cursor()方法获取操作游标  cursor = db.cursor() 
# SQL 删除语句 sql = "DELETE FROM EMPLOYEE WHERE AGE >'%d'" % (20) try:
   
# 执行SQL语句
    cursor.execute(sql)
   
# 提交修改
    db.commit() except:
   
# 发生错误时回滚
    db.rollback() 
# 关闭连接 db.close() 

执行事务

事务机制可以确保数据一致性。

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

  • 原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
  • 一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
  • 隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

Python DB API 2.0 的事务提供了两个方法 commit 或 rollback。

实例


# SQL删除记录语句 sql = "DELETE FROM EMPLOYEE WHERE AGE >'%d'" % (20) try:
   
# 执行SQL语句
    cursor.execute(sql)
   
# 向数据库提交
    db.commit() except:
   
# 发生错误时回滚
    db.rollback() 

对于支持事务的数据库, 在Python数据库编程中,当游标建立之时,就自动开始了一个隐形的数据库事务。

commit()方法游标的所有更新操作,rollback()方法回滚当前游标的所有操作。每一个方法都开始了一个新的事务。


错误处理

DB API中定义了一些数据库操作的错误及异常,下表列出了这些错误和异常:

异常 描述
Warning 当有严重警告时触发,例如插入数据是被截断等等。必须是 StandardError 的子类。
Error 警告以外所有其他错误类。必须是 StandardError 的子类。
InterfaceError 当有数据库接口模块本身的错误(而不是数据库的错误)发生时触发。 必须是Error的子类。
DatabaseError 和数据库有关的错误发生时触发。 必须是Error的子类。
DataError 当有数据处理时的错误发生时触发,例如:除零错误,数据超范围等等。 必须是DatabaseError的子类。
OperationalError 指非用户控制的,而是操作数据库时发生的错误。例如:连接意外断开、 数据库名未找到、事务处理失败、内存分配错误等等操作数据库是发生的错误。 必须是DatabaseError的子类。
IntegrityError 完整性相关的错误,例如外键检查失败等。必须是DatabaseError子类。
InternalError 数据库的内部错误,例如游标(cursor)失效了、事务同步失败等等。 必须是DatabaseError子类。
ProgrammingError 程序错误,例如数据表(table)没找到或已存在、SQL语句语法错误、 参数数量错误等等。必须是DatabaseError的子类。
NotSupportedError 不支持错误,指使用了数据库不支持的函数或API等。例如在连接对象上 使用.rollback()函数,然而数据库并不支持事务或者事务已关闭。 必须是DatabaseError的子类。

Python3 CGI编程

Python CGI编程


什么是CGI

CGI 目前由NCSA维护,NCSA定义CGI如下:

CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户端HTML页面的接口。


网页浏览

为了更好的了解CGI是如何工作的,我们可以从在网页上点击一个链接或URL的流程:

  • 1、使用你的浏览器访问URL并连接到HTTP web 服务器。
  • 2、Web服务器接收到请求信息后会解析URL,并查找访问的文件在服务器上是否存在,如果存在返回文件的内容,否则返回错误信息。
  • 3、浏览器从服务器上接收信息,并显示接收的文件或者错误信息。

CGI程序可以是Python脚本,PERL脚本,SHELL脚本,C或者C++程序等。


CGI架构图

Python3 CGI编程


Web服务器支持及配置

在你进行CGI编程前,确保您的Web服务器支持CGI及已经配置了CGI的处理程序。

Apache 支持CGI 配置:

设置好CGI目录:

ScriptAlias /cgi-bin/ /var/www/cgi-bin/ 

所有的HTTP服务器执行CGI程序都保存在一个预先配置的目录。这个目录被称为CGI目录,并按照惯例,它被命名为/var/www/cgi-bin目录。

CGI文件的扩展名为.cgi,python也可以使用.py
扩展名。

默认情况下,Linux服务器配置运行的cgi-bin目录中为/var/www。

如果你想指定其他运行CGI脚本的目录,可以修改httpd.conf配置文件,如下所示:

<Directory "/var/www/cgi-bin">   AllowOverride None
    Options +ExecCGI
    Order allow,deny
    Allow from all </Directory>

在 AddHandler 中添加 .py
后缀,这样我们就可以访问 .py
结尾的 python 脚本文件:

AddHandler cgi-script .cgi .pl .py

第一个CGI程序

我们使用Python创建第一个CGI程序,文件名为hello.py
,文件位于/var/www/cgi-bin目录中,内容如下:

#!/usr/bin/python3
#coding=utf-8 
print ('<html>') 
print ('<head>') 
print ('<meta charset="utf-8">') 
print ('<title>Hello Word - 我的第一个 CGI 程序!</title>') 
print ('</head>') 
print ('<body>') 
print ('<h2>Hello Word! 我的第一CGI程序</h2>') 
print ('</body>') 
print ('</html>')

文件保存后修改 hello.py
,修改文件权限为 755:

chmod 755 hello.py
 

以上程序在浏览器访问显示结果如下:

Python3 CGI编程

这个的hello.py
脚本是一个简单的Python脚本,脚本第一行的输出内容”Content-type:text/html”发送到浏览器并告知浏览器显示的内容类型为”text/html”。

用 print 输出一个空行用于告诉服务器结束头部信息。


HTTP头部

hello.py
文件内容中的” Content-type:text/html”即为HTTP头部的一部分,它会发送给浏览器告诉浏览器文件的内容类型。

HTTP头部的格式如下:

HTTP 字段名: 字段内容 

例如:

Content-type: text/html

以下表格介绍了CGI程序中HTTP头部经常使用的信息:

描述
Content-type: 请求的与实体对应的MIME信息。例如: Content-type:text/html
Expires: Date 响应过期的日期和时间
Location: URL 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源
Last-modified: Date 请求资源的最后修改时间
Content-length: N 请求的内容长度
Set-Cookie: String 设置Http Cookie

CGI环境变量

所有的CGI程序都接收以下的环境变量,这些变量在CGI程序中发挥了重要的作用:

变量名 描述
CONTENT_TYPE 这个环境变量的值指示所传递来的信息的MIME类型。目前,环境变量CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示数据来自于HTML表单。
CONTENT_LENGTH 如果服务器与CGI程序信息的传递方式是POST,这个环境变量即使从标准输入STDIN中可以读到的有效数据的字节数。这个环境变量在读取所输入的数据时必须使用。
HTTP_COOKIE 客户机内的 COOKIE 内容。
HTTP_USER_AGENT 提供包含了版本数或其他专有数据的客户浏览器信息。
PATH_INFO 这个环境变量的值表示紧接在CGI程序名之后的其他路径信息。它常常作为CGI程序的参数出现。
QUERY_STRING 如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值即使所传递的信息。这个信息经跟在CGI程序名的后面,两者中间用一个问号’?’分隔。
REMOTE_ADDR 这个环境变量的值是发送请求的客户机的IP地址,例如上面的192.168.1.67。这个值总是存在的。而且它是Web客户机需要提供给Web服务器的唯一标识,可以在CGI程序中用它来区分不同的Web客户机。
REMOTE_HOST 这个环境变量的值包含发送CGI请求的客户机的主机名。如果不支持你想查询,则无需定义此环境变量。
REQUEST_METHOD 提供脚本被调用的方法。对于使用 HTTP/1.0 协议的脚本,仅 GET 和 POST 有意义。
SCRIPT_FILENAME CGI脚本的完整路径
SCRIPT_NAME CGI脚本的的名称
SERVER_NAME 这是你的 WEB 服务器的主机名、别名或IP地址。
SERVER_SOFTWARE 这个环境变量的值包含了调用CGI程序的HTTP服务器的名称和版本号。例如,上面的值为Apache/2.2.14(Unix)

以下是一个简单的CGI脚本输出CGI的环境变量:

#!/usr/bin/python3
#coding=utf-8
import os  
print ("Content-type: text/html") 
print () 
print ("<meta charset="utf-8">") 
print ("<b>环境变量</b>
<br>") 
print ("<ul>") for key in os.environ.keys():
     
print ("<li>
<span style='color:green'>%30s </span>: %s </li>" % (key,os.environ[key])) 
print ("</ul>") 

将以上点保存为 test.py
,并修改文件权限为 755,执行结果如下:

Python3 CGI编程


GET和POST方法

浏览器客户端通过两种方法向服务器传递信息,这两种方法就是 GET 方法和 POST 方法。

使用GET方法传输数据

GET方法发送编码后的用户信息到服务端,数据信息包含在请求页面的URL上,以”?”号分割, 如下所示:

http://www.test.com/cgi-bin/hello.py
?key1=value1&

key2=value2 

有关 GET 请求的其他一些注释:

  • GET 请求可被缓存
  • GET 请求保留在浏览器历史记录中
  • GET 请求可被收藏为书签
  • GET 请求不应在处理敏感数据时使用
  • GET 请求有长度限制
  • GET 请求只应当用于取回数据

简单的url实例:GET方法

以下是一个简单的URL,使用GET方法向hello_get.py
程序发送两个参数:

/cgi-bin/test.py
?name=W3Cschool教程&

url=http://www.soxitoday.com 

以下为hello_get.py
文件的代码:

#!/usr/bin/python3
#coding=utf-8 
# CGI处理模块
import cgi, cgitb  
# 创建 FieldStorage 的实例化 form = cgi.FieldStorage()  
# 获取数据 site_name = form.getvalue('name') site_url  = form.getvalue('url')  
print ("Content-type:text/html") 
print () 
print ("<html>") 
print ("<head>") 
print ("<meta charset="utf-8">") 
print ("<title>W3Cschool教程 CGI 测试实例</title>") 
print ("</head>") 
print ("<body>") 
print ("<h2>%s官网:%s</h2>" % (site_name, site_url)) 
print ("</body>") 
print ("</html>") 

文件保存后修改 hello_get.py
,修改文件权限为 755:

chmod 755 hello_get.py
 

浏览器请求输出结果:

Python3 CGI编程

简单的表单实例:GET方法

以下是一个通过HTML的表单使用GET方法向服务器发送两个数据,提交的服务器脚本同样是hello_get.py
文件,hello_get.html 代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/hello_get.py" method="get">站点名称: <input type="text" name="name"> <br /> 站点 URL: <input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>

默认情况下 cgi-bin 目录只能存放脚本文件,我们将 hello_get.html 存储在 test 目录下,修改文件权限为 755:

chmod 755 hello_get.html 

Gif 演示如下所示:

Python3 CGI编程

使用POST方法传递数据

使用POST方法向服务器传递数据是更安全可靠的,像一些敏感信息如用户密码等需要使用POST传输数据。

以下同样是hello_get.py
,它也可以处理浏览器提交的POST表单数据:

#!/usr/bin/python3
#coding=utf-8 
# CGI处理模块
import cgi, cgitb  
# 创建 FieldStorage 的实例化 form = cgi.FieldStorage()  
# 获取数据 site_name = form.getvalue('name') site_url  = form.getvalue('url')  
print ("Content-type:text/html") 
print () 
print ("<html>") 
print ("<head>") 
print ("<meta charset="utf-8">") 
print ("<title>W3Cschool教程 CGI 测试实例</title>") 
print ("</head>") 
print ("<body>") 
print ("<h2>%s官网:%s</h2>" % (site_name, site_url)) 
print ("</body>") 
print ("</html>") 

以下为表单通过POST方法(method=”post”)向服务器脚本 hello_get.py
提交数据:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/hello_get.py" method="post">站点名称: <input type="text" name="name"> <br /> 站点 URL: <input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>
</form>

Gif 演示如下所示:

Python3 CGI编程

通过CGI程序传递checkbox数据

checkbox用于提交一个或者多个选项数据,HTML代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/checkbox.py" method="POST" target="_blank">
<input type="checkbox" name="youj" value="on" />W3Cschool教程 <input type="checkbox" name="google" value="on" />Google <input type="submit" value="选择站点" />
</form>
</body>
</html>

以下为 checkbox.py
文件的代码:

#!/usr/bin/python3 
# 引入 CGI 处理模块
import cgi, cgitb  
# 创建 FieldStorage的实例  form = cgi.FieldStorage()  
# 接收字段数据 if form.getvalue('google'):
    google_flag = "是" else:
    google_flag = "否"  if form.getvalue('youj'):
    youj_flag = "是" else:
    youj_flag = "否"  
print ("Content-type:text/html") 
print () 
print ("<html>") 
print ("<head>") 
print ("<meta charset="utf-8">") 
print ("<title>W3Cschool教程 CGI 测试实例</title>") 
print ("</head>") 
print ("<body>") 
print ("<h2>W3Cschool教程是否选择了 : %s</h2>" % youj_flag) 
print ("<h2>Google 是否选择了 : %s</h2>" % google_flag) 
print ("</body>") 
print ("</html>") 

修改 checkbox.py
权限:

chmod 755 checkbox.py
 

浏览器访问 Gif 演示图:

Python3 CGI编程

通过CGI程序传递Radio数据

Radio 只向服务器传递一个数据,HTML代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/radiobutton.py" method="post" target="_blank">
<input type="radio" name="site" value="youj" />W3Cschool教程 <input type="radio" name="site" value="google" />Google <input type="submit" value="提交" />
</form>
</body>
</html>

radiobutton.py
脚本代码如下:

#!/usr/bin/python3 
# 引入 CGI 处理模块
import cgi, cgitb  
# 创建 FieldStorage的实例  form = cgi.FieldStorage()  
# 接收字段数据 if form.getvalue('site'):
    site = form.getvalue('site')
 else:
    site = "提交数据为空"  
print ("Content-type:text/html") 
print () 
print ("<html>") 
print ("<head>") 
print ("<meta charset="utf-8">") 
print ("<title>W3Cschool教程 CGI 测试实例</title>") 
print ("</head>") 
print ("<body>") 
print ("<h2>选中的网站是 %s</h2>" % site) 
print ("</body>") 
print ("</html>") 

修改 radiobutton.py
权限:

chmod 755 radiobutton.py
 

浏览器访问 Gif 演示图:

Python3 CGI编程

通过CGI程序传递 Textarea 数据

Textarea 向服务器传递多行数据,HTML代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/textarea.py" method="post" target="_blank">
<textarea name="textcontent" cols="40" rows="4">在这里输入内容... </textarea>
<input type="submit" value="提交" />
</form>
</body>
</html>

textarea.py
脚本代码如下:

#!/usr/bin/python3 
# 引入 CGI 处理模块
import cgi, cgitb  
# 创建 FieldStorage的实例  form = cgi.FieldStorage()  
# 接收字段数据 if form.getvalue('textcontent'):
    text_content = form.getvalue('textcontent')
 else:
    text_content = "没有内容"  
print ("Content-type:text/html") 
print () 
print ("<html>") 
print ("<head>") 
print ("<meta charset="utf-8">") 
print ("<title>W3Cschool教程 CGI 测试实例</title>") 
print ("</head>") 
print ("<body>") 
print ("<h2>输入的内容是:%s</h2>" % text_content) 
print ("</body>") 
print ("</html>") 

修改 textarea.py
权限:

chmod 755 textarea.py
 

浏览器访问 Gif 演示图:

Python3 CGI编程

通过CGI程序传递下拉数据。

HTML 下拉框代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/dropdown.py" method="post" target="_blank">
<select name="dropdown">
<option value="youj" selected>W3Cschool教程</option>
<option value="google">Google</option>
</select>
<input type="submit" value="提交"/>
</form>
</body>
</html>

dropdown.py
脚本代码如下所示:

#!/usr/bin/python3 
# 引入 CGI 处理模块
import cgi, cgitb  
# 创建 FieldStorage的实例  form = cgi.FieldStorage()  
# 接收字段数据 if form.getvalue('dropdown'):
    dropdown_value = form.getvalue('dropdown')
 else:
    dropdown_value = "没有内容"  
print ("Content-type:text/html") 
print () 
print ("<html>") 
print ("<head>") 
print ("<meta charset="utf-8">") 
print ("<title>W3Cschool教程 CGI 测试实例</title>") 
print ("</head>") 
print ("<body>") 
print ("<h2>选中的选项是:%s</h2>" % dropdown_value) 
print ("</body>") 
print ("</html>") 

修改 dropdown.py
权限:

chmod 755 dropdown.py
 

浏览器访问 Gif 演示图:

Python3 CGI编程


CGI中使用Cookie

在 http 协议一个很大的缺点就是不对用户身份的进行判断,这样给编程人员带来很大的不便,而 cookie 功能的出现弥补了这个不足。

cookie 就是在客户访问脚本的同时,通过客户的浏览器,在客户硬盘上写入纪录数据 ,当下次客户访问脚本时取回数据信息,从而达到身份判别的功能,cookie 常用在身份校验中。

 

cookie的语法

http cookie的发送是通过http头部来实现的,他早于文件的传递,头部set-cookie的语法如下:

Set-cookie:name=name;

expires=date;

path=path;

domain=domain;

secure  
  • name=name: 需要设置cookie的值(name不能使用”;

    “和”,“号),有多个name值时用 “;

    ” 分隔,例如:name1=name1;

    name2=name2;

    name3=name3

  • expires=date: cookie的有效期限,格式: expires=”Wdy,DD-Mon-YYYY HH:MM:SS”
  • path=path: 设置cookie支持的路径,如果path是一个路径,则cookie对这个目录下的所有文件及子目录生效,例如: path=”/cgi-bin/”,如果path是一个文件,则cookie指对这个文件生效,例如:path=”/cgi-bin/cookie.cgi”。
  • domain=domain: 对cookie生效的域名,例如:domain=”www.soxitoday.com”
  • secure: 如果给出此标志,表示cookie只能通过SSL协议的https服务器来传递。
  • cookie的接收是通过设置环境变量HTTP_COOKIE来实现的,CGI程序可以通过检索该变量获取cookie信息。

Cookie设置

Cookie的设置非常简单,cookie会在http头部单独发送。以下实例在cookie中设置了name 和 expires:

#!/usr/bin/python3
#  
print ('Content-Type: text/html') 
print ('Set-Cookie: name="W3Cschool教程";

expires=Wed, 28 Aug 2016 18:30:00 GMT') 
print () 
print (""" <html> 
<head> <meta charset="utf-8"> <title>W3Cschool教程(w3cschool.cn)</title> 
</head> <body>
<h1>Cookie set OK!</h1>    </body>
</html>""") 

将以上代码保存到 cookie_set.py
,并修改 cookie_set.py
权限:

chmod 755 cookie_set.py
 

以上实例使用了 Set-Cookie 头信息来设置Cookie信息,可选项中设置了Cookie的其他属性,如过期时间Expires,域名Domain,路径Path。这些信息设置在 “Content-type:text/html”之前。


检索Cookie信息

Cookie信息检索页非常简单,Cookie信息存储在CGI的环境变量HTTP_COOKIE中,存储格式如下:

key1=value1;

key2=value2;

key3=value3.... 

以下是一个简单的CGI检索cookie信息的程序:

#!/usr/bin/python3 
# 导入模块
import os
import Cookie  
print ("Content-type: text/html") 
print ()  
print (""" <html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<h1>读取cookie信息</h1>""")
  if 'HTTP_COOKIE' in os.environ:
     cookie_string=os.environ.get('HTTP_COOKIE')
     c=Cookie.SimpleCookie()
     c.load(cookie_string)
      try:
 
   data=c['name'].value
 
   
print ("cookie data: "+data+"<br>")
     except KeyError:
 
   
print ("cookie 没有设置或者已过去<br>") 
print (""" </body>
</html>""") 

将以上代码保存到 cookie_get.py
,并修改 cookie_get.py
权限:

chmod 755 cookie_get.py
 

以上 cookie 设置颜色 Gif 如下所示:

文件上传实例

HTML设置上传文件的表单需要设置 enctype 属性为 multipart/form-data,代码如下所示:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body> <
form enctype="multipart/form-data"
 

     action="/cgi-bin/save_file.py" method="post">
<p>选中文件: <input type="file" name="filename" />
</p>
<p>
<input type="submit" value="上传" />
</p>   </form>
</body>
</html>

save_file.py
脚本文件代码如下:

#!/usr/bin/python3
import cgi, os
import cgitb;

cgitb.enable()  form = cgi.FieldStorage() 
# 获取文件名 fileitem = form['filename'] 
# 检测文件是否上传 if fileitem.filename:
   
# 设置文件路径
     fn = os.path.basename(fileitem.filename)
    open('/tmp/' + fn, 'wb').write(fileitem.file.read())
     message = '文件 "' + fn + '" 上传成功'
     else:
    message = '文件没有上传'
     
print (""" Content-Type: text/htmln <html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<p>%s</p>
</body>
</html>""" % (message,)) 

将以上代码保存到 save_file.py
,并修改 save_file.py
权限:

chmod 755 save_file.py
 

以上 cookie 设置颜色 Gif 如下所示:

Python3 CGI编程

如果你使用的系统是Unix/Linux,你必须替换文件分隔符,在window下只需要使用open()语句即可:

fn = os.path.basename(fileitem.filename.replace("\", "/" )) 

文件下载对话框

我们先在当前目录下创建 foo.txt 文件,用于程序的下载。

文件下载通过设置HTTP头信息来实现,功能代码如下:

#!/usr/bin/python3 
# HTTP 头部 
print ("Content-Disposition: attachment;


filename="foo.txt"") 
print ()
# 打开文件 fo = open("foo.txt", "rb")  str = fo.read();


print (str) 
# 关闭文件 fo.close()