openpyxl知识点补充,pandas模块基础、random模块、subprocess模块、logging模块、练习
openpyxl模块知识补充——读取数据
openpyxl对读取excel文件不是很方便,pandas模块优化了读取的方式
1.查看excel文件中所有工作簿名称
load_workbook.sheetnames
from openpyxl import Workbook,load_workbook
wb = Workbook()
ws1 = wb.create_sheet("学生信息表")
ws2 = wb.create_sheet("学生成绩表")
ws1.append(["姓名","年龄","性别"])
ws1.append(["张三",18,"男"])
ws1.append(["李四",19,"女"])
ws1.append(["老王",20,"男"])
ws1.append(["小黑",23,"男"])
wb.save("学生信息表.xlsx")
wd = load_workbook(r'学生信息表.xlsx')
print(wd.sheetnames) # ['Sheet', '学生信息表', '学生成绩表']
2.查看指定excel文件工作簿的最大行、最大列
worksheet.max_row 、 worksheet.max_column
wd = load_workbook(r'学生信息表.xlsx')
wd1 = wd['学生信息表']
print(wd1) # <Worksheet "学生信息表">
print(wd1.max_row) # 5
print(wd1.max_column) # 3
3.读取特定的值——两种方式
第一种方式:指定位置信息.value 第二种方式:worksheet.cell(行,列).value
wd = load_workbook(r'学生信息表.xlsx')
wd1 = wd['学生信息表']
print(wd1['A1'].value) # 姓名
print(wd1.cell(row = 3,column = 2).value) # 19
4.查看excel文件指定工作簿的所有行、列
worksheet.rows(columns) 用for循环嵌套,用.value读取出来
wd = load_workbook(r'学生信息表.xlsx')
wd1 = wd['学生信息表']
print(wd1.rows) # <generator object Worksheet._cells_by_row at 0x00000255FB87B4C0>
for i in wd1.rows:
# print(i) # (<Cell '学生信息表'.A1>, <Cell '学生信息表'.B1>, <Cell '学生信息表'.C1>)....
print([j.value for j in i ]) # ['姓名', '年龄', '性别'] ['张三', 18, '男']....
for j in wd1.columns:
print(j) # (<Cell '学生信息表'.A1>, <Cell '学生信息表'.A2>, <Cell '学生信息表'.A3>, <Cell '学生信息表'.A4>, <Cell '学生信息表'.A5>)...
print([i.value for i in j]) # ['姓名', '张三', '李四', '老王', '小黑'] # ['年龄', 18, 19, 20, 23]...
pandas模块
pandas模块功能强大,创建excel文件更加简洁方便
import pandas
d = {
'姓名':['张三','李四','老王','小黑'],
"年龄":[18,19,20,23],
"性别":['男','女','男','男']
}
df = pandas.DataFrame(d)
df.to_excel(r"学生信息.xlsx")
网络爬虫实战--爬取链家二手房数据
https://sh.lianjia.com/ershoufang/
import requests
import re
import pandas
res1 = requests.get("https://sh.lianjia.com/ershoufang/")
with open(r'lianjia.html','wb')as f:
f.write(res1.content)
with open(r'lianjia.html','r',encoding='utf8') as f:
data = f.read()
home_title = re.findall('<a class="" href=".*?" target="_blank" data-log_index=".*?" data-el=".*?" data-housecode=".*?" data-is_focus="" data-sl="">(.*?)</a>',data)
home_name = re.findall('<a href=".*?" target="_blank" data-log_index=".*?" data-el=".*?">(.*?) </a>',data)
home_address = re.findall(' - <a href=".*?" target="_blank">(.*?)</a>',data)
home_detail_info = re.findall('<span class="houseIcon"></span>(.*?)</div>',data)
home_follow_info =re.findall('<div class="followInfo"><span class="starIcon"></span>(.*?)</div>',data)
home_all_price =re.findall('<div class=".*?"><i> </i><span class="">(.*?)</span>',data)
home_unit_price = re.findall('<div class=".*?" data-hid=".*?" data-rid=".*?" data-price=".*?"><span>(.*?)</span>',data)
d = {
'标题':home_title,
'小区名称':home_name,
'小区地址':home_address,
'房屋详细信息':home_detail_info,
'房屋收藏信息':home_follow_info,
'房屋单价':home_unit_price,
'房屋总价(万)':home_all_price
}
res = pandas.DataFrame(d)
res.to_excel(r'链家房屋信息.xlsx')
random随机数模块
1.random()
返回0-1之间的随机数
import random
print(random.random()) # 0.49781208840423374
print(random.random()) # 0.2810934030122708
2.randint(a,b)
返回a-b之间的随机整数
import random
print(random.randint(2, 7)) # 5
print(random.randint(2, 7)) # 6
3.choice()
随机抽取容器类型里面的数据值
import random
print(random.choice(['一等奖','二等奖','三等奖'])) # 三等奖
print(random.choice(['一等奖','二等奖','三等奖'])) # 二等奖
4.sample()
随机抽样,自定义抽样的个数
import random
print(random.sample(['A', 'B', 'C', 'D', 'E', 'F', 'G'], 3)) # ['C', 'G', 'B']
print(random.sample(['A', 'B', 'C', 'D', 'E', 'F', 'G'], 3)) # ['B', 'G', 'F']
5.shuffle()
可以将容器类型的数据排列打乱
import random
l1 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A', '大王', '小王']
random.shuffle(l1)
print(l1) # [3, 4, 'Q', 10, 5, 'A', 8, 2, '大王', 6, '小王', 9, 'K', 7, 'J']
random模块实战
编写python代码 产生五位随机验证码(数字、小写字母、大写字母)
import random
code = ''
for i in range(5):
res1 = str(random.randint(0,9))
res2 = chr(random.randint(65,90))
res3 = chr(random.randint(97,122))
num = random.choice([res1,res2,res3])
code += num
print(code) # BY84f
print(code) # bea9P
编写python代码 产生自定义位数的随机验证码(数字、小写字母、大写字母)
import random
def num_code(n):
code = ''
for i in range(n):
res1 = str(random.randint(0,9))
res2 = chr(random.randint(65,90))
res3 = chr(random.randint(97,122))
num = random.choice([res1,res2,res3])
code += num
return code
print(num_code(4)) # fi8a
print(num_code(5)) # jIw2I
print(num_code(6)) # 4X1LX0
hashlib加密模块
1.什么是加密
将明文数据经过处理之后变成密文数据的过程
2.为什么加密
防止隐私泄露
3.如何判断当前数据值是否已经加密
一般情况下,如果是一串没有规则的数字字母符号的组合,一般都是加密之后的结果
4.加密算法:对明文数据采用的加密策略
ps:不同的加密算法复杂程度不一样,得出的结果舱段也不一样
一般加密之后的结果越长,说明采用加密的算法越复杂
5.常见的加密算法:md5、sha系列、hmac、base64
6.加密之后的结果一般情况下不能反解密
ps:所谓的反解密很多时候其实时偷换概念:提前假设别人的密码是什么,然后用过各种算法算出对应的密文,之后构造出对应的关系,然后比对密文,最后映射密文{'密文1':123,'密文2':321,...}
hashlib代码实战
基础练习
import hashlib
m1 = hashlib.md5() # 选择md5加密算法作为数据的加密策略
m1.update(b'123') # 往里面添加明文数据,数据必须是Bytes类型
res = m1.hexdigest() # 获取加密之后的结果
print(res) # 202cb962ac59075b964b07152d234b70
加盐处理
对待加密的明文在加密之前,添加一些干扰的字符串;同时也有动态加盐,即干扰项每一次都不一样,例如每次获取当前的时间、每个用户用户名截取一段
import hashlib
pwd = input("请输入你的银行卡密码>>>:").strip()
m1 = hashlib.md5()
m1.update('中国银行(干扰项)'.encode('utf8'))
m1.update(pwd.encode('utf8'))
res = m1.hexdigest()
print(res) # 21c0b48cc5b84847e4bcdb542d34cceb
补充
只要明文数据是一样的那么采取相同的算法得出的密文肯定一样
import hashlib
m1 = hashlib.md5()
m1.update(b'123')
m1.update(b'ABC')
m1.update(b'dfg')
res = m1.hexdigest()
print(res) # 42cef12be984c329ff47e5a887d17c4c
import hashlib
m1 = hashlib.md5()
m1.update(b'123ABCdfg')
res = m1.hexdigest()
print(res) # 42cef12be984c329ff47e5a887d17c4c
加密实际应用场景
1.用户密码加密:注册存储加密、登陆比对密文
2.文件安全性校验
正规的软件程序写完之后会做一个内容加密;网址提供软件文件记录该文件内容对应的密文;用户下载完毕后不直接运行,而是对下载的内容做加密,然后比对两次密文是否一致。如果一致表示文件没有被改动,可运行;如果不一致,则表示改程序有可能被植入病毒
3.大文件加密优化
例如:程序文件100G,需要加密处理,怎样加密
一般情况,读取100G内容然后全部加密,会运行很慢,所以不对100G所有内容加密,而是截取一部分加密,例如:每隔500M读取30bytes
subprocess模块
subprocess是模拟cmd命令窗口
import subprocess
cmd = input("输入您的指令:>>>").strip()
sub = subprocess.Popen(
cmd,
shell=True,
stdout = subprocess.PIPE,
stderr= subprocess.PIPE
)
# print(sub.stdout.read()) # 二进制的数据
# stdout执行命令之后正确的返回结果
print(sub.stdout.read().decode('gbk'))
# stderr执行命令报错之后返回的结果
print(sub.stderr.read().decode('gbk'))
logging日志模块
简介
1.什么是日志
日志就类似于历史记录
2.为什么要使用日志
为了记录事物发生的事实
3.如何使用日志
3.1 日志等级(5个)
import logging
logging.debug('debug等级') # 10
logging.info('info等级') # 20
logging.warning('warning等级') # 30 默认从warning级别开始记录日志
logging.error('error等级') # 40
logging.critical('critical等级') # 50
>>> WARNING:root:warning等级
>>> ERROR:root:error等级
>>> CRITICAL:root:critical等级
3.2 基本使用
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('你好')
>>> 2022-07-21 18:04:55 PM - root - ERROR -logging模块: 你好
日志模块的组成部分
有logger对象(日志的产生)、filter对象(日志的过滤,可以忽略)、handler对象(日志的产出)、format对象(日志的格式)
import logging
# 1.日志的产生(相当于准备原材料)>>>logger对象
logger = logging.getLogger('购物车记录')
# 2.日志的过滤(剔除不良品)>>>filter对象(可以忽略)
# 3.日志的产出(成品)>>>handler对象
hd1 = logging.FileHandler('a1.log', encoding='utf-8') # 输出a1.log文件中
hd2 = logging.FileHandler('a2.log', encoding='utf-8') # 输出到a2.log文件中
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绑定format对象
hd1.setFormatter(fm1)
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)
# 7.设置日志等级
logger.setLevel(10)
# 8.记录日志
logger.debug('写了半天 好累啊 好热啊')
ps:我们在记录日志的时候,不需要向上述一样全部自己写,过于繁琐,该模块提供了固定的配置字典直接调用即可
日志配置字典
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配置
# '购物车记录': {
# '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注册成功')
实战应用
1.将日志字典放在配置文件内(conf文件夹中的setings.py),因为字典数据时日志模块固定的配置,写完一次之后几乎都不需要动
ps:配置文件中变量名推荐大写
2.将最后记录产生日志的步骤中,封装成函数,放在公共的lib文件夹中的common.py文件中
def get_logger(msg):
# 记录日志
logging.config.dictConfig(settings.LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger(msg)
# logger1.debug(f'{username}注册成功') # 这里让用户自己写更好
return logger1
ps: 有返回值是因为,可以之后更加灵活的添加日志等级
作业
思考链家二手房多页数据如何爬取
# 第一页:https://sh.lianjia.com/ershoufang/pg1/
# 第二页:https://sh.lianjia.com/ershoufang/pg2/
# 第三页:https://sh.lianjia.com/ershoufang/pg3/
# 第一百页:https://sh.lianjia.com/ershoufang/pg100/
import requests
import re
import pandas
base_path = "https://sh.lianjia.com/ershoufang/pg%s/"
for i in range(1,101):
data = requests.get(base_path%i)
res1 = requests.get("https://sh.lianjia.com/ershoufang/")
with open(r'lianjias.html', 'ab')as f:
f.write(res1.content)
with open(r'lianjias.html', 'r', encoding='utf8') as f:
data = f.read()
home_title = re.findall(
'<a class="" href=".*?" target="_blank" data-log_index=".*?" data-el=".*?" data-housecode=".*?" data-is_focus="" data-sl="">(.*?)</a>',
data)
# print(home_title)
home_name = re.findall('<a href=".*?" target="_blank" data-log_index=".*?" data-el=".*?">(.*?) </a>', data)
# print(home_name)
home_address = re.findall(' - <a href=".*?" target="_blank">(.*?)</a>', data)
# print(home_address)
home_detail_info = re.findall('<span class="houseIcon"></span>(.*?)</div>', data)
# print(home_detail_info) # ['2室2厅 | 96.46平米 | 南 北 | 精装 | 中楼层(共6层) | 2007年建 | 板楼']
home_follow_info = re.findall('<div class="followInfo"><span class="starIcon"></span>(.*?)</div>', data)
# print(home_follow_info)
home_all_price = re.findall('<div class=".*?"><i> </i><span class="">(.*?)</span>', data)
# print(home_all_price)
home_unit_price = re.findall('<div class=".*?" data-hid=".*?" data-rid=".*?" data-price=".*?"><span>(.*?)</span>',
data)
# print(home_unit_price)
d = {
'标题': home_title,
'小区名称': home_name,
'小区地址': home_address,
'房屋详细信息': home_detail_info,
'房屋收藏信息': home_follow_info,
'房屋单价': home_unit_price,
'房屋总价(万)': home_all_price
}
res = pandas.DataFrame(d)
res.to_excel(r'链家房屋信息(s).xlsx')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)