目录
- 一、购物车
- 二、hashlib模块
- 三、子进程模块subprocess模块
- 四、logging日志模块
- 五、关于python第三方模块的简介
- 六、requests模块-网络爬虫模块
- 七、openpyxl模块-自动化办公
一、购物车
import os
import json
"构建记录用户登录的字典"
is_login = {'username': ''}
"由于都用到了这部分代码,可以将其放在全局中使用"
# 4 获取用户名文件路径
base_path = os.path.dirname(__file__)
db_path = os.path.join(base_path, 'db')
# 5 如果没有db文件路径,则创建
if not os.path.exists(db_path):
os.mkdir(db_path)
"校验用户登录状态的装饰器"
def login_auth(func_name):
def inner(*args, **kwargs):
# 执行函数前增加的新功能
if not is_login.get('username'):
print('您未登录,请先登录')
login()
res = func_name(*args, **kwargs)
return res
return inner
def register():
# 3 添加循环
while True:
# 1 获取用户输入
username = input('请输入用户名:').strip()
if username == 'q':
break
password = input('请输入密码:').strip()
confirm_pwd = input('请确认密码:').strip()
# 2 判断密码是否正确
if not password == confirm_pwd:
print('您的密码不一致,重新输入')
continue
# 6 拼接用户文件路径
user_file_path = os.path.join(db_path, f'{username}.json')
# 7 判断用户文件路径是否存在
if os.path.exists(user_file_path):
print('该用户名已经被注册过')
continue
# 8 不存在则新建用户文件
user_data_dict = {
'username': username,
'password': password,
'balance': 133333,
'shop_car': {}
}
with open(user_file_path, 'w', encoding='utf8') as f:
json.dump(user_data_dict, f)
print(f'用户{username}您好,您已经注册成功')
break
def login():
while True:
# 1 获取用户输入
username = input('请输入用户名:').strip()
if username == 'q':
break
# 2 获取用户文件路径,判断路径是否存在
user_file_path = os.path.join(db_path, f'{username}.json')
# 3 判断用户名文件是否存在,不存在则未注册
if not os.path.exists(user_file_path):
print('您的用户名未注册')
continue
password = input('请输入您的密码:').strip()
# 4 获取用户真实字典
with open(user_file_path, 'r', encoding='utf8') as f:
user_data_dict = json.load(f)
if not password == user_data_dict.get('password'):
print('密码错误,重新输入')
continue
# 5 登录成功,记录登录的状态,在全局中建立登录状态字典
is_login['username'] = username
print(f'用户{username}您好登录成功')
break
"""
使用3、4功能要判断用户登录状态,
可以构建装饰器,来为3、4功能函数增加判断是否登录的功能
"""
@login_auth
def add_shop_car():
# 8 构建临时小字典,存放添加的商品信息
temp_good_list = {}
while True:
# 1 获取商品信息,循环打印输出给用户
good_list = [
['kfc', 3],
['芦笋烤鹅肝', 22],
['酸奶', 666],
['抹茶拿铁', 999],
['战斧牛排', 1000],
['仰望星空派', 2000],
['鸡哥陪玩', 10000]
]
for num, g_data in enumerate(good_list):
print(f"商品编号:{num} | 商品名称:{g_data[0]} | 商品单价:{g_data[1]}")
# 2 获取用户输入,想要的商品编号
choice_good_num = input('请输入您想要的商品编号:').strip()
"10 获取结束条件,保存商品信息"
if choice_good_num == 'q':
# 11 获取真实用户字典
user_file_path = os.path.join(db_path, f'{is_login.get("username")}.json')
with open(user_file_path, 'r', encoding='utf8') as f:
user_data_dict = json.load(f)
# 12 获取旧购物车
old_shop_car = user_data_dict.get('shop_car')
# 13 循环获得原购物车中的商品信息
for g_name, g_list in temp_good_list.items():
if g_name in old_shop_car:
old_shop_car[g_name][0] += temp_good_list[g_name][0]
else:
old_shop_car[g_name] = g_list
# 14 将改过的购物车写入用户文件
user_data_dict['shop_car'] = old_shop_car
with open(user_file_path, 'w', encoding='utf8') as f:
json.dump(user_data_dict, f)
print('添加商品成功')
break
# 3 判断商品编号是否是纯数字
if not choice_good_num.isdigit():
print('商品编号必须是纯数字')
continue
# 4 判断输入编号是否在商品编号内
choice_good_num = int(choice_good_num)
if choice_good_num not in range(len(good_list)):
print('您输入的编号不存在')
continue
# 5 获取此时商品的信息
now_good_list = good_list[choice_good_num] # ['仰望星空派', 2000]
# 6 获取商品数量
good_num = input('请输入商品数量:').strip()
# 7 判断商品数量是否是纯数字
if not good_num.isdigit():
print('商品数量必须是纯数字')
continue
good_num = int(good_num)
# 9 判断商品名字是否在临时小字典内
good_name = now_good_list[0] # ['仰望星空派', 2000]
if good_name in temp_good_list: # temp_good_list ={'仰望星空派': [11, 2000]}
temp_good_list[good_name][0] += good_num
else:
temp_good_list[good_name] = [good_num, now_good_list[1]]
@login_auth
def pay_shop_car():
# 1 获取用户文件内的信息
user_file_path = os.path.join(db_path, f'{is_login.get("username")}.json')
# 2 读取用户文件信息
with open(user_file_path, 'r', encoding='utf8') as f:
user_data_dict = json.load(f)
# 3 获取真实购物车
shop_car = user_data_dict.get('shop_car')
# 4 判断购物车是否为空
if not shop_car:
print('您的购物车为空,请先添加商品')
return
# 5 统计价格
total_money = 0
for g_list in shop_car.values():
total_money += g_list[0] * g_list[1]
# 6 获取当前余额
curreent_balance = user_data_dict.get('balance')
# 7 判断余额和总价
if total_money > curreent_balance:
print('余额不足,请先充值')
return
user_data_dict['balance'] -= total_money
# 8 清空购物车
user_data_dict['shop_car'] = {}
# 9 写入文件
with open(user_file_path, 'w', encoding='utf8') as f:
json.dump(user_data_dict, f)
print(f'用户{is_login.get("username")}结算成功,消费{total_money},余额为{user_data_dict.get("balance")}')
# 记录功能编号的字典
func_num_dict = {
'1': register,
'2': login,
'3': add_shop_car,
'4': pay_shop_car
}
# 循环获取字典,调用函数功能
while True:
print("""
1:注册功能
2:登陆功能
3:添加购物车功能
4:结算购物车功能
""")
choice_func_num = input('请输入想使用的功能编号:').strip()
if choice_func_num not in func_num_dict:
print('您选择的功能编号不存在,重新输入')
else:
func_num_dict.get(choice_func_num)()
二、hashlib模块
hashlib模块中含有很多的加密算法,可以将不同的明文数据通过不同的算法转换成不同的长度的密文,通常以16进制的字符串来表示加密后的密文。
1.加密的含义,如何理解加密
当一串字符我们无法看懂,其中又包括了数字、字母、符号的时候,就有可能是加密处理后的密文。加密的操作可以保证数据的安全,防止数据泄露后造成损失。
关于密文,相同的明文再加密后如果其密文结果越长,就说明其算法越复杂,其安全性也越高。
2.常见的加密算法
md5、 base64、hmac、sha系列等等
2.加密算法的基本使用
三步:1)选择加密算法
2)传入明文数据
3)获取加密密文
# 案例
import hashlib # 导入hashlib加密模块
1.选择加密算法
x = hashlib.md5() # 选择加密算法为md5
2.传入明文数据
1)一次传入明文
# 用update关键字传入明文,选择解码模式是 utf8
x.update('你好我好大家好,广州好迪'.encode(encoding='utf8'))
2)多次传入相同明文
x1.update('你好我好大家好'.encode('utf8'))
x1.update(','.encode('utf8'))
x1.update('广州好迪'.encode('utf8'))
3)获取加密密文
res = x.hexdigest() # 用关键字hexdigest获取密文,并用一个变量名接收返回的结果
print(res) # d7ceedfa09a76805da2a2830a1764360
res1 = x1.hexdigest()
print(res1) # d7ceedfa09a76805da2a2830a1764360
"只要选择的算法相同,传入相同的明文,加密后的结果也是相同的"
3.加密补充说明
1.加密算法不变如果传入的明文相同,加密后的密文也想相同
2.加密之后的结果是无法反解密的
一般所谓的解密都是通过撞库来进行所谓的返解密的,并非破解加密算法
3.加盐处理和动态加盐处理
1)加盐处理:在明文中加入固定的干扰项,使得传入的明文更加的复杂,增加密文的复杂性,防止撞库而得到明文
import hashlib
md5 = hashlib.md5()
md5.updata(b'公司干扰项', encoding='utf8') # 添加干扰项,防止明文过于简单
md5.update(b'hello~world~python')
res = md5.hexdigest()
2)动态加盐:干扰项是随机变化的,防止干扰项被泄露后用户数据被撞库匹配到明文
动态干扰项常用的有:当前时间、用户名的部分字符...这样使得这些加盐处理之后的密文更加安全,难以撞库匹配
4.加密操作的用处
1 对用户密码加密
2 文件安全性校验
3 文件内容一致性校验
4 大文件校验
5.优秀hash算法的特性
正向快速:给定明文和 hash 算法,在有限时间和有限资源内能计算出 hash 值。
逆向困难:给定(若干) hash 值,在有限时间内很难(基本不可能)逆推出明文。
输入敏感:原始输入信息修改一点信息,产生的 hash 值看起来应该都有很大不同。
冲突避免:很难找到两段内容不同的明文,使得它们的 hash 值一致(发生冲突)。即对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。
三、子进程模块subprocess模块
模拟操作系统,执行命令并获取结果
subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
import subprocess
# Popen 是 subprocess的核心,子进程的创建和管理都靠它处理。
res = subprocess.Popen( # 激活终端
'asdas', # 操作系统要执行的命令
shell=True, # 固定配置
stdin=subprocess.PIPE, # 输入命令
stdout=subprocess.PIPE, # 输出结果
)
print('正确结果', res.stdout.read().decode('gbk')) # 获取操作系统执行命令之后的正确结果
print('错误结果', res.stderr) # 获取操作系统执行命令之后的错误结果
Windows系统的编码默认中文系统是gbk编码
MacOS终端默认情况下字符以UTF-8编码,终端中输入locale查看默认编码
四、logging日志模块
1.如何理解日志
日志可以理解为是记录数据行为的文件,它可以帮助我们来快速定位问题。
2.日志的级别
日志的级别,从上往下重要程度依次提高,日志模块的默认日志等级上warning,低于warning等级的日志信息都不会在终端中显示出来。
1.debug
logging.debug('debug message')
2.info
logging.info('info message')
3.warning
logging.warning('warning message')
4.error
logging.error('error message')
5.critical
logging.critical('critical message')
3.日志的组成
1.产生日志
logger日志记录器,每个记录器都有一个名称,直接使用logging模块来记录日志时,该模块会默认创建
2.过滤日志
剔除不良品,在日志阶段就可以控制想要的日志内容
3.输出日志
handler处理器,记录器负责产生日志,而处理器则负责日志最终的输出,存放成日志文件。
4.日志格式
formatter格式器,格式器可以以对象的形式设置在handler上,格式器可以指定日志的输出格式,比如展示时间、时间格式、日志的级别、展示记录器的名字等等,都可以通过一个格式器对消息进行格式化输出。
Python内置了很多实用的处理器,常用的有:
1、StreamHandler 标准流处理器,将消息发送到标准输出流、错误流
2、FileHandler 文件处理器,将消息发送到文件
3、RotatingFileHandler 文件处理器,文件达到指定大小后,启用新文件存储日志
4、TimedRotatingFileHandler 文件处理器,日志以特定的时间间隔轮换日志文件
import logging
# 1.日志的产生(准备原材料) logger对象
logger = logging.getLogger('购物车记录')
# 2.日志的过滤(剔除不良品)基本不用,在日志生产阶段就可以控制想要什么样的日志内容
# 3.日志的输出(成品) handler对象
hd1 = logging.FileHandler('a1.log',encoding='utf8') # 输出到文件中
hd2 = logging.FileHandler('a2.log',encoding='utf8') # 输出到文件中
hd3 = logging.StreamHandler() # 输出到终端
# 4.日志的格式(包装) formatter对象
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 20-info 30-warning 40-error 50-critical
# 8.记录日志
logger.debug('日志内容日志内容')
五、关于python第三方模块的简介
第三方模块是技术大佬写的模块,功能很多
1.下载第三方模块的方式
1.1 pip工具
注意每个解释器都有pip工具,如果我们的电脑上有多个版本的解释器那么我们在使用pip的时候一定要注意到底用的是哪一个 否则极其任意出现使用的是A版本解释器然后用B版本的pip下载模块
(1) 为了避免pip冲突 我们在使用的时候可以添加对应的版本号,如
python27 pip2.7
python36 pip3.6
python38 pip3.8
(2)下载第三方模块的句式
pip install 模块名
(3)下载第三方模块临时切换仓库
pip install 模块名 -i 仓库地址
(4)下载第三方模块指定版本(不指定默认是最新版)
pip install 模块名==版本号 -i 仓库地址
pip install 模块名==版本号 -i 仓库地址
1.2 pycharm提供的下载方式
2.下载第三方模块可能会出现的问题
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模块-网络爬虫模块
1.小练习:获取宏牛网站的分公司信息
# 思路
1.直接拷贝网友源代码数据保存到本地
2.在pycharm中读取文件当作字符串处理
3.编写正则表达式来筛选我们想要的内容
import re
# 1.文件操作读取文本内容
with open(r'redbull.html', 'r', encoding='utf8') as f:
# 2 直接读取全部内,将全部内容绑定变量名data
data = f.read()
# 3 研究各部分数据的特征,编写相应的正则表达式
# <h2>红牛杭州分公司</h2><p class='mapIco'>杭州市上城区庆春路29号远洋大厦11楼A座</p><p class='mailIco'>310009</p><p class='telIco'>0571-87045279/7792</p></li><li
"方法1:一次性获取每个公司全部的数据"
# res = re.findall(
# "<h2>(.*?)</h2><p class='mapIco'>(.*?)</p><p class='mailIco'>(.*?)</p><p class='telIco'>(.*?)</p></li><li", data)
#
# print(res)
"方法2:分步分挨个获取最后统一整合"
title_list = re.findall("<h2>(.*?)</h2>", data)
# print(title_list)
"""
['红牛杭州分公司', ... ,'红牛金丽衢代表处']
"""
address_list = re.findall("<p class='mapIco'>(.*?)</p>", data)
mail_list = re.findall("<p class='mailIco'>(.*?)</p>", data)
telephone_list = re.findall("<p class='telIco'>(.*?)</p>", data)
# 4 (处理信息)得到了公司名称、公司地址、公司邮编、公司电话这些信息的列表后,我们需要将其一一对应起来组合
res = zip(telephone_list, address_list, mail_list, telephone_list)
# print(list(res))
# [('0571-87045279/7792', '杭州市上城区庆春路29号远洋大厦11楼A座', '310009', '0571-87045279/7792')...]
# 5 将其写入txt文件中
with open(r'redbull.txt', 'w', encoding='utf8') as f:
# 6 添加for循环,可以格式化输出
for data_tuple in res:
print(
"""
公司名称:%s
公司地址:%s
公司邮编:%s
公司电话:%s
""" % data_tuple)
f.write(
"""
公司名称:%s
公司地址:%s
公司邮编:%s
公司电话:%s
""" % data_tuple)
2.requests模块简介
requests模块能够模拟浏览器发送网络请求
# Python 内置了 requests 模块,该模块主要用来发 送 HTTP 请求
1.requests模块的语法
# 1 导入 requests 包
import requests
# 2 发送请求
# 朝指定网址发送请求获取页面数据(等价于:浏览器地址栏输入网址回车访问)
x = requests.get('http://www.redbull.com.cn/about/branch')
# 3 返回网页内容
print(x.text) # 并非所有网站都是以utf8来进行字符编码的
2.requests模块语法的补充说明
# 1 获取bytes类型的网页数据(二进制)
print(x.content)
# 2 可以指定字符编号,已经获取bytes类型的网页数据(二进制)
x.encoding = 'utf8' # 指定编码
print(x.text) # 获取字符串类型的网页数据(默认按照utf8)
3.小练习:利用requests模块来获取莲家二手房的二手房数据
"""
思路:
1.通过requests模块模拟浏览器向链家网站发送请求
2.返回网页内容
3.研究网页上的内容,编写对应的正则表达式
4.筛选出结果写入文件中
"""
import requests
import re
# 链家网站:https://sh.lianjia.com/ershoufang/pudong/
# 1 通过requests模块获取链家网站的内容
web_lj = requests.get('https://sh.lianjia.com/ershoufang/pudong/')
# 2 返回内容
data = web_lj.text
# 3 通过正则表达式来匹配数据,匹配我们想要的结果
house_title_list = re.findall(
'data-is_focus="" data-sl="">(.*?)</a>',
data)
print(house_title_list)
house_position_list = re.findall('<a href=".*?" target="_blank" data-log_index=".*?" data-el="region">(.*?)</a>', data)
# print(house_position_list)
house_street_list = re.findall('- <a href=".*?" target="_blank">(.*?)</a>', data)
# print(house_street_list)
house_info_list = re.findall('<div class="houseInfo"><span class="houseIcon"></span>(.*?)</div>', data)
house_follow_list = re.findall('<div class="followInfo"><span class="starIcon"></span>(.*?)</div>', data)
house_total_price_list = re.findall(
'<div class="totalPrice totalPrice2"><i> </i><span class="">(.*?)</span><i>万</i></div>', data)
house_unit_price_list = re.findall(
'<div class="unitPrice" data-hid=".*?" data-rid=".*?" data-price=".*?"><span>(.*?)</span></div>', data)
house_data = zip(house_title_list, house_position_list, house_street_list, house_info_list, house_follow_list,
house_total_price_list, house_unit_price_list)
# 4 创建文件保存数据
with open(r'sec_hand_house.txt','w',encoding='utf8') as f:
for data in house_data:
print("""
房屋标题:%s
小区名称:%s
街道名称:%s
详细信息:%s
关注程度:%s
房屋总价:%s万元
房屋单价:%s
""" % data
)
f.write("""
房屋标题:%s
小区名称:%s
街道名称:%s
详细信息:%s
关注程度:%s
房屋总价:%s万元
房屋单价:%s
""" % data
)
七、openpyxl模块-自动化办公
1.openpyxl模块简介
1.excel文件的后缀名问题
2003版本之前后缀名为: ` .xls`
2003版本之后后缀名为: ` .xlsx`
2.操作excel表格的第三方模块
1)`xlwt`往表格中写入数据(兼容所有版本的excel文件)
2)`wlrd`从表格中读取数据(兼容所有版本的excel文件)
3)**`openpyxl`最近几年比较火热的操作excel表格的模块(对2003版本之前的兼容性较差 )
2.openpyxl操作
很多模块都会有官方文档,可以帮助我们快速了解如何使用该模块
openpyxl中的对象Workbook
- 1 workbook 相当于一个 Excel 文件档,每个被创建和打开的 Excel 文件都是独立的 Workbook 对象
- 2 sheet Excel 文档中的表单,每个 Excel 文档至少需要一个 sheet
- 3 cell 单元格,是不可分割的基本数据存储单元
from openpyxl import Workbook
1.创建一个excel文件 `Workbook`关键字
wb = Workbook()
2.在一个excel文件内创建多个工作簿sheet `create_sheet`
wb1 = wb.create_sheet('宿舍名单')
wb2 = wb.create_sheet('身份证信息')
wb3 = wb.create_sheet('电话信息')
3.修改默认的工作簿位置
# 在想修改的工作簿添加索引参数
wb4 = wb.create_sheet('女朋友电话', 0)
4.二次修改工作簿名称 `工作簿名.title = '新命名'`
wb4.title = '男神电话'
wb4.sheet_properties.tabColor = "1072BA"
5.填写数据
1)wb4['A1'] = 'haha'
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','哈哈哈'])
6.填写数据额公式
# 默认是公式本身,不会出现结果,需要用value参数指定才会获取计算结果
wb4['A5'] = '=sum(A1:A4)'
wb4.cell(row=8, column=3, value='=sum(A1:A4)')
7.保存excel文件
wb.save(r'aaaa.xlsx')
-
excel软件正常可以打开操作的数据集数量在10万左右, 一旦数据集过大,软件操作几乎无效需要使用pandas模块进行代码操作
-
模块openpyxl 主要用于数据的写入
-
模块pandas 擅长表单操作