python学习笔记
今日内容概要
- openpyxl模块读数据
- 爬取链家二手房数据
- random随机数模块
- hashlib加密模块
- subprocess模块
- 日志模块
今日内容详细
openpyxl模块读数据
# openpyxl读写数据使用的模块不一样
from openpyxl import Workbook, load_workbook
wb = load_workbook(r'111.xlsx',data_only=True) # 读取名为111.xlsx的文件
print(wb.sheetnames) # 查看excel文件中所有的工作簿名称
wb1 = wb['红浪漫消费记录'] # 获取表红浪漫消费记录
print(wb1.max_row) # 表的最大行数
print(wb1.max_column) # 表的最大列数
# 方式一:
print(wb1['A1'].value) # 位于A1位置的数据
# 方式二:
print(wb1.cell(row=2, column=2).value) # 位于第二行第二列位置的数据
# 循环获取每一行的数据
for i in wb1.rows:
print([j.value for j in i]) # ['username', 'gender', 'age']
# 循环获取每一列的数据
for j in wb1.columns:
print([i.value for i in j]) # ['username', 'jason', 'kevin', 'tony', None]
"""
openpyxl不擅长读数据 所以有一些模块优化了读取的方式
pandas模块
一层层优化(站在巨人的肩膀上!!!)
"""
# 封装了openpyxl的pandas模块操作excel表格的方式
import pandas
d = {
'公司名称': ['老男孩', '老女孩', '老伙计', '老北鼻'],
'公司地址': ['上海', '深圳', '杭州', '东京'],
'公司电话': [120, 130, 129, 996],
}
df = pandas.DataFrame(d)
df.to_excel(r'222.xlsx')
爬取链家二手房数据
import requests
res = requests.get('https://sh.lianjia.com/ershoufang/')
# 仅仅只能获取一页数据 爬虫知识点也是很多的 没你想的那么简单
with open(r'lj.html','wb') as f:
f.write(res.content)
with open(r'lj.html', 'r', encoding='utf8') as f:
data = f.read()
# 1.研究目标数据 筛选
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
)
home_name_list = re.findall(
'<a href=".*?" target="_blank" data-log_index=".*?" data-el="region">(.*?) </a>',
data
)
home_addr_list = re.findall(
' - <a href=".*?" target="_blank">(.*?)</a>',
data
)
home_info_list = re.findall(
'<div class="houseInfo"><span class="houseIcon"></span>(.*?)</div>',
data
)
home_others_list = re.findall(
'<div class="followInfo"><span class="starIcon"></span>(.*?)</div>',
data
)
home_total_price = re.findall(
'<div class="totalPrice totalPrice2"><i> </i><span class="">(.*?)</span><i>万</i></div>',
data
)
home_unit_price = re.findall(
'<div class="unitPrice" data-hid=".*?" data-rid=".*?" data-price=".*?"><span>(.*?)</span></div>',
data
)
d = {
'房屋标题':home_title_list,
'小区名称':home_name_list,
'所在街道':home_addr_list,
'具体信息':home_info_list,
'其他信息':home_others_list,
'房屋总价':home_total_price,
'房屋单价':home_unit_price
}
df = pandas.DataFrame(d)
df.to_excel(r'333.xlsx')
random随机数模块
方法 | 作用 |
---|---|
random | 返回0到1之间随机的小数 |
randint(a,b) | 用于声场一个指定范围内的整数。其中,参数a是下限,b是上限,生成的随机数n:a<=n<=b |
choice(seq) | 从非空序列 seq 返回一个随机元素。 如果 seq 为空,则引发 IndexError |
sample(seq,k) | 从指定序列中随机获取K长度的片段。不会修改原有的序列 |
shuffle(x) | 将序列 x 随机打乱位置 |
- random实战
def get_code(n): # n传入几就是几位数的验证码
code = '' # 定义全局变量用于存储所有的验证码
# 编写python代码 产生五位随机验证码(数字、小写字母、大写字母)
for i in range(n):
# 每次循环都应该产生 数字 小写字母 大写字母
random_int = str(random.randint(0, 9)) # 随机产生一个数字
random_lower = chr(random.randint(97, 122)) # 随机产生一个小写字母
random_upper = chr(random.randint(65, 90)) # 随机产生一个大写字母
# 从上述三个数据值中随机挑选一个作为验证码的一位数据
temp = random.choice([random_int, random_lower, random_upper])
code += temp # 拼接字符串
return code
res = get_code(5)
print(res)
hashlib加密模块
- 1.什么是加密
将明文数据(看得懂)经过处理之后变成密文数据(看不懂)的过程
- 2.为什么要加密
不想让敏感的数据轻易的泄露
- 3.如何判断当前数据值是否已经加密
一般情况下如果是一串没有规则的数字字母符合的组合一般都是加密之后的结果
- 4.加密算法
就是对明文数据采用的加密策略,不同的加密算法复杂度不一样,得出的结果长短也不一样
通常情况下加密之后的结果越长 说明采用的加密算法越复杂
- 5.常见加密算法
md5 sha系列 hmac base64
- 6.代码实参
import hashlib
md5 = hashlib.md5() # 选择md5加密算法作为数据的加密策略
md5.update(b'123') # 往里面添加明文数据 数据必须是bytes类型
res = md5.hexdigest() # 获取加密之后的结果
print(res) # 202cb962ac59075b964b07152d234b70
- 7.补充说明
1.加密之后的结果一般情况下不能反解密
202cb962ac59075b964b07152d234b70
"""
所谓的反解密很多时候其实是偷换概念
提前假设别人的密码是什么 然后用各种算法算出对应的密文
之后构造对应关系 然后比对密文 最终映射明文
{'密文1':123,'密文2':321,...}
"""
2.只要明文数据是一样的那么采用相同的算法得出的密文肯定一样
import hashlib
md5 = hashlib.md5() # 选择md5加密算法作为数据的加密策略
md5.update(b'123') # 往里面添加明文数据 数据必须是bytes类型
md5.update(b'hello') # 往里面添加明文数据 数据必须是bytes类型
md5.update(b'jason') # 往里面添加明文数据 数据必须是bytes类型
res = md5.hexdigest()
print(res) # 31b9a81dc788368469ee4b78877eb1eb
md5.update(b'123hellojason')
res = md5.hexdigest()
print(res) # 31b9a81dc788368469ee4b78877eb1eb
3.加盐处理(salt)
password = input('password>>>:').strip()
md5.update('公司设置的盐(干扰项)'.encode('utf8'))
md5.update(password.encode('utf8'))
res = md5.hexdigest()
print(res) # 78bf5bd131c520b54168206d75f9f9be
4.动态加盐(salt)
干扰项每次都不一样
eg:每次获取当前时间 每个用户用户名截取一段
5.加密实际应用场景
1.用户密码加密
注册存储密文 登录也是比对密文
2.文件安全性校验
正规的软件程序写完之后做一个内容的加密
网址提供软件文件记忆该文件内容对应的密文
用户下载完成后不直接运行 而是对下载的内容做加密
然后比对两次密文是否一致 如果一致表示文件没有被改
不一致则表示改程序有可能被植入病毒
3.大文件加密优化
程序文件100G
一般情况下读取100G内容然后全部加密 太慢
不对100G所有的内容加密 而是截取一部分加密
eg:每隔500M读取30bytes
subprocess模块
模拟计算机cmd命令窗口
import subprocess
cmd = input('请输入您的指令>>>:').strip()
sub = subprocess.Popen(cmd, # 在终端运行的命令
shell=True, # 新开一个终端
stdout=subprocess.PIPE, # 执行完命令, 将正确输出放到一个管道里
stderr=subprocess.PIPE # 将错误输出放到一个管道里
)
# stdout执行命令之后正确的返回结果
print(sub.stdout.read().decode('gbk')) # 拿到的是 bytes 格式的字符,在windows需要使用gbk编码,linux和mac上是"utf-8"
# stderr执行命令报错之后的返回结果
print(sub.stderr.read().decode('gbk')) # 拿到的是 bytes 格式的字符,在windows需要使用gbk编码,linux和mac上是"utf-8"
日志模块
日志模块需要你写的代码很少 几乎都是CV
- 1.什么是日志
日志就类似于是历史记录
- 2.为什么要使用日志
为了记录事物发生的事实(史官)
- 3.如何使用日志
日志等级 | 用处 | 数字记录 |
---|---|---|
debug等级 | 可以帮助我们在平时的开发过程中,帮助我们查看一些输出的信息是否正确,它可以替代我们平时使用的 print() 函数 | 10 |
info等级 | 它代表了一般的消息类信息,只是为了记录一些程序的行为,比如程序执行到了某个位置,进行一些简单的记录 | 20 |
warning等级 | 该等级是一种警告,一般来说程序不会出错,但是可能存在一定的潜在风险(默认从warning级别开始记录日志) | 30 |
error等级 | 一般对应业务中出现了重大问题。比如异常或者业务逻辑不应该执行到某种情况,我们都可以通过error来进行记录 | 40 |
critical等级 | 比 error 更严重的级别,不过一般来说 error 级别已经很严重了, 所以 critical 很少使用 | 50 |
# 基本使用
import logging
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
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('我不好!!!')
- 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('写了半天 好累啊 好热啊')
"""
我们在记录日志的时候 不需要向上述一样全部自己写 过于繁琐
所以该模块提供了固定的配置字典直接调用即可
"""
- 5.日志配置字典
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('购物车记录')
logger1.warning('尊敬的VIP客户 晚上好 您又来啦')
- 6.实战应用
# 按照软件开发目录规范编写使用
日志字典数据应该放在哪个py文件内
字典数据是日志模块固定的配置 写完一次之后几乎都不需要动
它属于配置文件
"""配置文件中变量名推荐全大写"""
该案例能够带你搞明白软件开发目录规范中所有py文件的真正作用
def get_logger(msg):
# 记录日志
logging.config.dictConfig(settings.LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger(msg)
# logger1.debug(f'{username}注册成功') # 这里让用户自己写更好
return logger1
- 作业
import re
import requests
import pandas
base_url = 'https://sh.lianjia.com/ershoufang/pg%s/'
for i in range(1, 10):
url = base_url % i
print(url)
res = requests.get(url) # 朝目标地址发送网络请求获取响应数据(相当于在浏览器地址栏中输入网址并回车)
# 仅仅只能获取一页数据
with open(rf'lj{i}.html', 'ab') as f:
f.write(res.content) # 获取bytes类型的数据保存页面数据到文件
with open(r'lj.html', 'r', encoding='utf8') as f:
data = f.read() # 读取lj.html文件
# 1.研究目标数据 筛选
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
)
home_name_list = re.findall(
'<a href=".*?" target="_blank" data-log_index=".*?" data-el="region">(.*?) </a>',
data
)
home_addr_list = re.findall(
' - <a href=".*?" target="_blank">(.*?)</a>',
data
)
home_user_list = re.search(
'<div class="houseInfo"><span class="houseIcon"></span>(.*?)</div>',
data
)
home_others_list = re.findall(
'<div class="followInfo"><span class="starIcon"></span>(.*?)</div>',
data
)
home_total_price = re.findall(
'<div class="totalPrice totalPrice2"><i> </i><span class="">(.*?)</span><i>万</i></div>',
data
)
home_unit_price = re.findall(
'<div class="unitPrice" data-hid=".*?" data-rid=".*?" data-price=".*?"><span>(.*?)</span></div>',
data
)
d = {
'房屋标题': home_title_list,
'小区名称': home_name_list,
'所在街道': home_addr_list,
'具体信息': home_user_list,
'其他信息': home_others_list,
'房屋总价': home_total_price,
'房屋单价': home_unit_price
}
df = pandas.DataFrame(d)
df.to_excel(r'333.xlsx')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了