1.模块
在编程过程中如果把所有的代码都写到一个.py文件中,那会降低代码的可阅读性,我们可以把代码中的函数或者类分组写到其他的.py文件中,这样的一个.py文件就叫做一个模块,而且我们不用担心模块的函数名或者变量名会与其他模块中的变量名冲突,但是模块名不可以重复,这时我们就可以将模块分组放入一个python package(python包)中,只要这个包的名称不和其他包相同就可以,但要注意此时的模块名变成了 包名.模块名 在导入时需要注意。包亦可以有多级目录,每一级中的模块名都变为 顶层包名.该级包名.模块名 在导入时需要注意。
2.使用模块
代码的标准开头应该这样写:
#!/usr/bin/env python 3 # 使这个文件可以在Unix/Linux/mac中直接运行
#-*- coding utf-8 -*- # 声明该文件使用标准UTF-8编码
'a test module' # 模块注释
__author__ = 'why' # 作者名
下面使用系统模块sys举一个例子:
import sys
def text():
arg = sys.argv
if len(arg) == 1:
print("hello world")
elif len(arg) == 2:
print("hello %s!" % arg[1])
else:
print("so many mess")
if __name__ == '__main__' : # 在命令行中该语句可以通过,其他地方不可以
text()
sys.argv 以列表形式返回在命令行输入的参数,而且第一个元素arg[0]一定是函数名
3.作用域:
在模块中定义的函数和变量有些我们并不想让它们被引用,那么可以给函数名或者变量名
加上前缀'_',但这不是绝对的,加前缀只是告诉别人这是不公开的函数或变量,还是可以
被引用
4.安装第三方模块
在Windows中,打开命令行,输入pip,确认已安装,之后输入pip install 模块名
等待安装完成
在Linux/Mac中pip已预装,有些是python2.x与python3.x共存,要使用python3安装则pip3
常用内置模块:
time
#时间戳 time.time() 1970年1月1日凌晨00:00,到当前时间的秒数
#结构化时间 time.localtime() 当地时间
time.gmtime() 世界标准时间
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2019, tm_mon=7, tm_mday=30, tm_hour=11, tm_min=10, tm_sec=30, tm_wday=1, tm_yday=211, tm_isdst=0)
>>> time.gmtime()
time.struct_time(tm_year=2019, tm_mon=7, tm_mday=30, tm_hour=3, tm_min=31, tm_sec=16, tm_wday=1, tm_yday=211, tm_isdst=0)
#字符串时间
>>> #将结构化时间转化为时间戳
>>> time.mktime(time.localtime())
1564457748.0
>>> #将结构化时间转化为字符串时间
>>> time.strftime("%Y-%m-%d %X",time.localtime())
'2019-07-30 11:38:39'
>>> #将字符串时间转化为结构化时间
>>> time.strptime("2019-7-30 11:40:56","%Y-%m-%d %X")
time.struct_time(tm_year=2019, tm_mon=7, tm_mday=30, tm_hour=11, tm_min=40, tm_sec=56, tm_wday=1, tm_yday=211, tm_isdst=-1)
>>> #将时间戳转化为标准格式的字符串
>>> time.ctime(time.time())
'Tue Jul 30 11:43:29 2019' # %a %b %d %H:%M:%S %Y
>>> #将结构化时间转化为标准格式的字符串
>>> time.asctime(time.localtime())
'Tue Jul 30 11:44:58 2019'
random
random.random() # 随机生成0-1的浮点数
random.randint(1,2) # 随机生成指定范围内的整数 [1,2]
random.randrange(1,2) # [1,2)
random.choice([1,2,3,4]) #从一个可迭代对象中随机选择一个
random.sample() # 随机选择两个
random.uinform(1,3) # 在指定范围中随机选择浮点数
ret = [1,2,3,4,5]
random.shuffle(ret) # 打乱顺序
ret
os
>>> import os
>>> os.getcwd()
'D:\\python37'
>>> # os.chdir()改变当前工作目录
>>> # os.makedirs(s1/s2)
>>> #os.removedirs() 若目录为空,则删除,并递归到上一级目录,若也为空,则继续删除,以此类推直到找到不控的文件夹
>>>
>>> #os.stat('filename.py') 查看文件信息
>>> #os.system('dir') 执行sheel
>>> # os.path.split() 分割路径和文件名
>>> # dirname() 取前面 basename() 取后面
>>> # os.path.join() 路径拼接
>>> # getatime()访问时间 getmtime()修改时间
>>> # os.getcwd() 获取当前工作目录
sys
>>> #sys.exit() 退出程序
>>> #sys.platform() 返回操作系统平台
>>> #sys.argv 命令行执行程序时 可以获取执行命令之后的输入
E:\python\DOME.C\s3>python 随机验证码.py 111 222
['随机验证码.py', '111', '222']
>>> #sys.stdout.write() 向屏幕打印
>>> # sys.stdout.flush() 刷新缓存
>>> # sys.version 获取python解释程序的版本信息
>>> # sys.path 返回模块的搜索路径,初始化时返回PYTHONPATH环境变量中的值
>>> # sys.maxsize 9223372036854775807 最大的int值 在python中是maxint
json # 只能序列化字符串
json.dumps() 序列化 第一步把单引号变成双引号,第二步包装成字符串
json.loads() 反序列
json.dump(dic,f) 文件操作
json.load(f) 文件操作
pickle:在使用上和json一样,但pickle将数据转换成bytes
shelve:处理成字典
XML
tag 标题
attrib 属性
text 内容
re 正则匹配模块
元字符:
默认贪婪匹配 加?变成惰性匹配 如*? +?
1. . 通配符
# 可以匹配任意字符,但数量要对应
>>> re.findall("a..b","abfb")
['abfb']
>>> re.findall("a..b","abfsb")
[]
2. ^ 在字符串开头匹配
# 只在开头进行匹配
>>> re.findall("^a..b","abfbacvb")
['abfb']
>>> re.findall('^a..b','advaewrwabvb')
[]
3. $ 结尾匹配
# 只在结尾匹配
>>> re.findall('a..b$','advaewrwabvb')
['abvb']
4. * 零到无穷
# 贪婪匹配 零个或无穷多个
>>> re.findall('abc*','avdaab')
['ab']
>>> re.findall('abc*','avdaabccc')
['abccc']
5. + 一到无穷
# 贪婪匹配,但至少有一个
>>> re.findall('abc+','avdaabccc')
['abccc']
>>> re.findall('abc+','avdaab')
[]
6. ? 零到一
# 最多匹配一个,可以将* +变为惰性匹配
>>> re.findall('abc?','avdaab')
['ab']
>>> re.findall('abc?','avdaabccc')
['abc']
7. {} 自定义范围 {0,} == *,{1,} == + {0,1} == ?
# 指定匹配的数目
>>> re.findall('abc{5}','avdaabccccccccccccc')
['abccccc']
8. [] 字符集
# 根据指定的字符集匹配
>>> re.findall('[a-z]+','avdaabccccccccccccc')
['avdaabccccccccccccc']
>>> re.findall('[0-9]+','avdaabccccc14235453cccccccc')
['14235453']
9. | 或
# 匹配 | 前后的内容
>>> re.findall('ka|sb','kaadbabadsb')
['ka', 'sb']
>>> re.findall('ka|s','kaadbabadsb')
['ka', 's']
>>> re.findall('k|sb','kaadbabadsb')
['k', 'sb']
>>> re.findall('ka|mm','kaadbabadsb')
['ka']
10. \ 转义字符
>>> re.findall('ka\|mm','kaadka|mmdsb')
['ka|mm']
#python解释器先读'ka\\\\mm'会使用两个转义字符变成'ka\\mm',再交给re,再转义一次\,完成匹配或者在
'ka\\mm'之前加r原生字符串,这样python解释器不会转义字符,直接交给re,但要知道交给re的字符串要有两个\
因为re要转义一次
>> re.findall('ka\\\\mm','kaadka\mmdsb')
['ka\\mm']
>>> # \d 匹配任何十进制数,==[0,9]
>>> # \D 匹配任何非数字字符 , ==[^0-9] ^在字符集中表示取反
>>> # \s 匹配任何空白字符 , ==[\t\n\r\f\v]
>>> # \S 匹配任何非空白字符 , ==[^\t\n\r\f\v]
>>> # \w 匹配任何字母数字字符, ==[a-zA-Z0-9]
>>> # \W 匹配任何非字母数字字符, ==[^a-zA-Z0-9]
>>> # \b 匹配特殊字符边界,比如空格、&、@、#
11. () 分组
方法:
1.findall:匹配所有匹配到的,把它们放在一个列表
2.search:只匹配第一个匹配到的,返回一个对象
>>> re.search('(?P<name>[a-z]+)\d+','alxe32wusir34xialv35')
<re.Match object; span=(0, 6), match='alxe32'>
# 显示内容
>>> re.search('(?P<name>[a-z]+)\d+','alxe32wusir34xialv35').group()
'alxe32'
# 注意group()小括号中的分组名要加引号
>>> re.search('(?P<name>[a-z]+)\d+','alxe32wusir34xialv35').group(name)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
re.search('(?P<name>[a-z]+)\d+','alxe32wusir34xialv35').group(name)
NameError: name 'name' is not defined
# 显示指定分组中的内容
>>> re.search('(?P<name>[a-z]+)+(?P<age>\d+)','alxe32wusir34xialv35').group('name')
'alxe'
>>> re.search('(?P<name>[a-z]+)+(?P<age>\d+)','alxe32wusir34xialv35').group('age')
'32'
3.match ,也是返回对象,但只匹配起始
4.split
# 先按a分 ["","sd","bcd"] 再按b分 "","cd"
re.split("[ab]","asdabcd")
['', 'sd', '', 'cd']
5.sub 替换 subn 返回一个元组,后面是匹配的次数
可以有四个参数,最后还可以加一个数字,代表匹配前多少次
>>> re.sub("\d+",'aaa',"beb6876erqeb8687aebqe68ebe8678")
'bebaaaerqebaaaaebqeaaaebeaaa'
>>> re.subn("\d+",'aaa',"beb6876erqeb8687aebqe68ebe8678")
('bebaaaerqebaaaaebqeaaaebeaaa', 4)
6.compile 编译一个规则
>>> com = re.compile("\d+")
>>> com.findall("adkvbaiw3253i4bk2u3h45b2345bh1j3")
['3253', '4', '2', '3', '45', '2345', '1', '3']
7.finditer 同findall 但返回的是一个迭代器
注意:
>>> re.findall("www\.(baidu|163)\.com","www.baidu.com")
['baidu']
>>> re.findall("www\.(baidu|163)\.com","www.163.com")
['163']
>>> # 匹配成功了,但是会优先显示你分组的内容,如果要去掉优先级
>>> re.findall("www\.(?:baidu|163)\.com","www.baidu.com") # ?:要写在分组括号里
['www.baidu.com']
logging 日志
import logging # 导入logging模块
logger = logging.getLogger() # 括号默认为root,可以更改其他用户,但其他用户都为root的子用户,添加子用户的子用户用.连接
logger.setLevel(logging.DEBUG) # 设置记录的级别 debug<info<warning<error<critical
fh = logging.FileHandler("test.log") # 将日志记录到文件
ch = logging.StreamHandler() #将日志记录到窗口,也就是在窗口显示
fm = logging.Formatter("%(asctime)s %(message)s %(lineno)d") 设置日志的格式
"""
forma参数中可能用到的格式化串
%(name) s Logger的名字
%( levels)s数字形式的日志级别
%( cvelname)s文本形式的日志级别
%( pathname)s调用日志输出函数的模块的完整路径名,可能没有
%( filename)s调用日志输出函数的模块的文件名
%( module)s调用日志输出函数的模块名
%( funcName)调用日志输出函数的函数名
%( linen)d调用日志输出函数的语句所在的代码行
%( created)f当前时间,用UNX标准的表示时间的浮点数表示
%( relative Crcated)d输出日志信息时的,自 Logger创建以来的毫秒数
%( asctime)s字符串形式的当前时间。默认格式是“2019-07-31 17:49:57,078”
%( thread)d线程ID,可能没有
%( threadName)s线程名,可能没有
%( proccss)d进程Tb,可能没有
%( message)s用户输出的消息
"""
# 将相关设置写入
fh.setFormatter(fm)
logger.addHandler(fh)
logger.addHandler(ch)
# 打印日志
logger.debug('debug')
logger.info("info")
configparser 读取操作配置文件
# 配置文件格式
[DEFAULT] # 特殊的块,遍历其他块时会跟着遍历
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
import configparser
config = configparser.ConfigParser()
print(config.sections()) # 显示所有的块
config.read('example.ini') # 读取指定配置文件
config.add_section('yuan') # 添加一个块
config.set('yuan','k1','11111') #向新添加的块中添加键值对
config.remove_section('topsecret.server.com') #删除指定块
config.remove_option('bitbucket.org','user') #删除块中的键
hashlib 明文转密文,不可逆
可以对用户输入的用户名和密码进行加密
>>> import hashlib
>>> obj = hashlib.md5()
>>> obj.update("adimin".encode("utf8"))
>>> print(obj.hexdigest())
2c5016600cb36a786fc0be53603fba87
但如果用户输入过于简单,就可以通过撞库解密,所以可以进行 "加盐"
>>> import hashlib
>>> obj = hashlib.md5()
>>> obj.update("yonghushuru".encode("utf8"))
>>> print(obj.hexdigest())
3185b71621a4bbe08f32c942bfbb65a7
>>> obj = hashlib.md5("!@#$".encode("utf8")) # 加盐
>>> print(obj.hexdigest())
3a4d92a1200aad406ac50377c7d863aa
pickle:可以序列化任何对象
爬虫模块requests:
:param method: method for the new :class:`Request` object.
请求类型
:param url: URL for the new :class:`Request` object.
请求的域名
:param params: (optional) Dictionary, list of tuples or bytes to send
in the body of the :class:`Request`.
属性
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the :class:`Request`.
请求的数据
:param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
请求头
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
to add for the file.
:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
:param timeout: (optional) How many seconds to wait for the server to send data
before giving up, as a float, or a :ref:`(connect timeout, read
timeout) <timeouts>` tuple.
:type timeout: float or tuple
:param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
是否重定向:type allow_redirects: bool
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
代理
:param verify: (optional) Either a boolean, in which case it controls whether we verify
the server's TLS certificate, or a string, in which case it must be a path
to a CA bundle to use. Defaults to ``True``.
是否使用证书
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
以流的形式获取response
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
发送证书
HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),
是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1] 。
HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。
HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。
这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面 [2]
https比http安全,就是采用了证书验证,验证的过程是:
1.客户端和服务端在传输数据之前,会通过基于X.509证书对双方进行身份认证 。具体过程如下 [3] :
2.客户端发起 SSL 握手消息给服务端要求连接。
3.服务端将证书发送给客户端。
4.客户端检查服务端证书,确认是否由自己信任的证书签发机构签发。
如果不是,将是否继续通讯的决定权交给用户选择 ( 注意,这里将是一个安全缺陷 )。
如果检查无误或者用户选择继续,则客户端认可服务端的身份。
5.服务端要求客户端发送证书,并检查是否通过验证。
失败则关闭连接,认证成功则从客户端证书中获得客户端的公钥,一般为1024位或者 2048位。
到此,服务器客户端双方的身份认证结束,双方确保身份都是真实可靠的。
简单示例:
自动登录抽屉,无法成功{"code":400,"msg":"非法请求","success":false}
import requests
# response = requests.get('https://dig.chouti.com/')
# print(response.cookies.get_dict()) # 获取cookie
session = requests.Session() # 创建一个session实例,之后每次请求获得cookie等信息都能在下次请求时自动携带
response1 = session.get('https://dig.chouti.com/',
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'},)
User-Agent:将请求伪造成浏览器请求,否则有可能会遭遇防火墙
# 请求数据
request_data = {
"password":"hsiuqwid8q7w68",
"phone":'+8618198098630',
'loginType':2,
'NECaptchaValidate':'erk_NIkYv_9i.R-PIPewBJpM929LESPVgWJGj7qbb5ZAnv0tUh_TvwFpS1zVC_NJCIZy8BNmIBxAqLs2WTMwNKDfRZL8CKl75LGCBA7rkT94ci0P76M_LsOZLkF.lgzH0lTqFskIekFqIMvotKNoTmHFDL152_kkkJ5oE4wic-SOxYKnsPDANMQ6oYrnnaITfviv9hXznApIhOESp-5rUgX99IfcjZBeU6gWg-vRXo2Sb408Tp0hw7vST2IzwCnC0lXQIMYYM_tyBzFQ1v__bDNDiyouV980bpwuWJ4pI-Fj0mg9HTbb8-aeYDnk4GCaRQcQ6o6OK6qNgyW.H-GVn_d75Kr5E72JJ8ULxetfSTabBl0oCyoJv_qI7vytP5TPQrfVsk5bNXpVzH9gZOjQWT52_fl7OalS-0YhJMVmKYAnFiQlF_KFNyOmSYAlvauOSdNKB-MV.AyNjxYd2UaXo92OhgCeBxHcZqp8fSEK6-Cc0rS4ZHQOLapdzOa3'
}
# session的第二次请求,此时会自动携带第一次的cookie
response = session.post(
url='https://dig.chouti.com/login',
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'},
data=request_data
)
print(response.text)