正则表达式前戏
案例:京东注册手机号校验
基本需求:手机号必须是11位、手机号必须以13 15 17 18 19开头、必须是纯数字
'''纯python代码实现'''
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结合正则实现'''
import re
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{13,16}[0-9x]$
^[1-9]\d{14}(\d{2}[0-9x])?$
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$
2.编写校验邮箱的正则
3.编写校验用户手机号的正则(座机、移动)
4.编写校验用户qq号的正则
'''很多时候 很多问题 前人已经弄好了 你只需要花点时间找一找就可以'''
ps:能够写出简单的正则 能够大致看懂复杂的正则
re模块
在python中如果想要使用正则 可以考虑re模块
import re
# 常见操作方法
# res = re.findall('a', 'jason apple eva')
# print(res) # 查找所有符合正则表达式要求的数据 结果直接是一个列表
# res = re.finditer('a', 'jason apple eva')
# print(res) # 查找所有符合正则表达式要求的数据 结果直接是一个迭代器对象
# 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', 'jason apple eva')
# print(res) # None 匹配字符串的开头 如果不符合后面不用看了
# print(res.group()) # 匹配开头符合条件的数据 一个就结束
# obj = re.compile('\d{3}') # 当某一个正则表达式需要频繁使用的时候 我们可以做成模板
# res1 = obj.findall('23423422342342344')
# res2 = obj.findall('asjdkasjdk32423')
# print(res1, res2)
ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret) # ['', '', 'cd']
ret = re.sub('\d', 'H', 'eva3jason4yuan4', 1) # 将数字替换成'H',参数1表示只替换1个
print(ret) # evaHjason4yuan4
ret = re.subn('\d', 'H', 'eva3jason4yuan4') # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret) # ('evaHjasonHyuanH', 3)
re模块补充说明
1.分组优先
# res = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
# print(res) # ['oldboy']
# findall分组优先展示:优先展示括号内正则表达式匹配到的内容
# res = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
# 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.group()) # www.oldboy.com
2.分组别名
res = re.search('www.(?P<content>baidu|oldboy)(?P<hei>.com)', 'www.oldboy.com')
print(res.group()) # www.oldboy.com
print(res.group('content')) # oldboy
print(res.group(0)) # www.oldboy.com
print(res.group(1)) # oldboy
print(res.group(2)) # .com
print(res.group('hei')) # .com
第三方模块的下载与使用
第三方模块就是别人写的模块 一般情况下功能都特别强大
如果想使用第三方模块 第一次必须先下载之后才可以反复使用 等同于内置模块
1.pip工具下载
每个计时器都有pip工具 如果电脑上有多个版本的解释器 那么在使用pip工具下载的时候一定要注意到底使用的是哪一个 否则机器容易出现使用的是A版本解释器 然后用的是B版本的pip工具下载的模块
为了避免pip冲突 在使用的时候可以添加对应的版本号
python27 pip2.7
python36 pip3.6
python38 pip3.8
下载第三方模块的句式
pip install 模块名
下载第三方模块时临时切换仓库
pip install 模块名 -i 仓库地址
下载第三方模块时指定版本(不指定默认下载最新版)
pip install 模块名==版本号
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 仓库地址
清华大学 :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模块
requests模块能够模拟浏览器发送网络请求
import requests
res = requests.get()
# 括号内填写网址 朝指定网址发送请求获取页面数据(等价于浏览器地址栏输入网址回车访问)
res.content # 获取bytes类型的网页数据(二进制)
res.encoding = 'utf8' # 指定编码
res.text # 获取字符串类型的网页数据(默认按照utf8)
网络爬虫实战之爬取链家二手房数据
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表格的第三方模块
zlwt往表格中写入数据 xlrd 从表格中读取数据
兼容所有版本的excel文件
openpyxl最近几年比较火热的操作excel表格的模块
不兼容03版本之前的excel文件 兼容性狡差
ps还有很多操作excel表格的模块 甚至涵盖了上述的模块>>>:pandas
openpyxl操作
'''学会看官方文档
百度模块名 纯英文的就是官网
'''
from openpyxl import Workbook
wb = Workbook() # 创建一个excel文件
wb1 = wb.create_sheet('高富帅名单')
# 在excel文件内创建工作簿 括号内填工作簿名
wb2 = wb.create_sheet('富婆名单', 0)
# 还可以修改默认工作簿位置
wb2.title = '富婆通讯录' # 二次修改工作簿名称
wb2.sheet_properties.tabColor = "1072BA" # 修改工作簿颜色
# 添加数据方式1
wb1['A1'] = 'jason'
# 添加数据方式2
wb1.cell(row=2, column=1, value='18')
# 添加数据方式3
wb1.append(['编号', '姓名', '年龄', '爱好'])
wb1.append([1, 'jason', '18', 'read'])
# 填写数学公式
wb2.cell(row=1, column=1, value=111)
wb2.cell(row=2, column=1, value=222)
wb2.cell(row=3, column=1, value=333)
wb2.cell(row=4, column=1, value=444)
wb2['A5'] = '=sum(A1:A4)'
wb2.cell(row=8, column=3, value='=sum(A1:A4)')
# 保存excel文件
wb.save(r'a.xlsx')
'''
openpyxl主要用于数据的写入 至于后续的表单操作它并不是很擅长 如果想做需要更高级的模块pandas
excel软件正常可以打开操作的数据集在10万左右 一旦数据集过大 软件操作几乎无效 需要使用代码操作>>>:pandas模块
'''
hashlib加密模块
1.何为加密
将明文数据处理成密文数据 让人无法看懂
2.为什么要加密
保证数据的安全
3.如何判断数据是否是加密的
一串没有规律的字符串(数字、字母、符号)
4.密文的长短有何讲究
密文越长表示使用的加密算法(数据处理过程)越复杂
5.常见的加密算法有哪些
md5、base64、hmac、sha系列
6.加密算法基本操作
import hashlib
md5 = hashlib.md5() # 选择加密算法 可以通过点的方式点出其他算法
md5.update(b'hello') # 传入明文数据 数据是二进制形式
res = md5.hexdigest() # 获取加密密文
print(res) # 打印密文 5d41402abc4b2a76b9719d911017c592
加密补充说明
1.加密算法不变 内容如果相同 那么结果肯定相同
md5.update(b'hello~world') # 可以一次性传完
md5.update(b'hello')
md5.update(b'~world') # 也可以分多次传
# 最终的加密结果都是一样的
2.加密之后的结果是无法反解密的
只能从明文到密文正向推导 无法从密文到明文反向推导
常见的解密过程其实是提前猜测了很多种结果
3.加盐处理
在明文里面添加了一些额外的干扰项
# 1.选择加密算法
md5 = hashlib.md5()
# 2.传入明文数据
md5.update('公司设置的干扰项'.encode('utf8'))
md5.update(b'hello python') # 一次性传可以
# 3.获取加密密文
res = md5.hexdigest()
print(res) # e53024684c9be1dd3f6114ecc8bbdddc
4.动态加盐
干扰项是随机变化的
如:当前时间、用户名部分...
5.加密的应用方向
用户密码加密
文件安全性校验
文件内容一致性校验
大文件内容加密 # 截取部分内容加密即可
subprocess模块
模拟操作系统终端 执行命令并获取结果
import subprocess
res = subprocess.Popen(
'ipconfig', # 操作系统要执行的命令
shell=True, # 固定配置
stdin=subprocess.PIPE, # 输入命令
stdout=subprocess.PIPE, # 输出结果
)
print('正确结果', res.stdout.read().decode('gbk')) # 获取操作系统执行命令之后的正确结果 默认结果是二进制 可以通过编码转换
print('错误结果', res.stderr) # 获取操作系统执行命令之后的错误结果
logging日志模块
1.如何理解日志
简单的理解为是记录行为举止的操作(历史史官)
2.日志的级别
日志一共分成5个等级,从低到高分别是:
DEBUG 详细的信息,通常只出现在诊断问题上
INFO 确认一切按预期运行
WARNING 个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如。磁盘空间低”)。这个软件还能按预期工作。
ERROR 更严重的问题,软件没能执行一些功能
CRITICAL 一个严重的错误,这表明程序本身可能无法继续运行
3.日志模块要求
代码无需掌握 但是得会CV并稍作修改
import logging
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
# 1.日志的产生(准备原材料) logger对象
logger = logging.getLogger('购物车记录')
# 2.日志的过滤(剔除不良品) filter对象>>>:可以忽略 不用使用
# 3.日志的产出(成品) handler对象
hd1 = logging.FileHandler('a1.log', encoding='utf-8') # 输出到文件中
hd2 = logging.FileHandler('a2.log', encoding='utf-8') # 输出到文件中
hd3 = logging.StreamHandler() # 输出到终端
# 4.日志的格式(包装) format对象
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',
)
# 5.给logger对象绑定handler对象
logger.addHandler(hd1)
logger.addHandler(hd2)
logger.addHandler(hd3)
# 6.给handler绑定formmate对象
hd1.setFormatter(fm1)
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)
# 7.设置日志等级
logger.setLevel(10) # debug
# 8.记录日志
logger.debug('写了半天 好累啊 好热啊')
日志配置字典
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]' # 其中name为getlogger指定的名字
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.warning('尊敬的VIP客户 晚上好 您又来啦')
# logger1 = logging.getLogger('注册记录')
# logger1.debug('jason注册成功')
logger1 = logging.getLogger('红浪漫顾客消费记录')
logger1.debug('慢男 猛男 骚男')