Python库非常多,为方便快速查询,将自己之前用到的库做个简单汇总记录,不定期持续更新。
shutil
shutil模块提供目录和文件的高级操作
复制操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import shutil
#将文件src复制到文件或目录dest,保留文件权限
shutil.copy(src, dest)
#在shutil.copy的基础上加上copystat(),即将文件的访问/修改时间等信息也复制
shutil.copy2(src, dest)
#复制文件src的内容(不包含元数据)到文件dest(不支持目录复制,dest中必须包含文件名)
shutil.copyfile(src, dest)
#将类文件对象src.log的内容复制到类文件对象dest.log
shutil.copyfileobj(open('src.log','r'), open('dest.log', 'w'))
#递归拷贝src。symlinks=True则软链接文件也会被复制
shutil.copytree(src, dest, symlinks=True, ignore=shutil.ignore_patterns('*.pyc', '*.swap'))移动&删除操作
1
2
3
4
5#递归方式移动文件或目录
shutil.move(src, dest)
#递归删除文件
shutil.rmtree(folder1, folder2)压缩文件
压缩文件。将目录”/usr/local/project”压缩到”/home/mogl/test.tar.gz”
压缩包支持类型:zip/tar/gztar/bztar1
shutil.make_archive("/home/mogl/test", 'gztar', root_dir="/usr/local/project")
glob
glob模块提供Unix Shell规则的文件匹配功能1
2
3
4
5
6
7
8
9import glob
glob.glob('*.png')
glob.glob('[0-9].*')
#返回迭代器
files = glob.iglob('*.log')
for each_file in files:
print each_file
shlex
shlex模块提供简单的Unix Shell命令参数词法分析功能,可结合subprocess使用。1
2
3
4import shlex
shlex.split("ls -lht /tmp")
#['ls', '-lht', '/tmp']
argparse
argparse是用于命令行参数解析的模块,功能非常强大,目前所用到的只是简单功能,直接上实例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import argparse
parser = argparse.ArgumentParser(description='descritption', epilog="author:mogl")
parser.add_argument('-d', '--directory', action='store_true', help='Only search directory')
parser.add_argument('-i', '--ignore-case', action='store_true', help='Ignore case search')
parser.add_argument('-S', '--srcport', help='sorce port', type=int, required=True)
parser.add_argument('-D', '--destport', help='dest port', type=int, default=80)
parser.add_argument('file_name', nargs='+', help='The file name')
args = parser.parse_args()
#获取参数值
print args.ignore_case
print args.srcport
print args.destport
#python test.py -S 124 test mogl
#False
#124
#80
#['test', 'mogl']
参数
参数可分为两种:- 选项参数(optional)
parser.add_argument('-i', '--ignore-case', action='store_true', help='Ignore case search')
选项参数默认使用-
做前缀标识 - 位置参数(positional)
parser.add_argument('file_name', nargs='+', help='The file name')
- 选项参数(optional)
选项参数解析
选项参数默认返回None
,可用default
参数指定默认值。如果该参数是必须的则使用required=True
parser.add_argument('-i', '--ignore-case', action='store_true', help='Ignore case search')
parser.add_argument('-S', '--srcport', help='sorce port', type=int, required=True)
'-i', '--ignore-case'
参数长短语法action='store_true'
表明该参数不接受参数传递,即不接收诸如-i test
、--ignore-case=true
type=int
若不使用action='store_true'
则可表明接受参数传递,使用type
指定传入类型(type=int|str|complax
)help='sorce port'
该参数的说明
位置参数
若指定了位置参数,则运行程序时必须传入该参数才能运行
parser.add_argument('file_name', nargs='+', help='The file name')
nargs
将多个参数关联在一起。+
将多个参数存到一个列表里,至少要有一个参数否则报错
action
argparse默认设置6个action:- store
保存参数值,可能会先将参数值转换成另一个数据类型。若没有显式指定动作,则默认为该动作。 - store_const
保存一个被定义为参数规格一部分的值,而不是一个来自参数解析而来的值。这通常用于实现非布尔值的命令行标记。 - store_ture/store_false
保存相应的布尔值。这两个动作被用于实现布尔开关。 - append
将值保存到一个列表中。若参数重复出现,则保存多个值。 - append_const
将一个定义在参数规格中的值保存到一个列表中。 - version
打印关于程序的版本信息,然后退出
- store
re
re提供正则表达式匹配操作,是处理字符串最常用的库。
正则表达式语法
使用re库前,先大致了解正则表达式的基本语法,正好顺便总结一下有关正则表达式的内容。
符号 | 意义 | |||
---|---|---|---|---|
基本关键字 | ||||
. | 常规模式下匹配除\n 外的所有字符,DOTALL模式下\n 也匹配 |
|||
^ | 常规模式下匹配字符串开头,MULTILINE模式下匹配每行开头 | |||
$ | 常规模式下匹配字符串结尾,MULTILINE模式下匹配行尾 | |||
* | 匹配*前面内容零次或多次,贪婪匹配 | |||
+ | 匹配+前面内容零次或多次,贪婪匹配 | |||
? | 匹配?前面内容零次或1次 | |||
{m} | 匹配{m}前面内容m次 | |||
{m,n} | 匹配{m,n}前面内容m~n次 | |||
*? +? ?? {m,n}? | * + ? {m,n}都是贪婪匹配,后面加上?后为非贪婪匹配 | |||
[] | 匹配[]内字符集的任一字符,^ 表示不匹配,- 并用给出一段范围字符 |
|||
单竖线 | 或,只匹配其中一个 | |||
分组关键字 | ||||
(…) | 匹配括号内任意正则表达式并形成一个分组 | |||
(?P<name> …) |
为符合匹配的分组命名 | |||
(?#…) | 注释,(?#..)里的内容会被忽略 | |||
(?=…) | 匹配结果后面的字符串需要满足表达式... 。python_re_test——.*(?=_test) 则匹配到字符串python_re |
|||
(?!…) | 匹配结果后面的字符串必须不满足表达式... |
|||
(?<=…) | 匹配结果前面的字符串需要满足表达式... 。python_re_test——(?<=python_).* 则匹配字符串re_test |
|||
(?<!…) | 匹配结果前面的字符串必须不满足表达式... |
|||
特殊关键字 | ||||
\d | 匹配数字,相当于[0-9] | |||
\D | 匹配非数字,相当于[^0-9] | |||
\s | 匹配空白字符,相当于[\t\r\n\f\v] | |||
\S | 匹配非空白字符,相当于[^\t\r\n\f\v] | |||
\w | 匹配字母或数字,相当于[0-9a-zA-Z] | |||
\W | 匹配非字母或数字,相当于[^0-9a-zA-Z] | |||
\b | 匹配字符串边界 | |||
\B | 匹配非字符串边界 | |||
\A | 匹配字符串开头 | |||
\Z | 匹配字符串结尾 |
re库flags参数
Python的re库API中可指定flags参数,通过这些flags参数指定正则表达式选项通常使用类似re.I
这样的简写,比如re.compile(pattern, [flags])
函数——re.compile(pattern, re.I)
。
符号 | 意义 | |||
---|---|---|---|---|
re.A | ASCII | 使\w\W\b\B\d\D匹配ASCII字符 | ||
re.I | IGNORECASE | 忽略大小写 | ||
re.L | LOCALE | 使\w\W\b\B匹配本地字符集 | ||
re.M | MULTILINE | 多行模式,^ 匹配每行开头,$ 匹配每行结尾 |
||
re.X | VERBOSE | 详细模式,忽略空格和# 后面的注释 |
||
re.U | UNICODE | 使\w\W\b\B\d\D匹配unicode字符集 |
re库正则函数
re.compile(pattern[, flags])
将模式和标识编译成正则表达式对象,方便给search()
、match()
和findall()
等函数使用。1
2
3
4
5import re
pattern = re.compile(r'[0-9]+')
print pattern.findall('abc123d')
#123re.search(pattern, string[, flags])
在字符串string
中查找匹配pattern
表达式的串,成功则返回MatchObject对象,失败则返回Nonere.search (string[, pos[, endpos]])
对于已编译的正则表达式对象,search()
函数可指定搜索的起始结束位置1
2
3
4
5
6
7
8
9
10import re
#使用compile()
pattern = re.compile("a+")
print pattern.search("aabcde").group(0) #=>aa
print pattern.search("aabcde", 1).group(0) #=>a
#不使用compile()
regx = re.search(r'a+', 'aabcde')
print regx.group(0) #=>aa
re.match(pattern, string[, flags])
在字符串string
开头位置查找匹配pattern
表达式的串(必须是开头位置)- re.match(string[, pos[, endpos]])
同样对于已编译的正则对象可指定位置1
2
3pattern = re.compile("a+")
print pattern.match('aabcde').group(0) #=>aa
print pattern.match('xaabcde') #=>None
- re.match(string[, pos[, endpos]])
re.findall(pattern, string[, flags])
在字符串string
中查找所有匹配pattern
的串,成功则返回列表,失败则返回空列表。
re.search()
和re.match()
仅匹配一次。- re.findall(string[, pos[, endpos]])
同样对于已编译的正则对象可指定位置1
2
3
4
5pattern = re.compile("\d+")
print pattern.search('ab12cd34').group(0) #=>12
print pattern.match('ab12cd34') #=>None
print pattern.findall('ab12cd34') #=>['12', '34']
- re.findall(string[, pos[, endpos]])
re.finditer(pattern, string[, flags])
re.finditer()
和re.findall()
类似,只是re.finditer()
返回一个迭代器对象。1
2
3
4
5pattern = re.compile("\d+")
for each_iter in piter:
print each_iter.group(0)
#=>12
#=>34re.sub(pattern, rep_string, string[, count, flags])
- re.subn(pattern, rep_string, string[, count, flags])
在字符串string
中查找匹配pattern
的字符串并用rep_string
替换。rep_string
可以是一个函数,成功则返回替换后的字符串,否则返回原字符串。
re.subn()
和re.sub()
类似,只是re.subn()
返回替换后的字符串和替换次数。1
2
3pattern = re.compile(r'(name|full_name)')
pattern.sub('mogl', 'name test python re full_name')
#=>'mogl test python re mogl'
MatchObject对象
re.match()
、re.search()
和re.finditer()
若成功匹配的话都是返回一个MatchObject对象。(re.findall()
返回列表)
MatchObject对象可调用几个函数:
group()
:返回匹配的完整字符串groups()
:返回分组信息groupdict()
:返回所有命名分组字典start()
:返回匹配字符串的起始位置end()
:返回匹配字符串的结束位置span()
:返回起始位置和结束位置的元组
1 | import re |
os
os模块提供统一的操作系统功能。
os.getcwd()
获取当前工作目录os.chdir(path)
修改工作目录os.listdir(path)
列出path下所有文件/目录,不支持递归和通配符os.walk(path)
深度遍历path下所有文件/目录1
2for root, dirs, files in os.walk('/tmp'):
print "root=%s, dirs=%s, files=%s" % (root, dirs, files)**os.mkdir(path)
创建目录,若path已存在则抛出异常os.makedirs(‘/path/subpath’)
递归创建多级目录,相当于Linux命令mkdir -p
os.rmdir(path)
删除空目录os.removedirs(path)
递归删除path下的子目录,目录非空则异常os.remove(file)
删除文件,若file为目录则抛出异常os.rename(path1, path2)
重命名os.renames(path1, path2)
重命名,会创建path2目标路径os.chmod(path, mode)
修改权限1
os.chmod('/tmp/test', 0777)**
os.chown(path, uid, gid)
修改拥有者os.access(path, mode)
权限测试1
2
3os.access('/tmp/test.txt', os.W_OK)**
os.access('/tmp/test.txt', os.R_OK)**
os.access('/tmp/test.txt', os.X_OK)**
os.path
os.path提供操作路径的函数。
os.path.abspath(path)
获取绝对路径os.path.realpath(path)
软连接的真实路径os.path.basename(path)
获取文件名,以/
结尾的路径返回空os.path.dirname(path)
获取目录名os.path.exists(path)
判断path
路径是否存在os.path.isfile(path) / os.path.isdir(path) / os.path.islink(path) / os.path.ismount(path)
判断path
是否为文件/目录/软连接/挂载点os.path.split(path)
将path
切分为(目录, 文件名)
os.path.splitext(path)
将path
切分为(目录/主文件名, 后缀名)
os.path.join(path1, path2)
拼接路径
sys
sys模块,主要处理Python环境的变量使得程序与系统环境有交互。
- sys.argv[x]
获取命令行参数列表。0
表示程序名,1
表示第一个命令行第一个参数,以此类推。 - sys.exit(num)
程序退出状态码,sys.exit(0)
表示正常退出。 - sys.path
返回模块的搜索路径。 - sys.stdout / sys.stdin / sys.stderr
标准输出/输入/错误输出
time
time模块主要提供和时间相关的函数。
- time.time()
返回距离纪元(1970-01-01 00:00:00)开始的秒数,返回值为浮点数。 - time.ctime()
返回字符串型易读的时间,诸如:Wed Oct 1 20:18:59 2016
- time.clock()
返回当前进程消耗的CPU时间(秒) time.gmtime() / time.localtime()
time.gmtime()
和time.localtime()
的结果都是使用struct_time格式显示,可使用time.asctime()
转变成time.ctime()
的字符串格式显示。
time.gmtime()
获取的是UTC时间,time.localtime()
获取的是当前时区的时间。在中国:time.gmtime() = time.localtime() + 8hour
1
2
3
4
5
6
7
8time.gmtime()
#time.struct_time(tm_year=2016, tm_mon=10, tm_mday=5, tm_hour=15, tm_min=29, tm_sec=14, tm_wday=2, tm_yday=279, tm_isdst=0)
time.localtime()
#time.struct_time(tm_year=2016, tm_mon=10, tm_mday=5, tm_hour=23, tm_min=30, tm_sec=4, tm_wday=2, tm_yday=279, tm_isdst=0)
time.asctime(time.localtime())
#'Wed Oct 5 23:30:35 2016'time.strptime()
将字符串格式时间转成struct_time格式时间1
2time.strptime(time.ctime())
#time.struct_time(tm_year=2016, tm_mon=10, tm_mday=5, tm_hour=23, tm_min=37, tm_sec=17, tm_wday=2, tm_yday=279, tm_isdst=-1)time.strftime()
将时间格式化输出1
2time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
#'2016-10-05 23:39:23'time.sleep(num)
进程sleep时间
datetime
datetime模块提供操作日期和时间函数。
datetime模块常用的有四个类别,这些对象都是不可变对象:
datetime.date
:用于操作日期datetime.time
:用于操作时分秒datetime.datetime
:用于操作日期和时分秒datetime.timedelta
:用于操作时间间隔
datetime.date
1 | from datetime import date |
datetime.time
1 | import datetime |
datetime.datetime
datetime.datetime
和datetime.time
差不多1
2
3
4
5
6
7
8start = datetime.datetime.now()
#2016-10-06 23:47:29.105713
end = datetime.datetime.now()
#2016-10-06 23:47:45.449751
print (end - start).seconds
#16
datetime.timedelta
主要用于做时间的加减操作。1
2
3
4
5
6
7today = datetime.datetime.today()
#2016-10-06 23:41:46.170686
delta = datetime.timedelta(days=1)
yesterday = today - delta
#2016-10-05 23:41:46.170686
paramiko
paramiko模块提供ssh远程登录等相关功能。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
34import paramiko
def ssh_command(ip, username, passwd, cmd, port=22):
"""paramiko demo"""
try:
ssh = paramiko.SSHClient()
#允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, port, username, passwd, timeout=30)
stdin, stdout, stderr = ssh.exec_command(cmd)
except Exception, e:
raise "%s ssh connect error: %s" % (ip, e)
finally:
ssh.close()
std_result = {'stdout': stdout.readlines(),
'stderr': stderr.readlines()
}
return std_result
#paramiko模块还支持sftp传输功能
scp=paramiko.Transport((host_ip, ssh_port))
scp.connect(username=ssh_username, password=ssh_passowrd)
sftp=paramiko.SFTPClient.from_transport(scp)
#如果之前已有一个建立连接的ssh对象,则可直接复用该ssh连接对象
#sftp = paramiko.SFTPClient.from_transport(ssh.get_transport())
#sftp = ssh.open_sftp()
#下载文件
sftp.get('/tmp/remote_file','/tmp/local_file')
#上传文件
sftp.put('/home/local_file','/tmp/remote_file')
scp.close()
subprocess
subprocess模块允许创建新进程并获取返回值/输出信息,常用来调用系统命令。
常用已封装好的函数有三个:
- subprocess.call()
返回exit code。不管exit code
是什么都不会抛出异常。 - subprocess.check_call()
返回exit code并检查exit code。exit code
为0
则成功,否则抛出subprocess.CalledProcessError
异常。 - subprocess.check_output()
返回输出信息且检查exit code。exit code
不为0则抛出subprocess.CalledProcessError
异常。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import subprocess
#结果相同,返回的是exit code
subprocess.call(['echo', 'test'])
subprocess.call("echo test", shell=True)
subprocess.check_call(['echo', 'test'])
#test
#0
#返回的是输出信息
subprocess.check_output(['echo', 'test'])
#'test\n'
#可用shlex模块解析参数而不使用`shell=True`
subprocess.call(shlex.split("echo test"))
#test
#0
#忽略输出,只获取exit code
with open(os.devnull, 'w') as devnull:
exit_code = subprocess.call(["echo", "test"], stdout=devnull, stderr=devnull, shell=True)
subprocess.Popen()
subprocess.call
、subprocess.check_call
和subprocess.check_output
都是基于subprocess.Popen()
的封装。在创建了Popen
对象后,父进程不会主动等待子进程需要调用wait()
方法使其等待。1
2
3
4
5subprocess.Popen('ps aux|grep ipython', shell=True).wait()
#命令输出
#=>mogl 28580 0.0 0.3 32568 15332 pts/26 Sl+ 16:35 0:01 /usr/bin/python /usr/local/bin/ipython
#返回值
#=>0
可使用subprocess.PIPE
改变输入输出对象并获取子进程的更详细信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16child = subprocess.Popen('ps aux|grep ipython', shell=True, stdout=subprocess.PIPE)
child.pid
#25556
child.stdout.readlines()
#mogl 28580 0.0 0.3 32568 15332 pts/26 Sl+ 16:35 0:01 /usr/bin/python /usr/local/bin/ipython
child.poll
#检查子进程是否已终止。没终止返回空,终止返回exit code
child.wait()
#0
child.returncode
#0
subprocess.PIPE
还可以将多个子进程的输入输出连接
communicate()
是Popen对象的方法,该方法会阻塞父进程,直到子进程完成。child2
的输出也在PIPE中,需要调用child2.communicate()
读取。1
2
3child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
out = child2.communicate()
functools
functools提供高阶函数功能。主要包含cmp_to_key
、partial
、reduce
、total_ordering
、update_wrapper
和wraps
这几个函数。
functools.cmp_to_key(func)
functools.cmp_to_key()
是Python2.7新增的函数,用于将比较函数转成key函数,需要在接受key函数作为参数的函数中才使用。其实是为了兼容Python3,拿sorted()
函数为例:Python2版本的sorted()
函数支持cmp
参数来处理用户自定义的排序函数,但Python3后将cmp
参数移除了,所以需要使用到cmp_to_key
将自定义的排序函数转成key函数1
2
3
4
5
6
7#Python2
sorted([5, 2, 4, 1, 3], cmp=lambda x, y: y-x)
#=>[5, 4, 3, 2, 1]
#Python3
sorted([5, 2, 4, 1, 3], key=cmp_to_key(lambda x, y: y-x))
#=>[5, 4, 3, 2, 1]functools.total_ordering(cls)
functools.total_ordering()
也是Python2.7新增的函数,主要用于简化比较函数的写法。当某个类定义了__eq__()
方法,并且定义了__lt__()
、__le__()
、__gt__()
或__ge__()
方法中的其中一个,若使用@total_ordering()
装饰器,则该类会自动生成其他的比较方法。
官方例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from functools import total_ordering
@total_ordering
class Student:
def __eq__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) ==
(other.lastname.lower(), other.firstname.lower()))
def __lt__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) <
(other.lastname.lower(), other.firstname.lower()))
print dir(Student)
#=>['__doc__', '__eq__', '__ge__', '__gt__', '__le__', '__lt__', '__module__']functools.reduce(function, iterable)
functools.reduce()
和内置的reduce()
功能一样,使用functools.reduce()
也是为了兼容Python3。functools.partial(func[,*args][, keywords])**
functools.partial()
简单的说就是实现柯里化的。1
2
3
4
5
6
7
8from functools import partial
def add(x, y):
return x + y
add_y = partial(add, 1)
print add_y(1)
#=>2functools.wraps(wrapped[, assigned][, updated])
functools.wraps()
主要的作用是消除Python中装饰器带来的一些副作用。Python中使用装饰器,被装饰函数的__name__
属性会被改变,需要用functools.wraps()
进行修正。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from functools import wraps
def decorator(func):
#@wraps(func)
def wrapper(*args, **kwargs):
print "In decorator wrapper func."
return func(*args, **kwargs)
return wrapper
@decorator
def test():
print "In test func."
print test.__name__
#=>wrapperfunctools.update_wrapper(wrapper, wrapped[, assigned][, updated])
functools.wraps()
是functools.update_wrapper()
的简化版本,functools.update_wrapper()
功能更强大,默认会将被装饰函数的functools.WRAPPER_ASSIGNMENTS
(__module__
、__name__
、__doc__
)和functools.WRAPPER_UPDATES
(__dict__
)都复制给装饰函数。
实际上面的装饰器代码可用update_wrapper()
写:1
2
3
4
5
6
7from functools import update_wrapper
def decorator(func):
def wrapper(*args, **kwargs):
print "In decorator wrapper func."
return func(*args, **kwargs)
return update_wrapper(wrapper, func)
smtplib
smtplib模块用于发送邮件。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
42import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
def send_mail(send_list, subject, content):
"""html/text邮件"""
mail_host = "your_smtp_server_address"
mail_user = 'your_email_user(xxx@gmail.com)'
mail_passwd = 'your_email_password'
mail_port = 25
send_from = "your_send_from" + "<" + mail_user + ">"
##TEXT邮件
#msg = MIMEText(content, _subtype='plain', _charset='utf-8')
##HTML邮件
#msg = MIMEText(content, _subtype='html', _charset='utf-8')
##带附件邮件
msg = MIMEMultipart()
#邮件正文
msg.attach(MIMEText(content, _charset='utf-8'))
#附件一
att_1 = MIMEText(open('/tmp/attachment1.txt', 'rb').read(), 'base64', 'utf-8')
att_1['Content-Type'] = 'application/octet-stream'
#邮件中附件显示的文件名字
att_1['Content-Disposition'] = 'attachment; filename=%s' % "附件1"
msg.attach(att_1)
msg['From'] = send_from
msg['Subject'] = subject
try:
mail_server = smtplib.SMTP()
mail_server.connect(mail_host, mail_port)
mail_server.login(mail_user, mail_passwd)
mail_server.sendmail(msg['From'], send_list, msg.as_string())
mail_server.close()
return True
except Exception, e:
print str(e)
return False
requests
requests是第三方模块,相比Python内置的urlib2
更人性化。
由于requests是第三方模块,需要使用pip
进行安装,在一些版本中可能会在使用中出现SNIMissingWarning
和InsecurePlatformWarning
警告,可按以下方法安装。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#安装
yum install -y openssl-devel python-devel libffi-devel
pip install 'requests[security]'
#若在使用中出现SNIMissingWarning和InsecurePlatformWarning警告可
pip install pyopenssl ndg-httpsclient pyasn1
#若不想额外安装包可手动忽略警告
#关闭requests的https警告
try:
from requests.packages.urllib3.exceptions import (
SNIMissingWarning,
InsecureRequestWarning,
InsecurePlatformWarning
)
requests.packages.urllib3.disable_warnings(SNIMissingWarning)
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
except ImportError:
pass
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
39
40
41
42
43
44
45
46
47
48import requests
import json
url = 'https://github.com/timeline.json'
#GET请求(10s超时)
r = requests.get(url, timeout=10)
#文本方式显示
print r.text
#字节方式显示,中文显示为字符
print r.content
#显示编码 & 设置编码
print r.encoding
r.encoding = 'utf-8'
#响应状态码
r.status_code
#HTTP header
r.headers
r.headers['Content-Type']
#JSON化,失败会抛出异常
r.json()
#POST请求
headers = {
'content-type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'
}
data = {
"mobile": mobile,
"templateId": template_id,
"templateVariable": {
self.mobile: {
"secode": vcode
}
},
"userName": user_name,
"randomKey": random_key,
"fingerprint": fingerprint
}
try:
r = requests.post(url, data=json.dumps(data), headers=headers)
result = r.json()
#result = json.loads(r.content)
except Exception, err:
raise err
hashlib
hashlib模块实现各种hash算法。hashlib基于OpenSSL,支持md5
、sha1
、sha224
、sha256
、sha384
和sha512
等算法。
基本用法。update()
可多次调用,每次都会根据新增文本更新结果。1
2
3
4
5
6
7
8import hashlib
mystr = 'mogl'
mymd5 = hashlib.md5()
mymd5.update(mystr)
print mymd5.hexdigest()
#=>d2624edb33f3be2c461b1e95740b6b5c
用new()
方法通过字符串形式指定算法1
2
3
4
5
6
7import hashlib
import sys
hash_name = sys.argv[1]
myhash = hashlib.new(hash_name)
myhash.update(mystr)
print myhash.hexdigest()
multiprocessing
multiprocessing模块提供多进程编程。
multiprocessing.Process
Process
类的原型multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={})
。每个Process
类会生成一个process
对象并在新的进程中运行。
每个process
对象最多只能调用一次start()
方法,join([timeout])
方法会阻塞调用process
对象的进程等待子进程执行完毕。group
:仅为兼容threading.Thread
,通常为None
target
:子进程要执行的函数name
:进程名,默认为Process-1
、Process-2...
args
:target
函数调用的参数kwargs
:target
函数调用的字典参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from multiprocessing import Process
import os
def child_run(name):
print "Run in child process name: %s, pid: %s" % (name, os.getpid())
if __name__ == '__main__':
print "Parent process pid: %s" % os.getpid()
print "Creating child process..."
#注意args参数中必须有,
multi_proc = Process(target=child_run, args=('child_test',))
#设置daemon属性
#multi_proc.daemon = True
print "Starting child process..."
multi_proc.start()
multi_proc.join()
print "Process end."
#Parent process pid: 12198
#Creating child process...
#Starting child process...
#Run in child process name: child_test, pid: 12199
#Process end.多进程并行运行。每个子进程都是先
start()
,最后在一起join()
。若对每个process
对象都一起执行start()
和join()
则变成顺序执行而非并发执行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from multiprocessing import Process
import os
def child_run(name):
print "Run in child process name: %s, pid: %s" % (name, os.getpid())
if __name__ == '__main__':
names = ['mo', 'guo', 'liang', 'mogl']
proc_list = []
print "Parent process pid: %s" % os.getpid()
for name in names:
multi_proc = Process(target=child_run, args=(name,))
proc_list.append(multi_proc)
multi_proc.start()
for each_child_proc in proc_list:
each_child_proc.join()
#Parent process pid: 14516
#Run in child process name: mo, pid: 14517
#Run in child process name: guo, pid: 14518
#Run in child process name: liang, pid: 14519
#Run in child process name: mogl, pid: 14520
multiprocessing.Lock
multiprocessing.Lock
提供锁功能,当多进程需要访问共享资源时,可用锁来避免冲突。使用锁的话多进程并行则会受到锁的限制。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
41from multiprocessing import Process, Lock
import os
def printer(string):
print "In printer, string: %s, pid: %s" % (string, os.getpid())
def printer_lock(string, lock):
lock.acquire()
print "In printer, string: %s, pid: %s" % (string, os.getpid())
lock.release()
if __name__ == '__main__':
proc_list = []
names = ['mo', 'guo', 'liang', 'mogl']
print "Parent pid: %s" % os.getpid()
for each_name in names:
multi_proc = Process(target=printer, args=(each_name,))
proc_list.append(multi_proc)
multi_proc.start()
lock = Lock()
for each_name in names:
multi_proc_lock = Process(target=printer_lock, args=(each_name, lock))
proc_list.append(multi_proc_lock)
multi_proc_lock.start()
for each_proc in proc_list:
each_proc.join()
#Parent pid: 9313
#In printer, string: mo, pid: 9314
#In printer, string: liang, pid: 9316
#In printer, string: guo, pid: 9315
#In printer, string: mogl, pid: 9317
#In printer, string: mo, pid: 9318
#In printer, string: guo, pid: 9319
#In printer, string: liang, pid: 9320
#In printer, string: mogl, pid: 9321multiprocessing.Queue & multiprocessing.Pipe
multiprocessing
支持两种进程间通信方式:Queue
、PIPE
,Queue
是进程安全的。multiprocessing.Queue
使用Queue
实现进程间通信,进程A使用put()
方法将数据存入Queue
,进程B使用get()
方法从Queue
中读取数据。
put()
、get()
方法都有两个参数:block
、timeout
,若block=False
,Queue为full
/empty
则抛出异常,若设置了timeout
则阻塞等待再一次put
/get
。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
28from multiprocessing import Process, Queue
import os
def write_queue(queue):
print "In write_queue pid: %s" % os.getpid()
queue.put(['mogl'], block=False)
def read_queue(queue):
print "In read_queue pid: %s" % os.getpid()
print queue.get(block=False)
if __name__ == '__main__':
print "Parent pid: %s" % os.getpid()
queue = Queue()
write_proc = Process(target=write_queue, args=(queue,))
write_proc.start()
read_proc = Process(target=read_queue, args=(queue,))
read_proc.start()
write_proc.join()
read_proc.join()
#Parent pid: 18383
#In write_queue pid: 18384
#In read_queue pid: 18385
#['mogl']multiprocessing.Pipe
Pipe()
方法会返回(c1, c2)
代表一个管道的两端,默认Pipe()
的duplex=True
表示全双工管道,即管道的任意一端都可发送和接收信息。若duplex=False
则c1
只负责接收,c2
只负责发送。当调用recv()
方法从管道读取消息时候,若管道一端无消息,recv()
则会一直阻塞。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
31from multiprocessing import Process, Pipe
import os
def process_one(pipe):
pipe.send('hello, process_one send message.')
print 'process_one receive message:', pipe.recv()
print "process_one pid:", os.getpid()
def process_two(pipe):
print 'process_two receive message:', pipe.recv()
pipe.send('hello, process_two send message.')
print "process_two pid:", os.getpid()
if __name__ == '__main__':
pipe = Pipe()
print "main pid:", os.getpid()
pro1 = Process(target=process_one, args=(pipe[0],))
pro2 = Process(target=process_two, args=(pipe[1],))
pro1.start()
pro2.start()
pro1.join()
pro2.join()
#process_one发送消息后recv,由于管道一端无消息而阻塞,故先打印process_two的内容
#main pid: 14215
#process_two receive message: hello, process_one send message.
#process_two pid: 14217
#process_one receive message: hello, process_two send message.
#process_one pid: 14216
multiprocessing.Pool
Python多进程支持进程池,使用multiprocessing.Pool
能创建一个进程池可指定进程数量,当请求提交给pool后,若pool没满则可创建新进程处理该请求,若已满则等待空闲后再处理。
进程池中进程的创建可通过apply_async(func[, args[, kwds[, callback]]])
或apply(func[, args[, kwds]])
方法。apply_async()
是非阻塞,apply()
是阻塞(进程池中一个进程执行完才会执行下一个)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24from multiprocessing import Pool
import os
import time
import random
def child_process_task(name):
print "Running task %s, pid %s" % (name, os.getpid())
start_time = time.time()
time.sleep(random.random() * 3)
end_time = time.time()
print "Task %s is over and runs %0.2f seconds." % (name, (end_time - start_time))
if __name__ == '__main__':
print "Parrent process pid %s" % os.getpid()
#创建进场池。限制并发数量:child_pool = Pool(processes=4)
child_pool = Pool()
for eachpid in range(5):
#批量创建子进场(指定执行函数及其参数)
child_pool.apply_async(child_process_task, args=(eachpid,))
print "Waitting for all child process done..."
#调用join()前必须先调用close()。close()关闭pool不在接受新请求。join()等待所有子进程结束
child_pool.close()
child_pool.join()
print "All process is done."
MySQLdb
MySQLdb是第三方模块,用于连接及操作MySQL。
一般先使用MySQLdb.connect()
方法创建连接对象,该连接对象支持事务操作,即允许commit()
和rollback()
。然后使用cursor()
方法获取游标对象,该对象做两类操作——执行sql和获取查询结果。最后操作完数据库后需要调用close()
方法关闭相关对象。
执行sql
1 | import MySQLdb |
更新(update)、删除(delete)和插入(insert)等支持事务操作。1
2
3
4
5
6
7
8
9
10
11
12
13
14insert_sql = 'INSERT INTO STUDENT(NAME, AGE, GENDER)\
VALUES ("%s", "%s", "%s")' % ('mogl', 10, 'male')
try:
db_conn = MySQLdb.connect(host='localhost', user='root', passwd='fate', db='test', port=3306)
db_cur = db_conn.cursor()
db_cur.execute(insert_sql)
db_conn.commit()
except Exception, e:
db_conn.rollback()
raise e
finally:
db_cur.close()
db_conn.close()
获取查询结果
使用fetchall()
返回select
查询的所有结果,默认每行结果以元组形式返回,可使用cursorclass=MySQLdb.cursors.DictCursor
返回字典形式。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15select_sql = "select * from STUDENT"
try:
db_conn = MySQLdb.connect(host='localhost', user='root', passwd='fate', db='test', port=3306)
db_cur = db_conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
db_cur.execute(select_sql)
select_result = db_cur.fetchall()
except Exception, e:
raise e
finally:
db_cur.close()
db_conn.close()
for row in select_result:
print row['NAME'], row['AGE'], row['GENDER']
ConfigParser
ConfigParser模块用来解析类似ini格式的配置文件。
ini格式配置文件大致如下:
section
:[test1]
、[test2]
option
:section
下所有的键items
:section
下所有的键值对1
2
3
4
5
6
7
8
9#test.cfg
[test1]
name = mogl
passwd = 1234
[test2]
name = moguoliang
passwd = 4321
1 | import ConfigParser |
lxml
lxml用于解析xml或html,用法比较复杂,这里只记录自己用到的简单功能。
cssselect()
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
35from lxml import html
#实例一
page = '<img class="BDE_Image" src="http://test.com/test.jpg" width="560" height="323">'
doc = html.fromstring(page)
for index, content in enumerate(doc.cssselect('img.BDE_Image')):
img_src = content.attrib['src']
print index, img_src
#0 http://test.com/test.jpg
#实例二
page = """
<div class="buyer-name">mogl</div>
<span class="item-price" src='http://test.com/test.html'>$2.9</span>
<span class="item-price" src='http://test.com/test2.html'>$3.0</span>
"""
htmlDoc = html.fromstring(page)
buyers = htmlDoc.cssselect('div.buyer-name')
prices = htmlDoc.cssselect('span.item-price')
for eachBuyer in htmlDoc.cssselect('div.buyer-name'):
print "buyer:", eachBuyer.text_content()
for eachPrice in htmlDoc.cssselect('span.item-price'):
print eachPrice.text_content()
print eachPrice.attrib['src']
#buyer: mogl
#$2.9
#http://test.com/test.html
#$3.0
#http://test.com/test2.htmlxpath
先简单记录xpath
的路径表达式:
表达式 | 实例 | 意义 | ||
---|---|---|---|---|
/ | xpath(‘/div’) | 从根节点选取div 节点 |
||
// | xpath(‘//div’) | 选取所有div 节点 |
||
. | xpath(‘./div’) | 选取当前节点下的div 节点 |
||
.. | xpath(‘..’) | 选取父节点 | ||
@ | xpath(‘//@class’) | 选取属性 |
1 | from lxml import html |
BeautifulSoup
BeautifulSoup模块和lxml
类似都是用来解析HTML/XML的。该模块是是第三方模块需要安装。1
$> pip install beautifulsoup4
为了方便记录,就以以下的HTML代码为解析例子1
2
3
4
5html = """
<html><head><title>The BeautifulSoup test</title></head>
<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>
<img src=http://www.mogl.com/img/test.png width=270 height=129>
"""
默认Python会使用内置的解析器进行解析,但速度较慢,这里使用lxml
来进行解析(需要先装lxml
)。1
2
3
4
5
6
7from bs4 import BeautifulSoup
import re
#创建BeautifulSoup对象
soup = BeautifulSoup(html, 'lxml')
#格式化输出
print soup.prettify('utf-8')
Tag——标签
Tag
是HTML中的标签,诸如title
和a
等。BeautifulSoup对Tag
的处理主要包含三种:
- name
- string
- attrs
获取整个Tag
1
2
3
4
5
6
7
8print soup.title
print soup.head
print soup.a
print soup.img
#<title>The BeautifulSoup test</title>
#<head><title>The BeautifulSoup test</title></head>
#<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>
#<img height="129" src="http://www.mogl.com/img/test.png" width="270"/>
name
是获取Tag
的类型1
2
3
4print soup.title.name
print soup.a.name
#title
#a
string
是获取Tag
标签中的文本内容1
2
3
4print soup.title.string
print soup.a.string
#The BeautifulSoup test
#新闻
attrs
是获取Tag
标签中的属性1
2
3
4
5
6print soup.a.attrs
#{'href': 'http://news.mogl.com', 'class': ['mnav'], 'name': 'news'}
print soup.a['href']
#http://www.mogl.com/img/test.png
print soup.img.get('src')
#http://www.mogl.com/img/test.png
find_all——搜索
find_all()
是搜索当前tag
的所有节点,返回符合条件的tag
对象list。
find_all()
可对tag.name
和tag.attrs
进行搜索,还支持对使用re
的正则匹配。1
2
3
4
5
6
7
8print soup.find_all('a')
#[<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>]
print soup.find_all(['a', 'img'])
#[<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>, <img height="129" src="http://www.mogl.com/img/test.png" width="270"/>]
print soup.find_all(re.compile(r'^a|^i'))
#[<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>, <img height="129" src="http://www.mogl.com/img/test.png" width="270"/>]
对tag.attrs
进行搜索。当对HTML的class
属性搜索时,为避免与Python内置的class
关键字冲突,使用class_
。1
2
3
4
5
6
7
8
9print soup.find_all('a', class_="mnav")
#[<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>]
print soup.find_all(href=re.compile('mogl.com'), class_="mnav")
#[<a class="mnav" href="http://news.mogl.com" name="news">新闻</a>]
for num, each_tag in enumerate(soup.find_all('img')):
print num, each_tag['width']
#0 270