10.24-10.28周末回顾

一、购物车

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.日志的组成

image-20221027184135423

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提供的下载方式

image-20221026154541654

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 擅长表单操作

posted @ 2022-10-30 18:23  Duosg  阅读(26)  评论(0编辑  收藏  举报