正则表达式前戏
正则表达式是用来匹配与查找字符串的,从网上爬取数据自然或多或少会用到正则表达式,python的正则表达式要先引入re模块,正则表达式以r引导
案例:手机号校验
基本要求:手机号必须是11位、手机号必须是 13 15 17 18 19开头、必须是纯数字
'''纯python代码实现'''
while True:
# 获取用户输入手机号
phone_num = input('请输入您的手机号>>>:').strip()
# 判断是否是11位
if len(phone_num) == 11:
# 判断是否是纯数字
if phone_num.isdigit():
# 判断手机号的开头
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('请输入您手机号')
if re.match('^(13|14|15|18|19)[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.编写校验邮箱的正则
/^[a-zA-Z0-9_.-]+@[a-zA-Z0- 9-]+(\\.[a-zA-Z0-9-]+)*\.[a- zA-Z0-9]{2,6}$/
3.编写校验用户手机号的正则(座机、移动)
^1[3|4|5|7|8][0-9]{9}$
4.编写校验用户qq号的正则
[1-9]([0-9]{5,11})
re模块
在python中如果想要使用正则 可以考虑re模块
findall方法
# findall方法,该方法在字符串中查找模式匹配,将所有的匹配字符串以列表的形式返回,如果文本中没有任何字符串匹配模式,则返回一个空的列表,
# 如果有一个子字符串匹配模式,则返回包含一个元素的列表,所以,无论怎么匹配,我们都可以直接遍历findall返回的结果而不会出错,这对工程师
# 编写程序来说,减少了异常情况的处理,代码逻辑更加简洁
finditer方法
# finditer返回一个迭代器,遍历迭代器可以得到一个SRE_Match对象
search方法
# search方法,模式匹配成功后,也会返回一个SRE_Match对象,search方法和match的方法区别在于match只能从头开始匹配,而search可以从
# 字符串的任意位置开始匹配,他们的共同点是,如果匹配成功,返回一个SRE_Match对象,如果匹配失败,返回一个None,这里还要注意,
# search仅仅查找第一次匹配,也就是说一个字符串中包含多个模式的匹配,也只会返回第一个匹配的结果,如果要返回所有的结果,最简单
# 的方法就是findall方法,也可以使用finditer方法
group方法
# 匹配到一个符合的数据就立刻结束
match方法
#匹配字符串的开头 如果不符合后面不用看了
compile方法
#将指定的正则表达式模式编译为正则表达式对象,可用于匹配和搜索
split方法
# 按照能够匹配的子串讲字符串分割后返回列表
sub方法
#re.sub(pattern, repl, string, count=0, flags=0)
# 参数:
# pattern : 正则中的模式字符串。
# repl : 替换的字符串,也可为一个函数。
# string : 要被查找替换的原始字符串。
# count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
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.分组别名
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工具
pip3 install 模块名 # 不知道版本默认是最新版
pip3 install 模块名==版本号 # 指定版本下载
pip3 install 模块名 -i 仓库地址 # 临时切换
'''命令行形式永久修改需要修改python解释器源文件'''
方式2:
pycharm快捷方式
settings
project
project interprter
双击或者加号
点击右下方manage管理添加源地址即可
下载完第三方模块之后 还可以使用 import 或 from import句式导入使用
我们可以切换下载的仓库
1.阿里云 http://mirrors.aliyun.com/pypi/simple/
2.豆瓣 http://pypi.douban.com/simple/
3.清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
4.中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
5.华中科技大学http://pypi.hustunique.com/
报错解决措施
1.报错并有警告信息
WARNING: You are using pip version 20.2.1;
原因:是pip版本过低
解决措施:拷贝后面的命令执行更新
2.报错的提示信息中含有关键字timeout
原因:网络不稳定
解决措施:再次尝试或者切换更加稳定的网络
3.没有任何关键字 不同的模块报不同的错
原因:模块需要特点的计算机环境
解决措施:拷贝报错信息使用百度、浏览器搜索
网络爬虫模块之requests模块
爬虫就是编写程序,模拟浏览器发送请求,然后服务端把数据响应给我,然后我再对响应的数据做解析,拿到我想要的那一小部分,这就是整个爬虫过程
get请求
# 请求路径
import requests
# 朝指定网址发送请求获取页面数据
res = requests.get('http://www.redbull.com.cn/about/branch')
print(res.content) # 获取bytes类型的网页数据(二进制)
res.encoding = 'utf8' # 指定编码
print(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文件的版本及后缀
2003版本之前 excel的文件后缀是xls
2003版本之后 excel的文件后缀是xlsx、csv
2.操作excel表格的第三方模块
xlwt往表格中写入数据、wlrd从表格中读取数据
兼容所有版本的excel文件
openpyxl最近几年比较火热的操作excel表格的模块
03版本之前的兼容性较差
ps:还有很多操作excel表格的模块 甚至涵盖了上述的模块 >>>:pandas
openpyxl操作
新建excel .批量创建工作簿
import openpyxl as vb
local=r'E:ETL平台gina_loop.xlsx'# 指定文件路径
wb=vb.Workbook()#新建EXECL文档
for i in range(1,11,2):#创建10个工作表,2是步长
wb.create_sheet('2021年2月'+ str(i) +'日')#i是数 字,需转换为字符串
wb.save(local)
在一个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"
打开一个excel文件
from openpyxl import load_workbook
wb2 = load_workbook('文件名称.xlsx')
删除工作薄
import openpyxl as vb
local=r'E:ETL平台gina_loop.xlsx'# 指定文件路径
wb=vb.load_workbook(local)
print(wb.sheetnames)
for i in wb:
print(i.title.split("-"))
if i.title.split("-")[0]=='上海':#split("-") 用-进行分隔,分隔后 从0开始 上海-2021年 , ['上海','2021年']
wb.remove(wb[i.title])
wb.save(local)
wb.close()
获取值单元格值
import openpyxl as vb
local=r'E:ETL平台gina_area.xlsx'# 指定文件路径
local11=r'E:ETL平台gina_area_copy.xlsx'# 指定文件 路径
wb=vb.load_workbook(local11)
ws=wb['2021年2月1日']
for i in range(1,10,1):
print(i,ws.cell(row=i,column=2).value)
print(ws['A1'].value)
hashlib加密模块
1.何为加密
将文明数据处理成密文数据 让人无法看懂
2.为什么要加密
保证数据的安全,防止密码泄露
3.如何判断数据是否加密
密文数据的表现形式一般都是一串没有规则的字符串(数字、字母、符号)
4.加密算法
将明文变成密文的内部规则,算法的难易程度可以根据产生密文的长短来判断,越长越复杂
5.常见的加密算法有:md5、base64、hmac、sha系列
使用方法
import hashlib
# 使用指定算法——md5算法
md5 = hashlib.md5()
# 将明文数据传递给算法对象,并且直接接受bytes类型
md5.update(b'hello world') # 如果字符串是纯数字和英文,那么直接在前面加b转变成bytes类型
# 获取加密数据
res = md5.hexdigest()
print(res)
加密补充说明
1.加密算法不变 内容如果相同 那么结果肯定相同
# md5.update(b'hello~world~python~666') # 一次 性传可以
md5.update(b'hello') # 分多次传也可以
md5.update(b'~world') # 分多次传也可以
md5.update(b'~python~666') # 分多次传也可以
2.加密之后的结果是无法直接反解密的
md5解密内部本质
提前想好很多可能是密码的组合
123 自己加密
321 自己加密
222 自己加密
{'密文1':123,'密文2':321}
3.加盐处理(增加破解的难度)
在明文里面添加一些额外的干扰项
# 1.选择加密算法
md5 = hashlib.md5()
# 2.传入明文数据
md5.update('公司设置的干扰项'.encode('utf8'))
md5.update(b'hello python') # 一次性传可以
# 3.获取加密密文
res = md5.hexdigest()
print(res)
4.动态加盐(用来干扰动态变化)
干扰项是随机变化的
可以是用户名的一部分、也可以是当前的时间
加密的应用场景
'''
1.密码加密如何比对
用户输入的还是明文但是到了程序里面就会采用相同的加密算法变成 密文——然后对数据库里面的密文进行比对,如果一致就是正确,不 一致就是错误
2.文件内容一致性校验
在提供安全软件的同时,会对给该内容做加密处理得到一个该安全软 件独有的密文
用户在下载软件之后也会对内容做相同的加密比对两次密文是否一致
如果一致,那就表示中途没有被修改, 如果不一致那就表示中途被 修改、可能会存在病毒
'''
subprocess模块
subprocess是python内置的模块,这个模块中的Popen可以查看用户输入的命令行是否存在
存在:把内容写入到stdout管道中
不存在:把信息写入到stderr管道
'''需要注意的是,这个模块的返回结果只能让开发者看一次,如果想多次查看,需要在第一次输出的时候,把所有信息写入到变量中'''
popen用法
import subprocess
r = subprocess.Popen('asdas', # 操作系统要执行的命令
shell=True, # 固定配置
stdin=subprocess.PIPE, # 输入命令
stdout=subprocess.PIPE, # 输出结果
)
print('正确结果', r.stdout.read().decode('gbk')) # 获取操作系统执行命令之后的正确结果
print('错误结果', r.stderr) # 获取操作系统执行命令之后的错误结果
logging日志模块
日志是一种可以卓总某些软件运行时所发生事情的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可包含可选变量数据的消息来描述。此外,时间也有重要性的概念,这个重要性也可以被称为严重性级别(level)。
日志的等级
级别 | 何时使用 |
---|---|
DEBUG | 详细信息,典型地调试问题时会感兴趣 详细的debug信息 |
INFO | 证明事情按预期工作 关键事件 |
WARNING | 表明发生了一些意外,或者不久的将来会发生问题 软件还是在正常工作 |
ERROR | 由于更严重的问题,软件已不能执行一些共嗯那个 一般错误消息 |
CRITICAL | 严重错误,表明软件已不能继续运行了 |
NOTICE | 不是错误,但是可能需要处理。普通但是重要的时事件 |
ALERT | 需要立即修复,例如系统数据库损坏 |
EMERGENCY | 紧急情况,系统不可用(例如系统崩溃),一般会通知所有用户 |
logging用法
import logging
logging.debug("this is s debug message")
logging.info("this is a info message")
logging.warning("this is a warning message")
logging.error("this is a error message")
logging.critical("this is a critical message")
# 这里只显示warning及以上的日志
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('写了半天 好累啊')
日志配置字典
# 核心就在于CV
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'
# 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配置
},
}
# 使用配置字典
logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger('xxx')
logger1.debug('好好的 不要浮躁 努力就有收获')
项目开发流程
1.项目需求分析
产品经理(客户) 架构师 开发经理
1.架构师 开发经理提前构思大致方案
2.引导客户提出合理要求(避免不合理的请求)
3.记录会议内容
2.项目架构设计
架构师
1.项目编程语言
2.项目整体框架
框架、数据库服务
3.项目报价
3.项目分组开发
架构师 开发经理 程序员
1.任务拆分开发
4.项目提交测试
1.程序员自己要提前测试一下
2.测试部门专门测试(扣绩效)
5.项目交付上线
1.运维人员负责即可
项目需求分析
该项目的核心不仅在于引领初学者快速入门python项目开发,更是站在项目架构的角度教你如何在程序开发之初合理且优雅地设计程序的架构,从而极大地提升程序的开发效率与可扩展性
"""
- 额度15000或自定义
- 支持多账户登录
- 可以查看账户余额
- 可以提现(可自定义手续费比例)
- 提供还款接口
- 支持账户间转账
- 记录每月日常消费流水
- 实现购物商城,买东西加入购物车,调用信用卡接口结账
- 提供管理接口,包括添加账户、用户额度,冻结账户等
- ATM记录操作日志
- 用户认证功能
"""
1.注册功能
2.登录功能
3.查看余额
4.提现功能
5.充值功能
6.转账功能
7.查看流水
8.添加购物车
9.结算购物车
10.管理员功能
10.1.冻结账户
10.2.删除账户
项目架构设计(重点)
以实际项目为例讲解三层架构设计
百度
以百度登录功能为例 分析执行步骤
1.在浏览器页面上获取用户名和密码
2.基于网络发送给百度服务端
3.服务端连接数据库服务
淘宝
以淘宝买商品为例 分析执行步骤
1.浏览器页面展示商品总价
2.基于网络发送给淘宝服务端再次计算总价
3.调用数据库服务完成金额操作
"""
第一层:只做数据展示和简单的数据获取
cmd终端、浏览器页面、手机app页面
第二层:真正的核心业务逻辑处理(代码)
编写代码的py文件、目录、框架
第三层:数据操作
文件读写操作、py文件、数据库软件
"""
ATM架构设计
三层架构
core目录下的src.py(浏览器)
interface目录下的多个py文件(框架)
db目录下db_handler.py(数据库服务)
项目目录搭建
软件开发目录规范
标签:总结,匹配,res,第五,内容,home,print,logging,日志 From: https://www.cnblogs.com/oiqwyig/p/16842907.html