Python高级进阶-常用模块

Python 常用模块

[TOC]

Http

Python标准库中提供了:urllib等模块以供Http请求。

Requests模块,使用Requests可以轻而易举的完成浏览器可有的任何操作。

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
32
33
34
35
36
37
38
import requests
import json

ret = requests.get('https://github.com/timeline.json')

print(ret.url)
print(ret.text)

payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get("http://httpbin.org/get", params=payload)

print(ret.url)
print(ret.text)

payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)

print(ret.text)

url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}

ret = requests.post(url, data=json.dumps(payload), headers=headers)

print(ret.text)
print(ret.cookies

requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)

# 以上方法均是在此方法的基础上构建
requests.request(method, url, **kwargs)

XML处理

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

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

2.DOM(Document Object Model)
将XML数据在内存中解析成一个树,通过对树的操作来操作XML。

3.ElementTree(元素树)
ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少。

注:因DOM需要将XML数据映射到内存中的树,一是比较慢,二是比较耗内存,而SAX流式读取XML文件,比较快,占用内存少,但需要用户实现回调函数(handler)。

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
32
33
34
<?xml version="1.0" encoding="utf-8"?>
<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>

使用SAX解析xml

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

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

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

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

1、对大型文件进行处理;
2、只需要文件的部分内容,或者只需从文件中得到特定信息。
3、想建立自己的对象模型的时候。

在python中使用sax方式处理xml要先引入xml.sax中的parse函数,还有xml.sax.handler中的ContentHandler。

ContentHandler类方法介绍

  • characters(content)方法

    调用时机
    从行开始,遇到标签之前,存在字符,content的值为这些字符串。
    从一个标签,遇到下一个标签之前,存在字符,content的值为这些字符串。
    从一个标签,遇到行结束符之前,存在字符,content的值为这些字符串。

    标签可以是开始标签,也可以是结束标签。

  • startDocument()方法

文档启动的时候调用。

  • endDocument()方法

解析器到达文档结尾时调用。

  • startElement(name, attrs)方法

遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典。

  • endElement(name)方法

遇到XML结束标签时调用。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import xml.sax


class MovieHandler(xml.sax.ContentHandler):

def __init__(self):
super(self)
self.CurrentData = ""
self.type = ""
self.format = ""
self.year = ""
self.rating = ""
self.stars = ""
self.description = ""

# 元素开始事件处理
def startElement(self, tag, attributes):
self.CurrentData = tag
if tag == "movie":
print "*****Movie*****"
title = attributes["title"]
print "Title:", title

# 元素结束事件处理
def endElement(self, tag):
if self.CurrentData == "type":
print "Type:", self.type
elif self.CurrentData == "format":
print "Format:", self.format
elif self.CurrentData == "year":
print "Year:", self.year
elif self.CurrentData == "rating":
print "Rating:", self.rating
elif self.CurrentData == "stars":
print "Stars:", self.stars
elif self.CurrentData == "description":
print "Description:", self.description
self.CurrentData = ""

# 内容事件处理
def characters(self, content):
if self.CurrentData == "type":
self.type = content
elif self.CurrentData == "format":
self.format = content
elif self.CurrentData == "year":
self.year = content
elif self.CurrentData == "rating":
self.rating = content
elif self.CurrentData == "stars":
self.stars = content
elif self.CurrentData == "description":
self.description = content


if __name__ == '__main__':

# 创建一个 XMLReader
parser = xml.sax.make_parser()
# turn off namepsaces
parser.setFeature(xml.sax.handler.feature_namespaces, 0)

# 重写 ContextHandler
Handler = MovieHandler()
parser.setContentHandler(Handler)

parser.parse("movies.xml")
pass

xml.dom解析xml

DOM解析是将整个文件读入内存,因此可随机访问标签。

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
from xml.dom.minidom import parse
import xml.dom.minidom

# 使用minidom解析器打开 XML 文档
DOMTree = xml.dom.minidom.parse("movies.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
print "Root element : %s" % collection.getAttribute("shelf")

# 在集合中获取所有电影
movies = collection.getElementsByTagName("movie")

# 打印每部电影的详细信息
for movie in movies:
print "*****Movie*****"
if movie.hasAttribute("title"):
print "Title: %s" % movie.getAttribute("title")

type = movie.getElementsByTagName('type')[0]
print "Type: %s" % type.childNodes[0].data
format = movie.getElementsByTagName('format')[0]
print "Format: %s" % format.childNodes[0].data
rating = movie.getElementsByTagName('rating')[0]
print "Rating: %s" % rating.childNodes[0].data
description = movie.getElementsByTagName('description')[0]
print "Description: %s" % description.childNodes[0].data

ElementTree

对比其他 Python 处理 XML 的方案,xml.etree.ElementTree 模块(下文我们以 ET 来表示)相对来说比较简单,接口也较友好。
官方文档 里面对 ET 模块进行了较为详细的描述,总的来说,ET 模块可以归纳为三个部分:ElementTree类,Element类以及一些操作 XML 的函数。
XML 可以看成是一种树状结构,ET 使用ElementTree类来表示整个 XML 文档,使用Element类来表示 XML 的一个结点。对整 XML 文档的操作一般是对ElementTree对象进行,而对 XML 结点的操作一般是对Element对象进行。

example.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<data>
<country name="Liechtenstein">
<rank>1</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
</data>

解析文件

1
2
3
4
5
6
7
8
9
import xml.etree.ElementTree as ET

# 获取 XML 文档对象 ElementTree
tree = ET.parse('example.xml')
# 获取 XML 文档对象的根结点 Element
root = tree.getroot()
# 打印根结点的名称
print root.tag

解析字符窜

1
2
3
4
xml_str = ET.tostring(root)
print xml_str
root = ET.fromstring(xml_str)
print root.tag

构造 XML

1
2
3
4
5
6
7
8
9
10
11
12
13
a = ET.Element('a')
b = ET.SubElement(a, 'b')
b.text = 'leehao.me'
c = ET.SubElement(a, 'c')
c.attrib['greeting'] = 'hello'
d = ET.SubElement(a, 'd')
d.text = 'www.leehao.me'
xml_str = ET.tostring(a, encoding='UTF-8')
print xml_str

# 先构造一个 ElementTree 以便使用其 write 方法
tree = ET.ElementTree(a)
tree.write('a.xml', encoding='UTF-8')

查找与更新

Element类提供了Element.iter()方法来查找指定的结点。
Element.iter()会递归查找所有的子结点,以便查找到所有符合条件的结点。

1
2
3
4
5
6
7
# 获取 XML 文档对象 ElementTree
tree = ET.parse('example.xml')
# 获取 XML 文档对象的根结点 Element
root = tree.getroot()
# 递归查找所有的 neighbor 子结点
for neighbor in root.iter('neighbor'):
print neighbor.attrib
1
2
3
{'direction': 'E', 'name': 'Austria'}
{'direction': 'W', 'name': 'Switzerland'}
{'direction': 'N', 'name': 'Malaysia'}

使用Element.findall()或者Element.find()方法,则只会从结点的直接子结点中查找,并不会递归查找。

1
2
3
4
5
6

country = root.find('country')
rank = country.find('rank').text
name = country.get('name')
print name, rank

输出

1
Liechtenstein 1
1
2
3
4
for country in root.findall('country'):
rank = country.find('rank').text
name = country.get('name')
print name, rank

输出

1
2
Liechtenstein 1
Singapore 4

更新结点

如果需要更新结点的文本,可以通过直接修改Element.text来实现。
如果需要更新结点的属性,可以通过直接修改Element.attrib来实现或 (Element.set() )。
添加节点孩子(例如 Element.append()).
删除节点孩子(例如 Element.append()).

对结点进行更新后,可以使用ElementTree.write()方法将更新后的 XML 文档写入文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 获取 XML 文档对象 ElementTree
tree = ET.parse('example.xml')
# 获取 XML 文档对象的根结点 Element
root = tree.getroot()
for rank in root.iter('rank'):
new_rank = int(rank.text) + 1
rank.text = str(new_rank) ## 更新节点值
rank.attrib['updated'] = 'yes' ## 添加或更新节点属性值
## rank.set('updated', 'yes')
root.remove(country) ## 删除节点

tree.write('output.xml', encoding='UTF-8')

for country in root.findall('country'):
rank = country.find('rank')
name = country.get('name')
if int(rank.text) >= 4:
country.remove(rank) ## 删除节点
else:
element = Element("addednode", {})
element.text = 'content'
country.append(element) ## 增加节点
pass
print name, rank

新生成的output.xml文件以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version='1.0' encoding='UTF-8'?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
</data>

对比example.xml文件,可以看到output.xml文件已更新。

参考: https://blog.csdn.net/lihao21/article/details/72891932

argparse

argparse 是 Python标准库中用来解析命令行参数和选项的模块,其是为替代已经过时的 optparse 模块而生的,该模块在 Python2.7 中被引入。argparse模块的作用是用于解析命令行参数。

  • 创建 ArgumentParser() 对象
  • 调用 add_argument() 方法添加参数
  • 使用 parse_args() 解析添加的参数

创建解析器

使用 argparse 解析命令行参数时,首先需要创建一个解析器,创建方式如下所示:

1
2
import argparse
parser = argparse.ArgumentParser()

argparse_usage.py

1
2
3
4
5
6
7
8
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('integer', type=int, help='display an integer')
args = parser.parse_args()

print args.integer

1
2
$ python argparse_usage.py 10
10
  1. 定位参数
    上面的实例展示了定位参数的用法。
  2. 可选参数
    所谓可选参数,也就是命令行参数是可选的:参数名前加– 标识使用可选参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import argparse

parser = argparse.ArgumentParser()

parser.add_argument("--square", help="display a square of a given number", type=int)
parser.add_argument("--cubic", help="display a cubic of a given number", type=int)

args = parser.parse_args()

if args.square:
print args.square**2

if args.cubic:
print args.cubic**3
1
2
3
4
5
$ python argparse_usage.py --square 8
64

$ python argparse_usage.py --cubic 8
512

混合使用

定位参数和选项参数可以混合使用,看下面一个例子,给一个整数序列,输出它们的和或最大值(默认):

1
2
3
4
5
6
7
8
9
10
11
12
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')

args = parser.parse_args()

print args.accumulate(args.integers)
1
2
3
4
5
6
7
8
$ python argparse_usage.py
usage: argparse_usage.py [-h] [--sum] N [N ...]
argparse_usage.py: error: too few arguments

$ python argparse_usage.py 1 2 3 4
4
$ python argparse_usage.py 1 2 3 4 --sum
10

add_argument() 方法

add_argument() 方法定义如何解析命令行参数:

ArgumentParser.add_argument(name or flags…[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
每个参数解释如下:

  • name or flags - 选项字符串的名字或者列表,例如 foo 或者 -f, –foo。
  • action - 命令行遇到参数时的动作,默认值是 store。
  • store_const,表示赋值为const;
  • append,将遇到的值存储成列表,也就是如果参数重复则会保存多个值;
  • append_const,将参数规范中定义的一个值保存到一个列表;
  • count,存储遇到的次数;此外,也可以继承 argparse.Action 自定义参数解析;
  • nargs - 应该读取的命令行参数个数,可以是具体的数字,或者是?号,当不指定值时对于 Positional argument 使用 default,对于 Optional argument 使用 const;或者是 * 号,表示 0 或多个参数;或者是 + 号表示 1 或多个参数。
  • const - action 和 nargs 所需要的常量值。
  • default - 不指定参数时的默认值。
  • type - 命令行参数应该被转换成的类型。
  • choices - 参数可允许的值的一个容器。
  • required - 可选参数是否可以省略 (仅针对可选参数)。
  • help - 参数的帮助信息,当指定为 argparse.SUPPRESS 时表示不显示该参数的帮助信息.
  • metavar - 在 usage 说明中的参数名称,对于必选参数默认就是参数名称,对于可选参数默认是全大写的参数名称.
  • dest - 解析后的参数名称,默认情况下,对于可选参数选取最长的名称,中划线转换为下划线.:

time/datetime模块

时间有三种格式:第一种是时间戳、第二种是格式化时间、第三种就是时间元组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time,datetime  

time.sleep(1)#程序休息几秒
print(time.time())#获取当前时间戳
print(time.localtime(1497950139))#获取时间元组,其中1497950139是时间戳;默认是当前时区UTC+8
print(time.localtime())#时间戳不写的话,默认获取当前时间元组
print(time.gmtime(1498732057.6223967))#获取时间元组,默认是标准时区UTC
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime(1498732057.6223967)))
# #将时间元组1498732057.6223967转换成格式化时间 2017-06-29 10:27:37
print(time.strftime("%Y-%m-%d %H:%M:%S"))#时间元组不写的话,默认获取当前格式化时间
print(time.asctime())#将时间元组转换成格式化时间,括号里不写默认当前时间。比如输出:Fri Jul 14 14:36:57 2017
print(time.ctime(1498732057.6223967))#讲时间戳转换成格式化时间,括号里不写默认当前时间。比如输出:Thu Jun 29 18:27:37 2017
print(datetime.datetime.now())#将当前时间格式化输出 2017-06-29 18:35:24.570104
print(datetime.datetime.now()+datetime.timedelta(3))#3天后的时间
print(datetime.datetime.now()+datetime.timedelta(-3))#3天前的时间

os/sys模块

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import sys
print(sys.argv)#获取命令行参数list,第一个元素是程序本身路径,后面的元素是参数
print(sys.version)#获取Python解释程序的版本信息
print(sys.path)#返回模块的搜索路径,初始化使用PYTHONPATH环境变量的值
print(sys.platform)#返回操作系统平台名称
sys.stdout.write('please:')#向屏幕输出一句话,等价于:print('please:')
val=sys.stdin.readline()[:-1]#获取输入的
sys.exit(0)#退出程序,正常退出时exit(0)

import os,time
print(os.getcwd())#获取当前工作目录,绝对路径
os.chmod('\user\bin',7)#linux环境下,给文件/目录加权限
print(os.chdir(r'D:\learning\huhy'))
#更改当前目录,到指定目录中
print(os.makedirs("OS/huhy1/hat1"))#在父目录下递归创建文件夹
print(os.removedirs("OS/file"))#递归删除空目录,若不是空目录无法删除,会报错
print(os.mkdir('huat'))#创建文件夹,若文件夹已存在则会报错
os.rmdir(r"D:\learning\huhy\sample\huat")#删除文件夹
print(os.remove(r'D:\learning\huhy\sample\huat\sss.txt'))#删除文件,若文件找不到会报错
os.rename(r'huat\test.txt',r'huat\case.txt')#重命名文件的名称
print(os.stat(r'huat\case.txt'))#获取文件信息
print(os.name)#显示当前使用的平台
print(os.sep)#当前操作系统的路径分隔符
print(os.environ)#当前系统的环境变量
print(os.pathsep)#当前系统的环境变量中每个路径的分隔符,linux是‘,’,windows是‘;’
print(os.linesep)#当前操作系统的换行符
with open('huat\case.txt','w',encoding='utf-8') as fw:
fw.write('ddddd')
fw.write(os.linesep)
fw.write('taayy')
print(os.path.abspath(__file__))#获取当前文件的绝对路径

print(__file__)#这个也会获取到当前文件的路径,但是路径里面的斜杠不符合路径格式
print(os.path.split('huat\case.txt'))#分割文件和路径名称
print(os.path.dirname(r'\usr\local\bin'))#获取父目录
print(os.path.exists(r'\usr\local\bin\a.txt'))#判断文件目录/文件是否存在,存在就返回True,否则返回False
print(os.path.join(os.path.dirname(os.path.abspath(__file__)),'huat'))#拼接成一个路径
print(os.path.join(r'D:\learning\huhy\sample','huat'))#同上,拼接路径
print(os.listdir('.'))#列出当前目录下的所有文件
print(os.listdir('..'))#列出父目录下的所有文件
print(os.path.getatime(r'D:\learning\huhy\day\login.py'))
print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getatime(r'D:\learning\huhy\day\login.py'))))
#os.path.getatime输出最近访问时间戳
print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getmtime(r'D:\learning\huhy\day\login.py'))))
#os.path.getmtime输出最近修改时间戳
print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getctime(r'D:\learning\huhy\day\login.py'))))
#os.path.getctime输出文件创建时间戳
print(os.curdir)#当前目录
print(os.pardir)#父目录
print(os.path.basename(r'\usr\local\bin\a.txt'))#获取最后一级,如果是文件显示文件名,如果是目录显示目录名
print(os.path.isabs(r'D:\sample\huat\sss.txt'))#判断是否是绝对路径,是绝对路径返回True,否则返回False
print(os.path.isfile(r'D:\learning\huhy\sample\huat\case.txt'))#判断该绝对路径是否是文件
print(os.path.isdir(r'D:\learning\huhy\sample\huat'))#判断是否是路径