the fifth week
目录
正则表达式前戏
while True:
# 1.获取用户输入的手机号
phone_num = input('请输入您的手机号>>>:').strip()
# 2.先判断是否是十一位
if len(phone_num) == 11:
# 3.再判断是否是纯数字
if phone_num.isdigit():
# 4.判断手机号的开头
if phone_num.startswith('13') or phone_num.startswith('15') or phone_num.startswith(
'17') or phone_num.startswith('18') or phone_num.startswith('19'):
print('手机号码输入正确')
else:
print('手机号开头不对')
else:
print('手机号必须是纯数字')
else:
print('手机号必须是11位')
'''python结合正则实现'''
phone_number = input('please input your phone number: ')
if re.match('^(13|14|15|18)[0-9]{9}$', phone_number):
print('是合法的手机号码')
else:
print('不是合法的手机号码')
通过使用正则表达式,可以:
测试字符串内的模式。
例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
替换文本。
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
基于模式匹配从字符串中提取子字符串。
可以查找文档内或输入域内特定的文本
字符组
'''字符组默认匹配方式是挨个挨个匹配'''
[0123456789] 匹配0到9任意一个数(全写)
[0-9] 匹配0到9任意一个数(缩写)
[a-z] 匹配26个小写英文字母
[A-Z] 匹配26个大写英文字母
[0-9a-zA-Z] 匹配数字或者小写字母或者大写字母
ps:字符组内所有的数据默认都是或的关系
特殊符号
'''特殊符号默认匹配方式是挨个挨个匹配'''
. 匹配除换行符以外的任意字符
\w 匹配数字、字母、下划线
\W 匹配非数字、非字母、非下划线
\d 匹配数字
^ 匹配字符串的开头
$ 匹配字符串的结尾
两者组合使用可以非常精确的限制匹配的内容
a|b 匹配a或者b(管道符的意思是或)
() 给正则表达式分组 不影响表达式的匹配功能
[] 字符组 内部填写的内容默认都是或的关系
[^] 取反操作 匹配除了字符组里面的其他所有字符
注意上尖号在中括号内和中括号意思完全不同
量词
'''正则表达式默认情况下都是贪婪匹配>>>:尽可能多的匹'''
* 匹配零次或多次 默认是多次(无穷次)
+ 匹配一次或多次 默认是多次(无穷次)
? 匹配零次或一次 作为量词意义不大主要用于非贪婪匹配
{n} 重复n次
{n,} 重复n次或更多次 默认是多次(无穷次)
{n,m} 重复n到m次 默认是m次
ps:量词必须结合表达式一起使用 不能单独出现 并且只影响左边第一个表达式
jason\d{3} 只影响\d
贪婪和非贪婪
"""所有的量词都是贪婪匹配如果想要变为非贪婪匹配只需要在量词后面加问号"""
待匹配的文本
<script>alert(123)</script>
待使用的正则(贪婪匹配)
<.*>
请问匹配的内容
<script>alert(123)</script> 一条
# .*属于典型的贪婪匹配 使用它 结束条件一般在左右明确指定
待使用的正则(非贪婪匹配)
<.*?>
转义符
"""斜杠与字母的组合有时候有特殊含义"""
\n 匹配的是换行符
\\n 匹配的是文本\n
\\\\n 匹配的是文本\\n
ps:如果是在python中使用 还可以在字符串前面加r取消转义
正则表达式实战建议
1.编写校验用户身份证号的正则
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$
2.编写校验邮箱的正则
\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
3.编写校验用户手机号的正则(座机、移动)
固定电话:[0-9-()()]{7,18}
手机:\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
4.编写校验用户qq号的正则
[1-9]([0-9]{5,11})
re模块
# while 1:
# phone_num=input('请输入您的手机号>>>:').strip()
# if len(phone_num)==11:
# if not phone_num.isdigit():
# print('手机号必须是纯数字')
# if phone_num.startswith('13') or phone_num.startswith('15') or phone_num.startswith(
# '17') or phone_num.startswith('18') or phone_num.startswith('19'):
# print( print('手机号开头不对'))
# print(print('手机号码输入正确'))
#
# print('手机号必须是11位')
#
import re
res=re.findall('a','jason apple eva')
print(res)#['a', 'a', 'a']# 查找所有符合正则表达式要求的数据 结果直接是一个列表
res=re.finditer('a','jason apple eva')
print(res)#<callable_iterator object at 0x000001FBF213C2E0>迭代器对象## 查找所有符合正则表达式要求的数据 结果直接是一个迭代器对象
res=re.search('a', 'jason apple eva')
print(res)#<re.Match object; span=(1, 2), match='a'>
print(res.group())#a
res=re.match('a', 'ason apple eva')
print(res)#None 匹配字符串的开头 如果不符合后面不用看了<re.Match object; span=(0, 1), match='a'>
print(res.group())#a匹配开头符合条件的数据 一个就结束没有匹配到就会报错
obj=re.compile('\d{3}')
res=obj.findall('23423422342342344')
res2 = obj.findall('asjdkasjdk32423')
print(res,res2)
ret=re.split('[ab]','abcd')#先对a分割得到‘’和‘bcd'再对’‘和’bcd‘
print(ret)
ret=re.sub('\d','H','eva3jason4yuan4',2)#将数字替换成'H',参数2表示只替换2个
print(ret)#evaHjasonHyuan4
ret=re.subn('\d','H','eva3jason4yuan4')# 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)#('evaHjasonHyuanH', 3)
re模块补充说明
1.分组优先
import re
res=re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(res)#['oldboy']
res=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
res=res[0]
print(res)#www.oldboy.com
res=re.search('www.(baidu|oldboy).com','www.oldboy.com')
print(res.group())#www.oldboy.com
res=re.match('www.(baidu|oldboy).com','www.oldboy.com')
print(res)#<re.Match object; span=(0, 14), match='www.oldboy.com'>
print(res.group())#www.oldboy.com
2.分组别名
res = re.search('www.(?P<content>baidu|oldboy)(?P<hei>.com)', 'www.oldboy.com')
res1=re.search('www.(?P<content>baidu|oldboy)(?P<hei>.com)','www.baidu.cpm')
print(res.group())#www.oldboy.com
print(res.group('content'))#oldboy
print(res.group(0))#www.oldboy.com 0 代表全部组
print(res.group(1))#oldboy 第一组符合要求的值
print(res.group(2))#.com
print(res.group('hei'))#.com
网络爬虫简介
网络爬虫:通过编写代码模拟浏览器发送请求获取数据并按照自己指定的要求筛选出想要的数据
第三方模块的下载与使用
第三方模块:别人写的模块 一般情况下功能都特别强大
我们如果想使用第三方模块 第一次必须先下载后面才可以反复使用(等同于内置模块)
下载第三方模块的方式
1pip 是 Python 包管理工具,该工具提供了对 Python 包的查找、下载、安装、卸载的功能。
软件包也可以在 https://pypi.org/ 中找到。
目前最新的 Python 版本已经预装了 pip
注意每个解释器都有pip工具 如果我们的电脑上有多个版本的解释器那么我们在使用pip的时候一定要注意到底用的是哪一个 否则极其任意出现使用的是A版本解释器然后用B版本的pip下载模块
为了避免pip冲突 我们在使用的时候可以添加对应的版本号
python27 pip2.7
python36 pip3.6
python38 pip3.8
下载第三方模块的句式
pip install 模块名
下载第三方模块临时切换仓库
pip install 模块名 -i 仓库地址
下载第三方模块指定版本(不指定默认是最新版)
pip install 模块名==版本号 -i 仓库地址
2.pycharm提供快捷方式
"""
下载第三方模块可能会出现的问题
1.报错并有警告信息
WARNING: You are using pip version 20.2.1;
原因在于pip版本过低 只需要拷贝后面的命令执行更新操作即可
d:\python38\python.exe -m pip install --upgrade pip
更新完成后再次执行下载第三方模块的命令即可
2.报错并含有Timeout关键字
说明当前计算机网络不稳定 只需要换网或者重新执行几次即可
3.报错并没有关键字
面向百度搜索
pip下载XXX报错:拷贝错误信息
通常都是需要用户提前准备好一些环境才可以顺利下载
4.下载速度很慢
pip默认下载的仓库地址是国外的 python.org
我们可以切换下载的地址
pip install 模块名 -i 仓库地址
pip的仓库地址有很多 百度查询即可
清华大学 :https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科学技术大学 :http://pypi.mirrors.ustc.edu.cn/simple/
华中科技大学:http://pypi.hustunique.com/
豆瓣源:http://pypi.douban.com/simple/
腾讯源:http://mirrors.cloud.tencent.com/pypi/simple
华为镜像源:https://repo.huaweicloud.com/repository/pypi/simple/
"""
网络爬虫模块之requests模块
Python 内置了 requests 模块,该模块主要用来发 送 HTTP 请求,requests 模块比 urllib 模块更简洁。
requests模块能够模拟浏览器发送网络请求
import requests
# 1.朝指定网址发送请求获取页面数据(等价于:浏览器地址栏输入网址回车访问)
# res = requests.get('http://www.redbull.com.cn/about/branch')
# print(res.content) # 获取bytes类型的网页数据(二进制)
# res.encoding = 'utf8' # 指定编码
# print(res.text) # 获取字符串类型的网页数据(默认按照utf8)
requests 方法
requests 方法如下表:
方法 描述
delete(url, args) 发送 DELETE 请求到指定 url
get(url, params, args) 发送 GET 请求到指定 url
head(url, args) 发送 HEAD 请求到指定 url
patch(url, data, args) 发送 PATCH 请求到指定 url
post(url, data, json, args) 发送 POST 请求到指定 url
put(url, data, args) 发送 PUT 请求到指定 url
request(method, url, args) 向指定的 url 发送指定的请求方法
网络爬虫实战之爬取链家二手房数据
import requests
import re
res = requests.get('https://sh.lianjia.com/ershoufang/pudong/')
# print(res.text)
data = res.text
home_title_list = re.findall(
'<a class="" href=".*?" target="_blank" data-log_index=".*?" data-el="ershoufang" data-housecode=".*?" data-is_focus="" data-sl="">(.*?)</a>',
data)
# print(home_title_list)
home_name_list = re.findall('<a href=".*?" target="_blank" data-log_index=".*?" data-el="region">(.*?) </a>', data)
# print(home_name_list)
home_street_list = re.findall(
'<div class="positionInfo"><span class="positionIcon"></span><a href=".*?" target="_blank" data-log_index=".*?" data-el="region">.*? </a> - <a href=".*?" target="_blank">(.*?)</a> </div>',
data)
# print(home_street_list)
home_info_list = re.findall('<div class="houseInfo"><span class="houseIcon"></span>(.*?)</div>', data)
# print(home_info_list)
home_watch_list = re.findall('<div class="followInfo"><span class="starIcon"></span>(.*?)</div>', data)
# print(home_watch_list)
home_total_price_list = re.findall(
'<div class="totalPrice totalPrice2"><i> </i><span class="">(.*?)</span><i>万</i></div>', data)
# print(home_total_price_list)
home_unit_price_list = re.findall(
'<div class="unitPrice" data-hid=".*?" data-rid=".*?" data-price=".*?"><span>(.*?)</span></div>', data)
# print(home_unit_price_list)
home_data = zip(home_title_list, home_name_list, home_street_list, home_info_list, home_watch_list,
home_total_price_list, home_unit_price_list)
with open(r'home_data.txt','w',encoding='utf8') as f:
for data in home_data:
print(
"""
房屋标题:%s
小区名称:%s
街道名称:%s
详细信息:%s
关注程度:%s
房屋总价:%s
房屋单价:%s
"""%data
)
f.write("""
房屋标题:%s
小区名称:%s
街道名称:%s
详细信息:%s
关注程度:%s
房屋总价:%s
房屋单价:%s\n
"""%data)
自动化办公领域之openpyxl模块
1.excel文件的后缀名问题
03版本之前
.xls
03版本之后
.xlsx
2.操作excel表格的第三方模块
xlwt往表格中写入数据、wlrd从表格中读取数据
兼容所有版本的excel文件
openpyxl最近几年比较火热的操作excel表格的模块
03版本之前的兼容性较差
ps:还有很多操作excel表格的模块 甚至涵盖了上述的模块>>>:pandas
3.openpyxl操作
'''学会看官方文档!!!'''
from openpyxl import Workbook
# 创建一个excel文件
wb = Workbook()
# 在一个excel文件内创建多个工作簿
wb1 = wb.create_sheet('学生名单')
wb2 = wb.create_sheet('舔狗名单')
wb3 = wb.create_sheet('海王名单')
# 还可以修改默认的工作簿位置
wb4 = wb.create_sheet('富婆名单', 0)
# 还可以二次修改工作簿名称
wb4.title = '高富帅名单'
wb4.sheet_properties.tabColor = "1072BA"
# 填写数据的方式1
# wb4['F4'] = 666
# 填写数据的方式2
# wb4.cell(row=3, column=1, value='jason')
# 填写数据的方式3
wb4.append(['编号', '姓名', '年龄', '爱好']) # 表头字段
wb4.append([1, 'jason', 18, 'read'])
wb4.append([2, 'kevin', 28, 'music'])
wb4.append([3, 'tony', 58, 'play'])
wb4.append([4, 'oscar', 38, 'ball'])
wb4.append([5, 'jerry', 'ball'])
wb4.append([6, 'tom', 88,'ball','哈哈哈'])
# 填写数学公式
# wb4.cell(row=1, column=1, value=12321)
# wb4.cell(row=2, column=1, value=3424)
# wb4.cell(row=3, column=1, value=23423432)
# wb4.cell(row=4, column=1, value=2332)
# wb4['A5'] = '=sum(A1:A4)'
# wb4.cell(row=8, column=3, value='=sum(A1:A4)')
# 保存该excel文件
wb.save(r'111.xlsx')
"""
openpyxl主要用于数据的写入 至于后续的表单操作它并不是很擅长 如果想做需要更高级的模块pandas
import pandas
data_dict = {
"公司名称": comp_title_list,
"公司地址": comp_address_list,
"公司邮编": comp_email_list,
"公司电话": comp_phone_list
}
# 将字典转换成pandas里面的DataFrame数据结构
df = pandas.DataFrame(data_dict)
# 直接保存成excel文件
df.to_excel(r'pd_comp_info.xlsx')
excel软件正常可以打开操作的数据集在10万左右 一旦数据集过大 软件操作几乎无效
需要使用代码操作>>>:pandas模块
"""
hashlib加密模块
1.hashlib的简介
hashlib 是一个提供了一些流行的hash(摘要)算法的Python标准库.其中所包括的算法有 md5, sha1, sha224, sha256, sha384, sha512等
hashlib是将明文数据处理成密文数据,让外人无法看懂,保证了数据的安全性。数据加密是把明文数据变成一串没有规律的字符串(数字、字母、符号)。密文越长表示加密算法的过程就越复杂。
2.hashlib的基本操作
import hashlib
md5=hashlib.md5()#选择加密算法
md5.update(b'hello')#传入名问数据
res=md5.hexdigest()#获取加密密文
print(res)#5d41402abc4b2a76b9719d911017c592
sha1=hashlib.sha1()#选择加密算法
sha1.update(b'hello')#传入名问数据
res=sha1.hexdigest()#获取加密密文
print(res)#aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
加密补充说明
1.加密算法不变 内容如果相同 那么结果肯定相同
import hashlib
md5=hashlib.md5()#选择加密算法
md5.update(b'hello word')
res=md5.hexdigest()
print(res)#13574ef0d58b50fab38ec841efe39df4
md5=hashlib.md5()#选择加密算法
md5.update(b'hello ')
md5.update(b'word')
res=md5.hexdigest()
print(res)#13574ef0d58b50fab38ec841efe39df4
2.加密之后的结果是无法反解密的
只能从明文到密文正向推导 无法从密文到明文反向推导
常见的解密过程其实是提前猜测了很多种结果
123 密文
321 密文
222 密文
3.加盐处理
在明文里面添加一些额外的干扰项
md5=hashlib.md5()#加盐处理
md5.update('干扰项'.encode('utf8'))
md5.update(b'hello word')
res=md5.hexdigest()
print(res)#ad4348185523194c41e11f65676e8e24
4.动态加盐
当前时间 用户名的部分 uuid(随机字符串(永远不会重复))
干扰项是随机变化的
import time
md5 = hashlib.md5()
# 把添加时间当作干扰向项
salt = time.time()
salt = str(salt)
md5.update(salt.encode('utf8'))
md5.update('123456'.encode('utf8'))
password = md5.hexdigest()
print(password)
# 46152da37b6d8096cdb144c3ccb6468a
有些所谓的破解密码网站,其实就是把尽可能多的可能输入的明文全部加密一遍,把密文保存起来,用户输入他的密文后,从数据库中找出相同的密文配对,从而判断明文是什么...
5.加密实战操作
1.用户密码加密
2.文件安全性校验
3.文件内容一致性校验
4.大文件内容加密
截取部分内容加密即可
md5 = hashlib.md5()
with open(r'a.txt', 'rb') as f:
for line in f:
md5.update(line)
real_data = md5.hexdigest()
print(real_data) # 29d8ea41c610ee5d1e76dd0a42c7e60a
with open(r'a.txt', 'rb') as f:
for line in f:
md5.update(line)
error_data = md5.hexdigest()
print(error_data) # 738a56b49f24884ba758d1e4ab6ceb74
import os
# 读取文件总大小
res = os.path.getsize(r'a.txt')
# 指定分片读取策略(读几段 每段几个字节) 10 f.seek()
read_method = [0, res // 4, res // 2, res]
# 用f.read(10)读取十个字符
# 读取到最后的位置时需要把光标往前移动
subprocess模块
import subprocess
res=subprocess.Popen(
'ipconfig ',#操作系统执行的指令
shell=True,#固定配置
stdin=subprocess.PIPE,#输入指令
stdout=subprocess.PIPE,#输出指令
)
print('正确结果',res.stdout.read().decode('gbk'))
print('错误结果',res.stderr)
正确结果
Windows IP 配置
logging日志模块
1如何理解日志
简单的理解为是记录行为举止的操作
2日志的级别
五种级别
debug:可以帮助我们在平时的开发过程中,帮助我们查看一些输出的信息是否正确。它可以替代我们平时使用的 print() 函数。
info:它代表了一般的消息类信息,只是为了记录一些程序的行为,比如程序执行到了某个位置,进行一些简单的记录。
warnning:该等级是一种警告,一般来说程序不会出错,但是可能存在一定的潜在风险。
error:一般对应业务中出现了重大问题。比如异常或者业务逻辑不应该执行到某种情况。我们都可以通过error来进行记录。
critical:比 error 更严重的级别,不过一般来说 error 级别已经很严重了,所以 critical 很少使用。
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
eg:
import logging
logging.debug('debug message')
logging.info('info message')
#只有高于info级别的日志bug才会显示
logging.warning('warning message')#WARNING:root:warning message
logging.error('error message')#ERROR:root:error message
logging.critical('critical message')#CRITICAL:root:critical message
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf8',)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
logging.error('我在这等你呢')
日志的组成
1.产生日志
2.过滤日志
3.输出日志
4.日志格式
import logging
logger=logging.getLogger('购物车记录')#1日志的产生
hd1=logging.FileHandler('a1.log',encoding='utf8')#输出到文件
hd2=logging.FileHandler('a2.log',encoding='utf8')#输出到文件
hd3=logging.StreamHandler()# 输出到终端
fm1=logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)#日志的格式(包装)
fm2 = logging.Formatter(
fmt='%(asctime)s - %(name)s: %(message)s',
datefmt='%Y-%m-%d',
)
logger.addHandler(hd1)#给logger对象绑定handler对象
logger.addHandler(hd2)
logger.addHandler(hd3)
hd1.setFormatter(fm1)#给handler绑定formmate对象
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)
logger.setLevel(10)#debug
logger.debug('略略略')
#2022-10-27 17:27:13 PM - 购物车记录 - DEBUG -333: 略略略
#2022-10-27 - 购物车记录: 略略略
日志配置字典
import logging
import logging.config
standard_format='[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]'
simple_format='[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
logfile_path='a3.log'
LOGGING_DIC={
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {}, # 过滤日志
'handlers': {
# 打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024 * 1024 * 5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
# logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '购物车记录': {
# 'handlers': ['default','console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
logging.config.dictConfig(LOGGING_DIC)
logger1=logging.getLogger('消费记录')
logger1.debug('啦啦啦')
#[2022-10-27 18:51:12,860][MainThread:13832][task_id:消费记录][333.py:140][DEBUG][啦啦啦]
#[DEBUG][2022-10-27 18:51:12,860][333.py:140]啦啦啦