1)获取文件名
os.path.splitext函数来一次性获取文件名和扩展名,然后检查扩展名是否为.xlsx。如果不是,我们只需添加正确的扩展名即可。
import os
excel_file = "example.xls" # 假设这是你的输入文件名
base_name, ext = os.path.splitext(excel_file)
if ext.lower() != '.xlsx':
excel_file = base_name + '.xlsx'
# 输出文件
tmp = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d-%H')
file_out = f'1.{tmp}-{table_name}-共计{len1}张.xlsx' # 输出文件名称
excel_file = os.path.splitext(excel_file)[0] + ".xlsx"
def query_data_and_save_to_excel(database, table, excel_file):
with db_lock:
try:
# 连接SQLite数据库
conn = sqlite3.connect(database)
# 查询数据库表数据
query = f"SELECT * FROM {table}"
df = pd.read_sql_query(query, conn)
excel_file = os.path.splitext(excel_file)[0] + ".xlsx"
df.to_excel(excel_file, index=False)
print("数据成功保存 {}".format(excel_file))
except Exception as e:
logger.error(f"发生错误: {e}")
finally:
# 关闭数据库连接
if conn:
conn.close()
2)DB_SQLITE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'db.sqlite3')
DB_SQLITE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'db.sqlite3')
这行代码的作用是构建一个指向当前脚本所在目录下名为 db.sqlite3
的文件的绝对路径。具体来说,它使用了Python的os
模块中的一些函数来实现这个功能。
-
os.path.abspath(__file__)
:获取当前脚本文件的绝对路径。 -
os.path.dirname()
:获取给定路径的目录名。在这里,它获取了当前脚本文件所在的目录。 -
os.path.join()
:将两个路径组合成一个路径。在这里,它将目录名和文件名('db.sqlite3')组合在一起,形成一个完整的文件路径。
3)装饰器@retry
发送GET请求
定义了一个名为send_get_request
的函数,用于发送GET请求并返回响应。函数使用了装饰器@retry
,该装饰器会在发生异常时自动重试指定次数(本例中为2次),并在每次重试之间等待指定的延迟时间(本例中为1秒)。
具体来说,函数的功能如下:
- 创建一个
requests.Session()
对象,用于管理HTTP请求和响应。 - 使用
session.get()
方法发送GET请求,传入URL、请求头、查询参数和超时时间。 - 如果请求成功且状态码为200,则返回响应对象。
- 如果请求过程中发生异常(如网络错误、超时等),则记录错误日志并抛出异常。
@retry(tries=2, delay=1)
def send_get_request(url, headers=None, params=None, timeout=20):
session = requests.Session()
try:
response = session.get(url, headers=headers, params=params, timeout=timeout)
response.raise_for_status()
return response
except Exception as e:
logger.error(f"请求发生异常: {e} - {url}")
raise
4)发送POST请求
使用requests
库的Session
对象来复用TCP连接,从而提高性能。
# 定义一个装饰器函数,用于处理重试逻辑
@retry(tries=2, delay=1)
def get_token_with_retry(session, url, data, headers):
response = session.post(url, data=json.dumps(data), headers=headers)
response.raise_for_status() # 检查请求是否成功
return response.text
def get_token(operator, data):
url = "https://Token"
headers = {'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate, br'}
session = requests.Session()
try:
token = get_token_with_retry(session, url, data, headers)
if token:
update_tokenini_data(operator, 'TOKEN', f"{token}")
logger.info(f'时间:{datetime.datetime.now()}-->{operator}-{token} 更新成功')
return token
except (requests.exceptions.RequestException, ValueError) as e:
logger.error(f"TOKEN请求异常:{e}")
return None
5)raise
关键字
用于抛出异常。当程序遇到错误或异常情况时,可以使用raise
语句手动触发异常。raise
后面通常跟着一个异常类或异常实例,表示要抛出的异常类型。如果不指定异常类型,将默认抛出RuntimeError
异常。
def divide(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(e)
我们定义了一个divide函数,用于计算两个数相除的结果。如果除数为0,我们使用raise抛出一个ValueError异常,并附带一条错误信息。在调用divide函数时,我们使用try-except语句捕获异常,并在发生异常时打印错误信息。
注意事项
raise语句只能在函数或方法内部使用,不能在全局作用域或类定义中使用。
如果没有捕获到异常,程序将终止执行,并显示异常信息。
可以自定义异常类,继承自内置的异常类(如Exception),以创建更具体的异常类型。
6)logger日志管理
from loguru import logger
logger.add(
sink="./logs/appAPN.log",
enqueue=True,
rotation="2 MB",
retention="4 months",
encoding="utf-8",
backtrace=True,
diagnose=True,
#compression="zip",
)
logger.add()
是 Python 中的一个方法,用于向日志记录器添加一个日志处理器。这个方法接收多个参数,用于配置日志处理器的行为。以下是各个参数的解释:
sink
: 指定日志文件的路径。在这个例子中,日志将被写入到 "./logs/appAPN.log" 文件中。enqueue
: 如果设置为 True,则日志记录将被异步地添加到队列中,而不是直接写入文件。这可以提高性能,特别是在多线程或多进程环境中。rotation
: 设置日志文件的最大大小。在这个例子中,当日志文件达到 2 MB 时,将创建一个新的日志文件。旧的日志文件将被保留,直到达到指定的保留时间。retention
: 设置日志文件的保留时间。在这个例子中,日志文件将被保留 4 个月。超过这个时间的日志文件将被删除。encoding
: 设置日志文件的编码格式。在这个例子中,使用 utf-8 编码。backtrace
: 如果设置为 True,则在捕获异常时,将记录完整的堆栈跟踪信息。diagnose
: 如果设置为 True,则在捕获异常时,将记录诊断信息,如异常类型和异常值。compression
: 可选参数,用于指定日志文件的压缩格式。在这个例子中,注释掉了这个参数,所以不会对日志文件进行压缩。
7)使用str.strip()
方法去除两侧的空格
lambda表达式中,我们检查每个元素的数据类型是否为字符串(即object
),如果是,则使用str.strip()
方法去除两侧的空格;如果不是,则保持原样。
# 读取Excel数据
df = pd.read_excel(file_path,dtype=str)
# 去除所有数据中的空格
df = df.apply(lambda x: x.str.strip() if x.dtype == "object" else x)
8)设置pip源及pyqt安装
pip config list -v
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
C:\Users\XX\AppData\Roaming\pip\pip.ini
pip install pyqt5 -i https://mirrors.aliuyun.com/pypi/simple
pip install pyqt5 pyqt5-tools -i https://mirrors.aliuyun.com/pypi/simple
pyqt5 pyqt5-tools:高版本python安装不上,可以直接安装pyqt5designer配合vscode使用
pip install pyqt5designer
9)pandas导出转换成数值类型
解析:
df[['月用量GB', '月用量MB', '月用量KB']]
:选择DataFrame df中的'月用量GB'、'月用量MB'和'月用量KB'这三列。apply(pd.to_numeric, errors='coerce')
:对选定的列应用pd.to_numeric函数,将其转换为数值类型。如果某个值无法转换为数值,则将其设置为NaN。fillna('--')
:将NaN值替换为字符串'--'。
def query_data_and_save_to_excel(database, table, excel_file):
with db_lock:
try:
# 连接SQLite数据库
conn = sqlite3.connect(database)
# 查询数据库表数据
query = f"SELECT * FROM {table}"
df = pd.read_sql_query(query, conn)
excel_file = os.path.splitext(excel_file)[0] + ".xlsx"
# 将age列的数据类型转换为字符串
df[['月用量GB', '月用量MB', '月用量KB']] = df[['月用量GB', '月用量MB', '月用量KB']].apply(pd.to_numeric, errors='coerce').fillna('--')
df.to_excel(excel_file, index=False)
print("数据成功保存 {}".format(excel_file))
except Exception as e:
logger.error(f"发生错误: {e}")
finally:
# 关闭数据库连接
if conn:
conn.close()
10)文件互斥锁
import threading
class FileReaderWriter:
def __init__(self, file_path):
self.file_path = file_path
self.mutex = threading.Lock()
def read_file(self):
with self.mutex:
with open(self.file_path, 'r') as file:
content = file.read()
print("读取文件内容:", content)
def write_file(self, content):
with self.mutex:
with open(self.file_path, 'w') as file:
file.write(content)
print("写入文件内容:", content)
# 示例用法
file_reader_writer = FileReaderWriter('example.txt')
def read_file():
file_reader_writer.read_file()
def write_file():
file_reader_writer.write_file('Hello, World!')
# 创建多个线程进行读写操作
threads = []
for i in range(5):
threads.append(threading.Thread(target=read_file))
threads.append(threading.Thread(target=write_file))
for t in threads:
t.start()
for t in threads:
t.join()