◀▶log
日志
★ 基本介绍
| logging是Python内置的日志处理模块,用来记录程序的运行状态和故障排除;因为print是同步代码,会影响代码的执行速度,而logging是异步的,可以在多进程爬取中、在协程爬取中使用logging记录调试信息而不会影响到代码的异步执行和运行效率。 |
★ 日志信息等级
- 日志信息分成五级;从高到低排序为:
- CRITICAL:严重错误
- ERROR: 错误
- WARNING: 警告 (默认级别)
- INFO: 主要信息
- DEBUG: 调试信息
★ 日志输出
-
将日志输出到控制台
| import logging |
| |
| |
| logging.basicConfig(level=logging.WARNING, |
| format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') |
| logger = logging.getLogger("日志名") |
| |
| logger.debug() |
| logger.error() |
| ... |
-
将日志输出到文件
| import logging |
| |
| logging.basicConfig(level=logging.WARNING, |
| filename='./log.txt', |
| filemode='w', |
| format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') |
| |
| logger = logging.getLogger("日志名") |
| |
| |
| logger.info('这是 loggging info message') |
| logger.debug('这是 loggging debug message') |
| logger.warning('这是 loggging a warning message') |
| logger.error('这是 an loggging error message') |
| logger.critical('这是 loggging critical message') |
-
将日志输出到控制台同时输出到文件
| import logging |
| |
| |
| logger = logging.getLogger() |
| logger.setLevel(logging.INFO) |
| |
| |
| logfile = './log.txt' |
| fh = logging.FileHandler(logfile, mode='a') |
| fh.setLevel(logging.DEBUG) |
| |
| |
| ch = logging.StreamHandler() |
| ch.setLevel(logging.WARNING) |
| |
| |
| formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") |
| fh.setFormatter(formatter) |
| ch.setFormatter(formatter) |
| |
| |
| logger.addHandler(fh) |
| logger.addHandler(ch) |
| |
| |
| logger.debug('这是 logger debug message') |
| logger.info('这是 logger info message') |
| logger.warning('这是 logger warning message') |
| logger.error('这是 logger error message') |
| logger.critical('这是 logger critical message') |
★ 日志应用示例
-
自定义 log
日志
| |
| import logging |
| import logging.handlers |
| import os |
| |
| |
| class RequestFormatter(logging.Formatter): |
| |
| |
| def format(self, record): |
| record.url = "www.baidu.com" |
| record.remote_addr = "127.0.0.1" |
| return super().format(record) |
| |
| |
| |
| def create_logger(): |
| LOG_LEVEL = 'DEBUG' |
| LOG_FILE_DIR = 'logs/' |
| LOG_FILE_MAX_BYTES = 300 * 1024 * 1024 |
| LOG_FILE_BACKUP = 100 |
| |
| |
| if not os.path.isdir(LOG_FILE_DIR): |
| os.mkdir(LOG_FILE_DIR) |
| |
| |
| request_file_formatter = RequestFormatter('%(asctime)s - %(url)s[%(remote_addr)s] - ' |
| '%(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') |
| request_console_formatter = logging.Formatter( |
| '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') |
| |
| |
| file_handler = logging.handlers.RotatingFileHandler( |
| filename=os.path.join(LOG_FILE_DIR, "shopping.log"), |
| maxBytes=LOG_FILE_MAX_BYTES, |
| backupCount=LOG_FILE_BACKUP |
| ) |
| console_handler = logging.StreamHandler() |
| |
| |
| file_handler.setFormatter(request_file_formatter) |
| console_handler.setFormatter(request_console_formatter) |
| |
| |
| logger = logging.getLogger('Shopping') |
| logger.setLevel(LOG_LEVEL) |
| |
| |
| logger.addHandler(file_handler) |
| logger.addHandler(console_handler) |
| return logger |
| |
| |
| if __name__ == '__main__': |
| logger = create_logger() |
| logger.info('log日志测试') |
◀▶ 数据序列化
★ 什么是数据的序列化
| 数据的序列化指的是将数据从其原始格式转换为一种可存储或传输的格式,通常是字节流或字符串的形式。这样做的目的是为了能够在不同系统、编程语言或设备之间进行数据交换、存储或传输,同时保持数据的结构完整性。 |
★ 序列化的应用场景:
-
数据传输
| 序列化可用于在网络中传输数据,比如Web应用中的前后端数据交互,API请求和响应的数据传输等。 |
-
数据持久化
| 序列化使得数据可以被保存在文件系统或数据库中,例如存储配置文件、持久化对象等。 |
-
跨平台数据交换
| 序列化使得不同平台、不同编程语言之间能够共享和解释数据,促进系统间的数据交换和互操作。 |
★ Python
常见序列化工具
-
pickle
序列化
-
base64
序列化
-
base64
基本介绍
| Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2^6=64,所以每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同 |
-
使用方式
| base64.b64encode() 将bytes类型数据进行base64编码,返回编码后的bytes类型 |
| base64.b64deocde() 将base64编码的bytes类型进行解码,返回解码后的bytes类型 |
-
json
序列化
◀▶ 简单进度条
★ 进度条基本实现
-
功能代码
| import sys |
| import time |
| |
| |
| def progress_bar_demo(title, symbol): |
| for per in range(1, 101): |
| print("\r", end="") |
| print(f"【{title}】: {per}%: {symbol * (per // 2)} ", end="") |
| sys.stdout.flush() |
| time.sleep(0.1) |
| print("Complete !!!") |
| |
| |
| progress_bar_demo("Download progress", "▋") |
★ 进度条应用版
-
功能代码
| import sys |
| import time |
| |
| |
| |
| class ProgressBar: |
| |
| def __init__(self, title, symbol="▋"): |
| self.title = title |
| self.symbol = symbol |
| |
| self.is_stop = False |
| |
| self.process = self._process() |
| |
| next(self.process) |
| |
| |
| def update_process(self, percent): |
| if self.is_stop: |
| return True |
| |
| |
| if percent < 0: |
| percent = 0 |
| elif percent > 100: |
| percent = 100 |
| percent = int(percent) |
| |
| |
| try: |
| self.process.send(percent) |
| except StopIteration: |
| self.is_stop = True |
| return True |
| else: |
| return False |
| |
| def _process(self): |
| while True: |
| percent = yield |
| |
| print("\r", end="") |
| print(f"【{self.title}】: {percent}%: {self.symbol * (percent // 2)} ", end="") |
| sys.stdout.flush() |
| |
| if percent >= 100: |
| print("Complete !!!") |
| break |
| |
| |
| |
| total_num = 125 |
| complete_num = 0 |
| |
| pb = ProgressBar("Download progress") |
| while True: |
| |
| time.sleep(0.1) |
| complete_num += 1 |
| |
| is_over = pb.update_process(complete_num / total_num * 100) |
| if is_over: |
| break |
-
运行效果

◀▶ Python
加载 C
语言动态库
★ 背景说明
| 1. python是一门胶水语言,可以通过加载动态库的方式在一个项目中运行不同语言的程序 |
| 2. 通过动态库加载其他语言的方式可以解决多线程GIL使用C解释器无法并发运行的问题 |
★ 在 Linux
中运行 C
语言代码:
★ 使用 Python
中加载 C
语言动态库
◀▶ Python
环境变量设置与读取
★ 环境变量基本概念
-
环境变量定义
| 环境变量是操作系统中存储有关操作系统配置信息和应用程序运行环境的动态值的一种机制。环境变量的主要作用是为正在运行的进程提供配置信息,帮助程序找到所需的资源或者确定程序运行的方式。 |
| 在操作系统中,每个进程都有自己的环境变量集合。这些变量可以包含诸如路径、临时文件位置、语言设定、用户偏好设置等信息。程序可以通过读取环境变量来获取这些信息,从而适应不同的操作系统环境或用户设置。 |
-
作用
| 有些字符不宜明文写进代码里,比如数据库密码,个人账户密码,如果写进自己本机的环境变量里,程序用的时候通过 os.environ.get() 取出来就行了。这样开发人员本机测试的时候用的是自己本机的一套密码,生产环境部署的时候,用的是公司的公共账号和密码,这样就能增加安全性 |
★ 环境变量的设置
-
方式一. 设置系统环境变量
-
方式二. 设置Pycharm环境变量
-
方式三. 设置单个项目的环境变量
-
方式四. 将环境变量按指定格式写入到文件(一般设置为隐藏格式如 .env)
★ 环境变量的读取
-
读取环境变量所有key
-
环境变量常用key
-
Windows
系统
| os.environ['HOMEPATH']:当前用户主目录。 |
| os.environ['TEMP']:临时目录路径。 |
| os.environ["PATHEXT"]:可执行文件。 |
| os.environ['SYSTEMROOT']:系统主目录。 |
| os.environ['LOGONSERVER']:机器名。 |
| os.environ['PROMPT']:设置提示符。 |
-
Linux
系统
| os.environ['USER']:当前使用用户。 |
| os.environ['LC_COLLATE']:路径扩展的结果排序时的字母顺序。 |
| os.environ['SHELL']:使用shell的类型。 |
| os.environ['LAN']:使用的语言。 |
| os.environ['SSH_AUTH_SOCK']:ssh的执行路径。 |
-
环境变量的增删改查
| |
| os.environ['环境变量名称']='环境变量值' |
| os.putenv('环境变量名称', '环境变量值') |
| os.environ.setdefault('环境变量名称', '环境变量值') |
| |
| |
| os.environ['环境变量名称']='新环境变量值' |
| |
| |
| os.environ['环境变量名称'] |
| os.getenv('环境变量名称') |
| os.environ.get('环境变量名称', '默认值') |
| |
| |
| del os.environ['环境变量名称'] |
| del(os.environ['环境变量名称']) |
| |
| |
| '环境变量值' in os.environ |
目录结构生成器
| import os |
| import time |
| import math |
| |
| |
| class DirectoryGenerator: |
| |
| def __init__(self, root_path): |
| self.root_path = root_path |
| self.files_directory = {} |
| |
| |
| @staticmethod |
| def format_time(t): |
| return time.strftime('%Y-%m-%d %H-%M-%S', time.localtime(t)) |
| |
| |
| @staticmethod |
| def file_size_conversion(size_bytes): |
| if size_bytes == 0: |
| return "0B" |
| size_unit = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") |
| level = int(math.floor(math.log(size_bytes, 1024))) |
| level_bytes = math.pow(1024, level) |
| value = round(size_bytes / level_bytes, 2) |
| return f'{value}{size_unit[level]}' |
| |
| |
| def get_file_detail_info(self, file_path): |
| file_info = os.stat(file_path) |
| file_info_dict = { |
| 'last_visit_time': self.format_time(file_info.st_atime), |
| 'last_modify_time': self.format_time(file_info.st_mtime), |
| 'size': self.file_size_conversion(file_info.st_size), |
| } |
| return file_info_dict |
| |
| def get_files_directory(self): |
| |
| self.files_directory = self.__get_files_directory(self.root_path) |
| return self.files_directory |
| |
| def print_file_directory(self): |
| |
| self.__print_file_directory(self.files_directory) |
| |
| |
| def __get_files_directory(self, root_path): |
| |
| files_directory = {'name': os.path.basename(root_path), 'path': root_path, 'child': []} |
| |
| |
| for file_or_dir in os.listdir(root_path): |
| |
| path = os.path.join(root_path, file_or_dir) |
| |
| |
| if os.path.isfile(path): |
| child = {'name': os.path.basename(path), 'path': path, 'child': []} |
| |
| child.update(self.get_file_detail_info(path)) |
| files_directory['child'].append(child) |
| |
| else: |
| files_directory['child'].append(self.__get_files_directory(path)) |
| |
| return files_directory |
| |
| def __print_file_directory(self, files_directory): |
| is_file = os.path.isfile(files_directory['path']) |
| child_directorys = files_directory['child'] |
| if is_file: |
| print(f""" |
| 文件名: {files_directory['name']} |
| 文件大小: {files_directory['size']} |
| 最后访问时间: {files_directory['last_visit_time']} |
| 最后修改时间: {files_directory['last_modify_time']} |
| 文件路径: {files_directory['path']} |
| """, end='') |
| else: |
| print(f""" |
| 文件夹名: {files_directory['name']} |
| 文件夹路径: {files_directory['path']} |
| 子文件或子文件夹: {[child_directory['name'] for child_directory in child_directorys]} |
| """, end='') |
| |
| |
| for child_directory in child_directorys: |
| self.__print_file_directory(child_directory) |
| |
| |
| if __name__ == '__main__': |
| |
| search_path = r'C:\Users\damon\Desktop\目录生成器' |
| |
| directory_generator = DirectoryGenerator(search_path) |
| |
| directory_generator.get_files_directory() |
| |
| directory_generator.print_file_directory() |
| |
JWT
基本介绍与使用
★ JWT
基本概念
| JWT(JSON Web Token)是一种用于在网络应用之间传递信息的安全方式。它是一种基于 JSON 的开放标准(RFC 7519),用于在网络应用之间安全地传输声明。JWT 通常用于身份验证和授权,以及在分布式系统中传递声明。 |
★ JWT
组成部分
| JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。其中,头部和载荷都是 JSON 对象,签名是对头部和载荷进行加密后的字符串。 |
★ JWT
的使用流程
| 1. 用户向服务器发送身份验证请求,服务器验证用户身份并生成 JWT。 |
| 2. 服务器将 JWT 发送回客户端,客户端将其存储在本地。 |
| 3. 客户端向服务器发送请求时,将 JWT 作为请求头部的 Authorization 字段发送给服务器。 |
| 4. 服务器验证 JWT 的签名和有效期,并根据其中的声明进行授权。 |
★ JWT
的优点
| 无状态:JWT 中包含了所有必要的信息,因此服务器不需要在自己的数据库中存储用户信息,从而使得服务器可以更容易地扩展。 |
| 跨平台:由于 JWT 是基于 JSON 的开放标准,因此它可以在不同的编程语言和平台之间进行交互。 |
| 安全性:JWT 使用签名来验证数据的完整性和真实性,从而保证了数据的安全性。 |
★ JWT
说明
| 需要注意的是,JWT 中的信息是可以被解码的,因此不应该在 JWT 中存储敏感信息。此外,JWT 的有效期应该设置得足够短,以避免被恶意利用 |
★ JWT
基本使用示例
| """ |
| pip install PyJWT |
| """ |
| import jwt |
| import datetime |
| |
| |
| |
| secret_key = 'my_secret_key' |
| |
| expires_in = datetime.datetime.utcnow() + datetime.timedelta(minutes=30) |
| |
| payload = { |
| 'website': 'stu_manage', |
| 'user_id': 123, |
| 'exp': expires_in |
| } |
| |
| |
| jwt_token = jwt.encode(payload, secret_key, algorithm='HS256') |
| print(jwt_token) |
| |
| |
| |
| |
| decoded_token = jwt.decode(jwt_token, secret_key, algorithms=['HS256']) |
| |
| print(decoded_token) |
| print(datetime.datetime.fromtimestamp(decoded_token['exp'])) |
| |
| print(jwt.get_unverified_header(jwt_token)) |
| |
| |
★ JWT
封装使用
| """ |
| pip install PyJWT |
| """ |
| import jwt |
| from jwt.exceptions import DecodeError, ExpiredSignatureError |
| import datetime |
| import logging |
| |
| logger = logging.getLogger('django') |
| |
| |
| SECRET_KEY = 'django-insecure-2cvu_ew%s2&(3+ex7dn=gs@(4dv_)o5=81(q!4(h+_4eua7-7%' |
| |
| |
| |
| def generate_jwt_token(payload, expire): |
| expires_in = datetime.datetime.utcnow() + datetime.timedelta(seconds=expire) |
| payload.update({ |
| 'exp': expires_in |
| }) |
| jwt_token = jwt.encode(payload, SECRET_KEY, algorithm='HS256') |
| return jwt_token |
| |
| |
| |
| def checkout_token(token): |
| try: |
| decode_token = jwt.decode(token, SECRET_KEY, algorithms=['HS256']) |
| except (DecodeError, ExpiredSignatureError) as e: |
| logger.warning(f"JWT decode error: {e}") |
| return False |
| else: |
| decode_token.pop('exp') |
| return decode_token |
| |
| |
| if __name__ == '__main__': |
| import time |
| token = generate_jwt_token({"name": 12}, 3) |
| print(f"生成的token: {token}") |
| |
| time.sleep(2) |
| print(f"token校验结果: {checkout_token(token)}") |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?