一.模块初识
- 模块的分类
- 内置模块
- 安装python解释器的时候跟着装上的那些方法
- 第三方模块
- 没在安装怕python解释器的时候安装的那些功能
- 自定义功能
- 自己写的功能是一个通用的功能,可以当作是一个模块
- 内置模块
- 模块的定义
- 有的功能开发者自己无法完成,这样的话需要借助已经实现的函数/类来完成这些功能
- 自己实现不了的功能由别人代替了
- 比如:和操作系统打交道
- 和时间
- 随机数
- 压缩一个文件
- 和网络通信
- 别人写好的一组功能–> 文件夹/py文件/c语言编译好的一些编译文件
- 模块的好处
- 分类 管理方法
- 节省内存
- 提供更多的功能
- 为什么要有模块?
- 分类, 管理方法
- 节省内存
- 提供更多的功能
- 模块的创建和导入
# 自定义模块,模块的创建
# py文件名-->my_module
print('这是我的模块')
name = 'alex'
def login():
print('这是一个登录函数')
# 模块的导入
import my_module # 要导入一个py文件的名字,但是不加.py后缀名
# 模块的名字必须要满足变量的命名规范
# 一般情况下,模块都是小写字母开头的名字
# import这个模块相当于执行了这个模块所在的py文件
# 模块不会被多次导入
# 模块的使用
my_module.login()
print(my_module.name) # 直接调用导入进来模块的方法以及属性等等
# 模块的重命名
import my_module as m # 语法 import 模块名 as 新名字
m.login()
print(m.name)
# 导入多个模块
import os
import my_module
# PEP8规范
# 所有的模块导入都应该尽量放在这个文件的开头
# 模块的导入也是有顺序的
# 先导入内置模块
# 再导入第三方模块
# 最后导入自定义模块
- from_import
- from import的时候执行了什么??
- 想当于执行了整个py文件
- 导入了什么,就能是有什么, 不导入的变量, 不能使用
- 不导入并不意味着不存, 而是没有建立文件到模块中其他名字的引用
- 当模块中的方法或者变量 和 文件重名时, 那么这个名字只代表最后一次对他赋值的那个
- 在本文件中对全局变量的修改是完全不影响模块中的变量引用的
- from import的时候执行了什么??
- 模块的重命名
from module1 import login as l1
- 导入多个重命名
from module1 import login as l1, name as l2
- from 模块 import *
__all__ = ['age'] #可以控制*导入的东西,这里只表示导入age
name = 'alex'
age = 19
def login():
print('in my login')
def asd():
print('in my asd')
if __name__ == '__main__': # 所有测试语句方法在里面,在导入模块之后,执行脚本的时候就不会自动执行
login()
asd()
from module1 import * # *表示导入模块中所有的变量和方法
print(age)
# print(name)
# asd()
# login()
pyc编译文件
- python的执行 —> 解释-编译
- 当一个文件作为一个脚本被导入的时候
- 就会在这个文件所在的目录的_ _ pycache _ _下生成一个编译好的文件
- 为了之后导入这个文件的时候直接读这个编译好的pyc文件
- 可以节省一些导入的时间
运行一个py 文件的两中方式
- 以模块的形式运行
import my_module
if __name__ == '__main__':
my_module.login()
直接pycharm运行 cmd运行
1. 就是以脚本的方式运行 2. 那么需要在本文件中直接打印的代码上加上 3. if _ _ name _ _ = ['_ _ main _ _'] 4. 在编写py文件的时候 1. 所有不在函数和类中封装的内容都应该写在 2. if _ _ name _ _ = ['_ _ main _ _'] : 下面import sys import module1 print(sys.modules) # 结果是: 存储了所有导入的文件的名字和这个文件的内存地址 {sys : 文件的内存地址,'__main__' : 当前执行文件所在的地址} # 再次使用反射反射自己模块中的内容的时候 import sys print(getattr(sys.modules[__name__], 'name'))
模块搜索路径
- 模块没导入之前是在硬盘上的
- 模块的搜索路径全部存储在sys.path列表中
- 导入模块的顺序,是从前到后找到一个符合条件的模块就立即停止不再向后寻找
- 如果要导入的模块和当前执行文件是同级目录
- 直接导入即可
- 如果要导入的模块和当前执行的文件不是同级
- 需要吧导入的模块的绝对路径添加到sys.path 列表中
重新加载模块
- 在import之后 再修改这个被导入的模块, 程序是感知不到的
- reload这种方法可以强制程序再重新导入这个模块一次(非常不推荐使用)
import module1
import time
import importlib
module1.login()
time.sleep(20)
importlib.reload(module1) # 表示重新加载
module1.login()
- 模块的循环使用
- 在模块的导入中, 不要产生循环引用问题
- 如果发生循环导入了, 就会发现明明写在这个模块中的方法, 显示找不到
二.包
- 导入包相当于执行了这个包下面的 _ _ init _ _ 方法
- 可以设 _ _ init _ _方法来完成一些模块的导入
- 如果直接导入一个包, 那么相当于执行了这个包中的_ _ init _ _文件,并不会帮你把这个包下面的其他包以及py文件自动的导入到内存
# import bbb.api.policy
# bbb.api.policy.get()
import bbb.api.policy as a1
a1.get()
绝对导入和相对导入
在glance/api/version.py #绝对导入 from glance.cmd import manage manage.main() #相对导入 from ..cmd import manage manage.main()
三.正则表达式
定义: 就是一种匹配字符串的规则
应用: 登录注册的表单验证,爬虫,自动化开发, 日志分析
正则表达式是一种独特的语法,和python没有关系
- 字符组 []
- 在一个字符的位置上能出现的内容
- [1abc] 是一个范围
- [0-9] [A-Z] [a-z] 表示匹配三个字符
- [abc0-9] 表示匹配一个字符
- [0-9a-zA-Z] 表示匹配一个字符
- [^] 非字符组
- 元字符
- \d == [0-9] 也表示匹配一个字符, 匹配的是一个数字
- \w == [0-9a-zA-Z] 也表示匹配一个数字字母下划线
- \s == [\n \t] 包括回车 空格 和 制表符tab \n匹配回车 \t 匹配制表符
- \D 匹配非数字
- \W 匹配非数字字母下划线
- \S 匹配非空白
- \b 匹配单词的开始或结束
- | 或者的意思
- () 分组的意思
- ^ 匹配字符串的开始
- & 匹配字符串的结束
- . 除了换行符的所有
- [\d\D] [\w\W] [\s\S] 匹配所有
- 量词
- ? 重复0次或者一次(也就是可有可无)
- +重复1次或者更多次(1~多次)
- *重复0次或者更多次(0~多次)
- {n} 重复n次
- {n,} 重复至少n次
- {n,m} 重复n到m次
- 其他
- 贪婪匹配(回溯算法) 尽可能的匹配多的
- 量词? 表示惰性匹配也就是取消贪婪匹配
- ?? *? +? {n}?
- 最常用 .*?x 表示任意字符找到一个x
- 正则表达式的例子
1.匹配任意长度的正整数
[1-9]\d*
2.匹配小数
-?\d+\.\d+
3.匹配整数或者小数
-?\d+\.?\d* 有缺陷 1. 2. 这样的内容也会匹配上
-?\d+\.?\d+ 有缺陷 1 2 这样的一位数就匹配不上了
-?\d+(\.\d+)? 准确的
4.匹配负数
-0\.\d+|-[1-9]\d*(\.\d+)?
5.匹配qq号
[1-9]\d{5,11}
6.匹配长度为11位的电话号码
1[3-9]\d{9}
7.匹配长度为8-10位的用户密码 包含数字字母下划线和?@
[\w?@]{8,10}
8.匹配验证码,4位数字字母组成的
[\da-zA-Z]{4}
9.1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
匹配出最内层的小括号
\([\d\.+\-*/]+\)
\([^()]+\)
6.转义符
1.正则表达式中的转义
‘\ (‘ 表示转义小括号
# [()+*?/$.] 在字符组中一些特殊的字符会现出原形
# 所有的 \w \d \s(\n,\t, ) \W \D \S都表示它原本的意义
# [-]只有写在字符组的首位的时候表示普通的减号
# 写在其他位置的时候表示范围[1-9]
# 如果就是想匹配减号 [1\-9]
2.python中的转义
# 分析过程
'\n' # \转义符 赋予这个n一个特殊的意义 表示一个换行符
# print('\\n')
# print\\n('C:\\next')
# print(r'C:\next')
# '\\\\n' '\\n'
# 结论
# r'\\n' r'\n' 在python中
四.re模块
1.匹配
findall 和 search match
import re
# findall
# print(re.findall('\d', 'asdf23'))
# 参数 返回值类型(列表),返回值个数(1) 返回值内容:所有匹配上的内容
# search
ret = re.search('\d+', "afasdf1231adf212") # 返回值类型: 正则匹配结果的对象 返回值个数:1 如果匹配上了就返回对象
print(ret.group()) # 返回的对象是通过group 来获取匹配到的第一个结果
如果没有匹配上,结果就是None
# match
ret1 = re.match('\d+', '*&1231afasdf1231adf212') # 只匹配前面出现的,不然会报错
print(ret1.group())
2.替换
sub 和 subn
# sub 和 replace是一样的
print(re.sub('\d+', 'H', '123FSDF52FSF1'))
# subn 会打印你替换了的次数
print(re.subn('\d+', 'H', '123FSDF52FSF1'))
结果:('HFSDFHFSFH', 3)
3.切割
split
print(re.split('\d+', '123faaf23'))
# 会把数字不打印
# 结果是个列表 ['', 'faaf', '']
4.进阶方法
compile(时间效率) 和 finditer(空间效率)
# compile 起到一个预编译的作用,只有多次使用某一个相同的正则表达式的时候,compile才会提高我们程序的效率
ret = re.compile('-0\.\d+|-[1-9]+(\.\d+)?')
res = ret.search('asdf-0.01-99')
print(res.group())
# finditer
ret = re.finditer('\d', 'adfad12fasdf123') # 返回的是一个迭代器
print(ret)
for i in ret:
print(i.group())
5.python中的正则表达式
1.findall 会优先显示分组中的内容,要想取消分组优先,(?:正则表达式)
2.split 遇到分组 会保留分组内被切掉的内容
3.search 如果search中有分组的话,通过group(n)就能够拿到group中的匹配的内容
ret = re.findall('-0\.\d+|-[1-9]\d*(?:\.\d+)?', '-1asdada-200')
print(ret)
ret = re.split('(\d+)','alex83egon20taibai40')
print(ret)
# 分组遇见search
ret = re.search('\d+(.\d+)(.\d+)(.\d+)?','1.2.3.4-2*(60+(-40.35/5)-(-4*3))')
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))
6. 分组命名
1. (?P< name > 正则表达式) 表示给分组起名字
2. (?P=name) 表示使用这个分组,这里匹配到的内容应该和分组中的内容完全相同
7. 通过索引使用分组
1. \1 表示使用第一组, 匹配到的内容和分组中的内容完全相同
import re
# ret=re.findall(r"\d+(?:\.\d+)?","1-2*(60+(-40.35/5)-(-4*3))")
# print(ret)
# ret=re.findall(r"\d+(?:\.\d+)|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
# print(ret)
# ret.remove('')
# print(ret)
import re
# ret = re.findall('>(\w+)<',r'<a>wahaha<\a>')
# print(ret)
# ret = re.search(r'<(\w+)>(\w+)</(\w+)>',r'<a>wahaha</b>')
# print(ret.group())
# print(ret.group(1))
# print(ret.group(2))
分组命名
ret = re.search("<(?P<name>\w+)>\w+</(?P=name)>","<h1>hello</h1>")
print(ret.group('name')) #结果 :h1
# print(ret.group()) #结果 :<h1>hello</h1>
ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")
print(ret.group(1))
# print(ret.group()) #结果 :<h1>hello</h1>
ret = re.search(r'<(?P<tag>\w+)>(?P<c>\w+)</(\w+)>',r'<a>wahaha</b>')
print(ret.group())
print(ret.group('tag'))
print(ret.group('c'))
五.爬虫练习
import re
from urllib.request import urlopen
# 内置的包,来获取网页的源代码 字符串
def getPage(url):
reponse = urlopen(url)
return reponse.read().decode('utf-8')
def parsePage(s):
ret = com.finditer(s)
for i in ret:
ret = {
"id": i.group("id"),
"title": i.group("title"),
"rating_num": i.group("rating_num"),
"comment_num": i.group("comment_num")
}
yield ret
def main(num):
url = 'https://movie.douban.com/top250?start=%s&filter=' % num
reponse_html = getPage(url)
ret = parsePage(reponse_html)
print(ret)
f = open('info1',encoding='utf-8')
for obj in ret:
print(obj)
data = str(obj)
f.write(data, '\n')
f.close()
com = re.compile(
'<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
'.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)
count = 0
for i in range(10):
main(count)
count += 25
六.验证码代码
# 验证码
import random
def rand_code(n=6, flag=True):
code = ''
for i in range(n):
rand_num = str(random.randint(0, 9))
if flag == True:
rand_alph = chr(random.randint(97, 122)) # 是根据ASCLL 表 获取小写字母,97-127(a-z)
rand_alph_upper = chr(random.randint(65, 90)) # 是根据ASCLL表 获取大写字母 65-90(A-Z)
rand_num = random.choice([rand_num, rand_alph, rand_alph_upper])
code += rand_num
return code
ret = rand_code(flag=False)
print(ret)