• [技术干货] 【Python】常用模块-转载
    引言上一节博主讲解了关于【Python】模块与包这一节我们来看一下Python的一些常用模块一,time模块Python 的 time 模块是处理时间相关操作的核心模块之一,主要用于获取时间戳、时间格式化、程序延时、CPU 时间统计等场景。下面从核心功能、常用函数、使用示例等方面详细介绍:(一)、核心概念在使用 time 模块前,先理解两个基础概念:时间戳(timestamp):从1970 年 1 月 1 日 00:00:00(UTC/GMT 的午夜) 开始到当前时间的秒数(浮点数),是计算机存储时间的常用方式。结构化时间(struct_time):一个包含年、月、日、时、分、秒等信息的元组 / 对象,共 9 个元素,可通过索引或属性访问(如 tm_year、tm_mon)。(二)、常用函数分类及示例1. 获取时间戳(time())import timeprint(time.time())AI写代码python运行2. 返回结构化格式的时间(localtime())import time# localtime() -- 获取当前时间st = time.localtime()# 返回结构化格式的时间# 结构化时间(struct_time): struct_time元组共有9个元素#                   年              月        日          时# time.struct_time(tm_year=2025, tm_mon=12, tm_mday=10, tm_hour=19,#   分         秒         星期几      一年中的第几天   夏令时间# tm_min=50, tm_sec=32, tm_wday=2, tm_yday=344, tm_idsst=0)print(st)AI写代码python运行3.格式化和解析操作(time.strftime()和time.strptime())import time# strftime(format,struct_time) -- 根据指定格式将时间元组转换为字符串,参考格式化时间字符串化对应表# strptime(struct_time,format) -- 将时间字符串解析为时间元组struct_time# 将格式化时间转换成字符串时间str = time.strftime("%Y-%m-%d %X",time.localtime())str = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())# 将字符串时间转换成格式化时间tm = time.strptime("2025-12-10 20:23:05",'%Y-%m-%d %X')print(tm)print(str)AI写代码python运行常用格式化符号:符号    含义    示例%Y    4 位年份    2025%y    2 位年份    25%m    月份(01-12)    12%d    日期(01-31)    11%H    24 小时制(00-23)    10%I    12 小时制(01-12)    10%M    分钟(00-59)    30%S    秒(00-59)    00%a    星期缩写    Thu%A    星期全称    Thursday%b    月份缩写    Dec%B    月份全称    December4.延时函数(sleep())sleep(second) -- 程序休眠多少秒time.sleep(5)AI写代码python运行二.random模块1. random 随机数模块,用于产生随机数import random # random() -- 生成一个[0.0,1.0)范围内的随机小数r1 = random.random()print(r1)AI写代码python运行2. randint(a,b) -- 生成一个在[a,b]范围内的随机整数(包括a和b)import randomr2 = random.randint(1,10)print(r2)AI写代码python运行3. uniform(a,b) -- 返回一个在[a,b]区间内的随机小数(包括a和b)import randomr3 = random.uniform(1.0,3.0)print(r3)AI写代码python运行4. 利用切片的方式randrange(start,stop,step)import random# randrange(start,stop,step)# step是可以省略的# 从指定范围内按照指定基数递增的集合中获取一个随机数,类似于range()函数# 使用randrange方法生成一个在[0,10]之间的偶数r4 = random.randrange(0,10,2)print(r4)AI写代码python运行5. choice(有序的iterable) -- 从有序的可迭代对象中随机选择一个元素import random# choice(有序的iterable) -- 从有序的可迭代对象中随机选择一个元素# 通过索引来迭代的r5 = random.choice(range(1,10))print(r5) # 随机选择一个元素r5 = random.choice([1,1.2,15,17,12])print(r5) # 无序不可用# r5 = random.choice({'age':20,'sex':'男'})# print(r5)  # 报错AI写代码python运行注意像集合,字典等无序元素不能用choice()6. shuffle() -- 将有序可迭代对象中的元素打乱顺序(类似洗牌)import random# shuffle() -- 将有序可迭代对象中的元素打乱顺序(类似洗牌)list = [1,2,3,4,5,6]random.shuffle(list)print(list)AI写代码python运行三.os模块os模块,提供了很多允许你的程序与操作系统直接交互的功能文件和目录操作:创建、删除、重命名文件或目录,获取当前工作目录等路径操作:处理不同操作系统下的路径格式(如拼接路径)1. 文件和目录操作(os.system())import os# 文件和目录操作# 打开cmdos.system('start cmd')# 打开计算器os.system('start calc')AI写代码python运行2. 路径操作(os.getcwd())import os# 路径操作# 获取当前文件所在的路径目录print(os.getcwd()) # __file__内置变量,用于表示当前模块的文件路径。它的值取决于模块是如何加载的print(__file__)AI写代码python运行3. 创建和删除(os.mkdir()和os.rmdir())import os# 创建目录# 在当前目录下创建目录,如果存在则创建失败os.mkdir('test')# 删除目录# 删除目录 必须满足:空目录   空目录:里面没有任何东西os.rmdir('test')AI写代码python运行4. 重命名(os.rename())import os# 对目录重命名os.rename('test','test02')# 对目录下面的文件进行重命名os.rename('test02\\a.py','test02/b.py')AI写代码python运行5.os.path模块import os# os.path模块# 判断文件是否存在(os.path.exists())返回的是布尔型print(os.path.exists(r'C:\Users\Windows\PycharmProjects\pythonProjects\day14\test02\b.py')) # 获取当前文件所在目录print(os.path.dirname(__file__)) # 获取当前文件名print(os.path.basename(__file__)) # 给路径做拼接cur_path = os.path.dirname(__file__)file_path = os.path.join(cur_path,'a.py')print(file_path)AI写代码python运行四.json模块json.dumps():将Python对象转换为JSON字符串json.loads():解析JSON字符串并转换为Python对象json.dump(): 分别用于将Python对象写入文件作为JSON格式json.1oad(): 从文件中读取JSON数据到Python对象import json# 将Python字典转换JSON字符串data = {    'name': '张三',    'age':18,    'phone':'1861555284'} # 使用ensure_ascii=False来正确显示中文json_str = json.dumps(data,ensure_ascii=False)print(json_str)print(type(json_str))  # <class 'str'> # 解析JSON字符串并转换为Python对象json_str = '{"name":"张三","age":18,"phone":"1008611"}'data = json.loads(json_str)print(type(data))   #<class 'dict'> # 文件操作# data = {#     'name': '张三',#     'age':18,#     'phone':'1861555284'# }# # 将Python字典写入JSON文件with open('data.json','w',encoding="utf-8") as f:    json.dump(data,f,ensure_ascii=False) # 从JSON文件读取数据到Python字典with open('data.json','r',encoding="utf-8") as f:    load_data = json.load(f)print(type(load_data))  # <class 'dict'>AI写代码python运行五.结语其实博主是不喜欢发表长篇大论的,但是博主是有发表额度的,只好委屈大家一下了,博主的想法是从python零基础到实现开发软件或小程序,博主会不断推出这一类文章,后期还会出一份完整教程,正常博主会每天更新的,如果你也对python感兴趣的话,不妨给个一键三连支持一下博主(透露一下博主也是大一的┗|`O′|┛ 嗷~~)————————————————版权声明:本文为CSDN博主「buqizixv」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/buqizixv/article/details/155810433
  • [技术干货] 【Python】模块与包-转载
    在 Python 中,模块(Module) 和包(Package) 是组织代码的核心机制,用于解决代码复用、命名空间隔离和大型项目结构化的问题。下面从概念、使用、区别与联系等方面详细讲解:一、模块(Module)1. 什么是模块?模块是一个包含 Python 定义和语句的 **.py文件 **,它可以包含变量、函数、类、以及可执行代码。核心作用:代码复用:将常用功能封装在模块中,多处代码可导入使用。命名空间隔离:避免变量 / 函数名冲突(比如两个模块都有add函数,通过模块名区分)。2. 模块的基本使用(- 模块/变量/函数名:只能以字母(a-z/A-Z)、下划线(_)开头,后续可跟字母、数字、下划线;)(1)创建模块新建一个文件,例如math_utils.py,写入以下内容:# 定义变量PI = 3.1415926 # 定义函数def add(a, b):    return a + b # 定义类class Circle:    def __init__(self, radius):        self.radius = radius     def area(self):        return PI * self.radius **2AI写代码python运行2)导入模块(使用import)在另一个 Python 文件(如main.py)中,可以通过多种方式导入模块:导入整个模块:import math_utils#math_utils为模块名print(math_utils.PI)  # 输出:3.1415926print(math_utils.add(2, 3))  # 输出:5c = math_utils.Circle(2)print(c.area())  # 输出:12.5663704AI写代码python运行导入模块并指定别名:import math_utils as mu#mu为别名print(mu.PI)  # 简化调用AI写代码python运行从模块中导入指定内容:from math_utils import PI, add#math_utils为模块名#PI, add为模块内部的功能名#导入多个功能用逗号分开print(PI)print(add(2, 3))AI写代码python运行从模块中导入所有内容(不推荐,易冲突):import *如果这样写的话最好在模块源码内第一行做一个导出限制用:__all__=['要导出的功能']来实现源码部分(新建一个文件,例如math_utils_one.py,写入以下内容:):__all__=['add']def add(x,y):    return x+ydef minus(x,y):    return x-yAI写代码python运行主码部分:from math_utils_one import*print(add(2,3))#5#报错#NameError: name 'minus' is not definedprint(minus(2,3))AI写代码python运行这样就可以实现只导出需要的部分但是对from+模块+import+功能 或import+模块模块.功能这两种方式还是可以拿到minus(即受导出限制的功能)3)模块的内置属性每个模块都有内置属性,用于描述模块的信息:__name__:模块的名称。如果模块是主程序运行,__name__为__main__;如果被导入,__name__为模块名。__file__:模块的文件路径。__doc__:模块的文档字符串(注释)。# 在math_utils.py中添加if __name__ == "__main__":    print("我是主程序运行")else:    print("我被导入为模块")AI写代码python运行3. 系统内置模块Python 自带了大量内置模块(标准库),无需手动创建,可直接导入使用,例如:可以用ctrl+鼠标左键来进入模块内部查看其参数import os  # 操作系统相关功能import sys  # Python解释器相关import random  # 随机数import datetime  # 日期时间AI写代码python运行比如import time#导入时间模块print("开始时间")time.sleep(5)#sleep的单位是秒,参数为延迟时间print("结束时间")AI写代码python运行二、包(Package)1. 什么是包?包是一个包含__init__.py文件的文件夹(可观察是否存在__init__.py来判断是否为包),用于组织多个相关的模块,形成层级结构。核心作用:管理多个模块,解决大型项目中模块过多的问题。实现模块的层级命名空间(如package.module)my_package/          # 包的根目录    __init__.py      # 包的初始化文件(必须有)    module1.py       # 子模块1    module2.py       # 子模块2    sub_package/     # 子包        __init__.py        module3.pyAI写代码python运行(1)__init__.py的作用标识文件夹为 Python 包(Python 3.3 + 支持命名空间包,可无此文件,但推荐保留)。可在其中定义包的公共接口、初始化变量等。例如,在my_package/__init__.py中写入:# 导入子模块,让用户可直接通过包名访问from . import module1, module2# 定义包的版本__version__ = "1.0.0"AI写代码python运行3. 包的使用(1)导入包中的模块# 方式1:导入整个模块import my_package.module1 as m1print(m1.func1()) # 方式2:从包中导入模块from my_package import module2print(module2.func2()) # 方式3:从包的子模块中导入指定内容from my_package.module1 import func1AI写代码python运行(2)导入子包中的模块from my_package.sub_package import module3print(module3.func3())AI写代码python运行三、模块与包的区别与联系维度    模块(Module)    包(Package)形式    单个.py文件    包含__init__.py的文件夹作用    封装单个功能模块的代码    组织多个相关模块,形成层级命名空间    单层命名空间(如math)    多层命名空间(如numpy.core)联系:包是模块的集合与扩展,一个包可以包含多个模块和子包。模块和包都遵循 Python 的导入机制,本质都是为了代码的模块化和复用。四、常见问题与最佳实践1. 导入时的路径问题确保包 / 模块所在目录在 Python 的搜索路径(sys.path)中。项目根目录推荐加入sys.path,避免相对导入的问题。2. 相对导入与绝对导入绝对导入:从项目根目录开始导入(推荐),如from my_package import module1。相对导入:在包内部使用,用.表示当前目录,..表示上级目录,如from . import module2(仅在包内部有效,主程序中无法使用)。3. 最佳实践模块名和包名使用小写字母 + 下划线(如math_utils),符合 PEP8 规范。包的__init__.py保持简洁,只暴露公共接口,避免冗余代码。大型项目推荐按功能划分包(如api、utils、models),而非按文件类型。五、总结模块是 Python 代码的基本组织单元,对应单个.py文件;包是更高层级的组织形式,对应包含__init__.py的文件夹,用于管理多个模块;合理使用模块和包,能让代码结构清晰、易于维护和复用,是大型 Python 项目的基础。————————————————版权声明:本文为CSDN博主「buqizixv」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/buqizixv/article/details/155789933
  • [技术干货] 12月技术干货合集分享来啦~
    1、git删除分支实现步骤【转载】cid:link_62、git branch如何delete方式【转载】cid:link_73、 input的accept属性让文件上传安全高效【转载】cid:link_04、HTML5的<input>标签的`type`属性值详解和代码示例【转载】cid:link_15、 python爬虫脚本HTTP 403 Forbidden错误怎么办?【转载】cid:link_26、Python实现将.py代码转换为带语法高亮的Word和PDF【转载】cid:link_87、Python多进程中避免死锁问题的六种策略【转载】cid:link_98、 Python实现将PDF转DOCX的超简单教程(附源码)【转载】cid:link_39、Python基于OpenPyxl实现Excel转PDF并精准控制分页【转载】cid:link_1010、Python获取Docker容器实时资源占用(CPU、内存、IO等)5种实现方式【转载】cid:link_1111、 Python flash URL访问参数配置【转载】cid:link_1212、 Python利用PyMobileDevice3控制iOS设备的完整教程【转载】cid:link_413、 Python基本语法总结大全(含java、js对比)【转载】cid:link_514、 Python自动化提取多个Word文档的文本【转载】cid:link_1315、mybatis-plus分表实现案例(附示例代码)【转载】https://bbs.huaweicloud.com/forum/thread-02126200655519113076-1-1.html
  • [技术干货] Python自动化提取多个Word文档的文本【转载】
    日常工作和学习中,我们经常需要处理大量的Word文档。无论是进行数据分析、信息汇总,还是文档归档,手动逐一打开、复制、粘贴文档内容无疑是一项耗时且枯燥的任务。面对几十甚至上百个Word文档时,这种重复性劳动不仅效率低下,还极易出错。想象一下,如果你需要从上百份项目报告中提取关键的项目名称和摘要,或者从大量合同文件中汇总特定条款,手动操作将是噩梦。幸运的是,借助强大的Python编程能力和合适的库,我们完全可以实现这一过程的自动化,将原本数小时甚至数天的工作缩短到短短几分钟。本文将深入探讨如何利用Python批量提取Word文档中的文本内容,帮助你解放生产力,专注于更有价值的工作。为什么需要批量提取Word文档文本批量提取Word文档文本的需求源于现代信息处理的效率要求。其核心价值在于自动化处理所带来的巨大优势:数据分析与挖掘: 从海量文档中快速提取结构化或非结构化文本,为后续的数据分析、趋势洞察提供原始数据。例如,从客户反馈文档中提取关键词,分析用户情绪。信息整合与汇总: 将分散在多个Word文档中的信息集中起来,便于统一管理和查阅。例如,汇总多个部门的周报内容,生成一份综合报告。文档归档与检索: 提取文档核心内容作为元数据,提升文档检索的效率和准确性。例如,将合同文本提取并存储到数据库中,方便快速查找特定条款。内容迁移与转换: 在将Word文档内容迁移到其他系统(如内容管理系统、数据库)时,批量提取文本是第一步。效率与准确性: 自动化脚本能够以远超人工的速度完成任务,并且在重复性操作中保持极高的准确性,避免了人为疏忽造成的错误。可扩展性: 一旦脚本编写完成,可以轻松应用于更大规模的文档集,无需额外投入大量人力。批量提取Word文本的核心技术与工具Python在文档处理领域拥有众多强大的库,使其成为自动化处理文本的理想选择。对于Word文档(.doc 和 .docx 格式),虽然有多种库可供选择,但考虑到功能全面性、对复杂格式的支持以及易用性,我们将重点介绍 Spire.Doc for Python 库。Spire.Doc for Python 是一个功能丰富的Word文档处理库,它不仅能提取文本,还支持创建、编辑、转换Word文档等多种操作,尤其在处理复杂Word文档(如包含表格、图片、各种格式的文档)时表现出色。安装 Spire.Doc for Python在开始之前,请确保你的Python环境中已安装 spire.doc 库。如果尚未安装,可以通过 pip 命令轻松完成:1pip install Spire.Doc单个Word文档文本提取示例为了更好地理解其工作原理,我们首先来看一个简单的示例,演示如何从单个Word文档中提取所有文本内容。假设我们有一个名为 sample.docx 的Word文档。12345678910111213141516171819202122232425262728293031from spire.doc import *from spire.doc.common import * def extract_text_from_single_word(file_path):    """    从单个Word文档中提取所有文本内容。    :param file_path: Word文档的完整路径。    :return: 提取到的文本内容字符串。    """    document = Document()    try:        document.LoadFromFile(file_path) # 加载Word文档        text = document.GetText()       # 获取文档所有文本        return text    except Exception as e:        print(f"处理文件 {file_path} 时发生错误: {e}")        return None    finally:        document.Close() # 确保关闭文档,释放资源 # 示例使用if __name__ == "__main__":    input_doc_path = "sample.docx" # 替换为你的Word文档路径    extracted_content = extract_text_from_single_word(input_doc_path)     if extracted_content:        print("======== 提取的文本内容 ========")        print(extracted_content[:500]) # 打印前500个字符,避免内容过长        print("================================")    else:        print(f"未能从 {input_doc_path} 中提取文本。")代码解释:from spire.doc import * 和 from spire.doc.common import *:导入 spire.doc 库所需的所有类和枚举。document = Document():创建一个 Document 对象,用于表示一个Word文档。document.LoadFromFile(file_path):加载指定路径的Word文档。这是处理文档的第一步。text = document.GetText():这是核心方法,它会返回文档中所有的文本内容,以字符串形式表示。document.Close():关闭文档对象并释放相关资源。这是一个良好的编程习惯,尤其是在批量处理文件时,可以避免资源泄露。try...except...finally 块:用于处理文件加载或处理过程中可能出现的异常,并确保文档最终被关闭。实现批量文本提取的完整流程现在我们已经了解了如何从单个Word文档中提取文本,接下来将构建一个完整的批量处理流程,遍历指定目录下的所有Word文档,并将其文本内容提取出来保存到单独的文本文件中。批量处理流程设计准备工作:指定存放待处理Word文档的输入目录。指定存放提取结果的输出目录。遍历目录:使用Python的 os 模块遍历输入目录及其子目录,查找所有 .docx 和 .doc 文件。文本提取:对每个找到的Word文档,调用 Spire.Doc for Python 库进行文本提取。保存提取结果:将每个Word文档提取到的文本内容保存为独立的 .txt 文件,文件名与原Word文档保持一致。完整的批量处理代码示例123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051import osfrom spire.doc import *from spire.doc.common import * def batch_extract_text_from_word(input_dir, output_dir):    """    批量从指定目录下的Word文档中提取文本,并保存到输出目录。    :param input_dir: 包含Word文档的输入目录路径。    :param output_dir: 用于保存提取文本的输出目录路径。    """    if not os.path.exists(output_dir):        os.makedirs(output_dir) # 如果输出目录不存在,则创建     word_files_processed = 0         # 遍历输入目录下的所有文件和子目录    for root, _, files in os.walk(input_dir):        for file_name in files:            # 检查文件是否为Word文档            if file_name.endswith(".docx") or file_name.endswith(".doc"):                input_file_path = os.path.join(root, file_name)                                 # 构建输出文件名 (将 .docx/.doc 后缀替换为 .txt)                output_file_name = os.path.splitext(file_name)[0] + ".txt"                output_file_path = os.path.join(output_dir, output_file_name)                 print(f"正在处理: {input_file_path}")                document = Document()                try:                    document.LoadFromFile(input_file_path)                    text_content = document.GetText()                                         # 将提取的文本写入到新的 .txt 文件中                    with open(output_file_path, "w", encoding="utf-8") as f:                        f.write(text_content)                    print(f"文本已成功提取并保存至: {output_file_path}")                    word_files_processed += 1                except Exception as e:                    print(f"处理文件 {input_file_path} 时发生错误: {e}")                finally:                    document.Close() # 确保关闭文档     print(f"\n批量文本提取完成。共处理 {word_files_processed} 个Word文档。") # 示例使用if __name__ == "__main__":    # 请根据你的实际情况修改这些路径    input_directory = "D:\\MyWordDocuments"  # 存放Word文档的目录    output_directory = "D:\\ExtractedTexts" # 提取文本的保存目录     batch_extract_text_from_word(input_directory, output_directory)代码解释:os.walk(input_dir):这是一个非常强大的函数,用于遍历指定目录下的所有文件和子目录。它会返回一个生成器,每次迭代返回一个三元组 (root, dirs, files),其中 root 是当前正在遍历的目录路径,dirs 是 root 下的子目录列表,files 是 root 下的文件列表。os.path.exists(output_dir) 和 os.makedirs(output_dir):检查输出目录是否存在,如果不存在则创建。file_name.endswith(".docx") or file_name.endswith(".doc"):检查文件扩展名,确保只处理Word文档。os.path.join(root, file_name):将目录路径和文件名连接起来,形成完整的文件路径。os.path.splitext(file_name)[0]:获取文件名(不包含扩展名),用于构建输出的 .txt 文件名。with open(output_file_path, "w", encoding="utf-8") as f::以写入模式打开一个文件,并指定 utf-8 编码,以确保正确处理各种字符。with 语句确保文件在操作完成后自动关闭。错误处理与优化建议错误处理 (try-except): 在批量处理过程中,文件可能损坏、权限不足或格式异常。使用 try-except 块捕获这些异常,可以防止程序崩溃,并记录错误信息,以便后续排查。本示例中已包含基本的错误处理。文件编码: 在保存文本文件时,务必指定 encoding="utf-8"。Word文档可能包含多种语言和特殊字符,UTF-8 是最通用的编码,可以避免乱码问题。处理大文件: 对于单个非常大的Word文档,document.GetText() 可能会占用较多内存。如果遇到内存问题,可以考虑分块读取或优化 spire.doc 的相关设置(如果库支持)。多线程/多进程: 如果需要处理的Word文档数量极其庞大,并且机器有多核CPU,可以考虑使用Python的 threading 或 multiprocessing 模块实现并行处理,进一步缩短总处理时间。但这会增加代码复杂性,对于大多数场景,单线程顺序处理已经足够高效。
  • [技术干货] Python基本语法总结大全(含java、js对比)【转载】
    Python 基本语法 · JS/Java 开发者快速上手指南你会发现:Python = 更少的代码 + 更少的概念 + 更高的表达力。1. Python 是动态类型语言(像 JS,但比 JS 更简单)定义变量123a = 10b = "Hello"c = True无需 let、const、var、int 之类的关键字。变量类型由赋值决定。2. 缩进就是作用域(没有花括号)Java/JS:123if (x > 1) {  console.log('ok')}Python:12if x > 1:    print("ok")⚠️ 必须使用 4 个空格缩进(不能用 Tab)3. 基本数据类型PythonJSJavaintnumberintfloatnumberdoublestrstringStringboolbooleanbooleanlistArray数组/ArrayListtuple类似 readonly array不可变数组dictObjectMap示例:1234567age = 28               # intprice = 3.14           # floatname = "Tom"           # stris_ok = True           # boolarr = [1, 2, 3]        # listt = (1, 2)             # tupleuser = {"name": "Tom"} # dict4. 条件语句(更自然)123456if score > 90:    print("A")elif score > 60:    print("B")else:    print("C")注意:elif = else if5. 循环for 循环(更像 Java 的 foreach)12for item in [1, 2, 3]:    print(item)range12345for i in range(5):   # 0,1,2,3,4    print(i) for i in range(1, 5):  # 1,2,3,4    print(i)6. 函数定义Java/JS:123function add(a, b) {  return a + b}Python:12def add(a, b):    return a + b12def add(a, b) -> str:    return a + b-> str 完全可以不要,: 是函数必须的7. 类与对象Java:1234class User {  String name;  User(String name) { this.name = name; }}Python(更简洁):123456class User:    def __init__(self, name):        self.name = name u = User("Tom")print(u.name)关键点:构造函数是 __init__方法第一个参数必须是 self8. 字符串(功能超强)f-string(Python 最好用的语法)123name = "Tom"age = 18print(f"My name is {name}, age {age}")9. 列表(list)的常用操作123456arr = [1, 2, 3] arr.append(4)arr.insert(0, 100)arr.remove(2)print(len(arr))列表推导式(神器 🔥)12squares = [x*x for x in range(5)]print(squares)  # [0,1,4,9,16]10. 字典(dict)12345678910user = {    "name": "Tom",    "age": 20} print(user["name"])user["age"] = 30 for key, val in user.items():    print(key, val)11. 异常处理(与 Java 类似)123456try:    x = 10 / 0except ZeroDivisionError:    print("不能除以 0")finally:    print("done")12. 文件操作(非常简单)12345with open("test.txt", "r") as f:    content = f.read() with open("a.txt", "w") as f:    f.write("hello")13. 模块与导入Java:1import java.util.List;JS:1import fs from 'fs';Python:12import mathfrom math import sqrt14. Python 对象打印超级方便1print(user)你不需要写 JSON.stringify,也不需要重写 toString。15. 虚拟环境(推荐)123python -m venv venvsource venv/bin/activate  # Mac/Linuxvenv\Scripts\activate     # Windows16. pip 安装库1pip install requests示例:1234import requests res = requests.get("https://api.github.com")print(res.json())17. Pythonic 语法总结(从 JS/Java 转过来最常用)✓ 多重赋值1a, b = 1, 2✓ 三元表达式1msg = "ok" if x > 1 else "fail"✓ enumerate12for index, item in enumerate(arr):    print(index, item)✓ 交换变量1a, b = b, a✓ 一行读取文件1data = open("a.txt").read()继续为你输出 Python 快速上手指南(面向 JS & Java 工程师)。你可以随时说“继续”往下扩展更多内容。10. 列表推导式(List Comprehension)🔥这是 Python 最经典、最强大的语法之一。JS/Java 写法:1234const arr = [];for(let i=0; i<5; i++){  arr.push(i * i);}Python 一行:1squares = [x * x for x in range(5)]带条件:1evens = [x for x in range(10) if x % 2 == 0]11. 字典(dict)常用操作(相当于 JS Object / Java HashMap)创建:1user = {"name": "Tom", "age": 18}访问:12print(user["name"])print(user.get("age"))修改:1user["age"] = 20遍历:12for key, value in user.items():    print(key, value)12. 异常处理(类似 Java,更好用)123456try:    1 / 0except ZeroDivisionError as e:    print("Error:", e)finally:    print("done")13. 文件读写(非常简单)写文件:12with open("a.txt", "w", encoding="utf-8") as f:    f.write("hello")读文件:12with open("a.txt", "r", encoding="utf-8") as f:    content = f.read()with 会自动 close 文件。14. 模块与导入(import)相当于 JS 的 import,Java 的 import。12import mathprint(math.sqrt(16))from 写法:12from math import sqrtprint(sqrt(16))导入别名:1import numpy as np15. Python 的常用数据结构总结(对比 JS & Java)PythonJSJavalistArrayArray / ArrayListtuple无等价(类似 readonly array)不可变数组dictObject / MapHashMapsetSetHashSet16. Python 的强大语法糖✦ 解构赋值(JS 也有,但 Python 更强)1a, b = 1, 2交换变量(无需临时变量):1a, b = b, a解构列表:1x, y, z = [10, 20, 30]17. Lambda(匿名函数)JS:1const add = (a, b) => a + bPython:1add = lambda a, b: a + b用在排序中非常常见:1arr.sort(key=lambda x: x["age"])18. 装饰器(类似 JS 的高阶函数 + 注解功能)最基本的形式:123456789def log(fn):    def wrapper(*args, **kwargs):        print("call", fn.__name__)        return fn(*args, **kwargs)    return wrapper @logdef hello():    print("hi")19. Python 的包管理(pip)安装包:1pip install requests升级包:1pip install -U requests20. 虚拟环境(venv)—— 类似 JS 的 node_modules 隔离创建:1python -m venv venv激活(Mac/Linux):1source venv/bin/activate激活(Windows):1venv\Scripts\activate退出:1deactivate21. Python 异步(async/await)几乎与 JS 一样。12345678import asyncio async def hello():    print("Hello")    await asyncio.sleep(1)    print("World") asyncio.run(hello())22. f-string(Python 的模板字符串)1return f"It's always sunny in {city}!"f-string 是 Python 拼接字符串最常用的方式。等价于 JS 的模板字符串:1return `It's always sunny in ${city}!`23. 三引号字符串三引号字符串放在函数第一行 = 函数注释(用于文档、IDE 提示、help())。123def get_weather(city: str) -> str:    """Get weather for a given city."""    return f"It's always sunny in {city}!"相当于 Java 的:123/** * Get weather for a given city. */24. 类型是否必须写,是否有类似js和ts的区分类型 不是必写!不区分!只有一个 Python。但 Python 允许可选写类型注解,因此:Python = JS(动态) + TS(可选标注)写不写类型都能运行(不像 TS 那样必须编译检查)Python 官方把这套类型系统称为 Type Hints(类型提示)。Python 的类型注解是“提示”,不是“限制”例如:1234def add(a: int, b: int) -> int:    return a + b print(add("hello", "world"))照样运行……输出 "helloworld"(因为 Python 不强制类型)要强制检查必须使用外部工具,比如:mypypyrightpylance(VSCode)PyCharm 自带类型分析什么时候推荐写:大型项目团队协作需要 IDE 提示API 层数据结构定义
  • [技术干货] Python利用PyMobileDevice3控制iOS设备的完整教程【转载】
    PyMobileDevice3是一个纯Python 3实现的iOS设备控制工具库,为开发者和技术爱好者提供了强大的iOS设备管理能力。这个跨平台工具支持Windows、Linux和macOS系统,能够与iPhone等iOS设备进行深度交互,实现设备发现、文件管理、调试分析等丰富功能。快速安装指南基础安装PyMobileDevice3提供两种安装方式。最简单的方法是通过PyPi安装:1python3 -m pip install -U pymobiledevice3如需安装最新开发版本,可以从源码安装:123git clone https://gitcode.com/gh_mirrors/py/pymobiledevice3cd pymobiledevice3python3 -m pip install -U -e .平台特定配置不同操作系统需要额外的依赖配置:Windows用户:需要安装iTunes来提供必要的驱动程序支持。Linux用户:需要安装usbmuxd服务,在Ubuntu上可以通过apt安装:1sudo apt install usbmuxd所有平台:如需支持旧版iOS设备(iOS < 13),需要安装OpenSSL库:macOS: brew install opensslLinux: sudo apt install openssl自动补全功能安装完成后,可以启用命令自动补全功能:1pymobiledevice3 install-completions支持bash、zsh和fish等主流shell。核心功能详解设备发现与管理PyMobileDevice3支持通过USB和网络发现连接的iOS设备:12pymobiledevice3 usbmux listpymobiledevice3 bonjour rsd系统日志监控实时查看设备系统日志,包括调试信息:12pymobiledevice3 syslog livepymobiledevice3 syslog live -m SpringBoard文件系统操作通过AFC服务管理设备文件系统:1pymobiledevice3 afc shell应用管理查看和管理设备上安装的应用程序:12pymobiledevice3 apps listpymobiledevice3 apps query 应用包名常见使用场景设备调试与诊断重启设备:pymobiledevice3 diagnostics restart获取崩溃报告:pymobiledevice3 crash pull /保存路径进程管理:查看运行中的进程和详细信息网络分析使用PCAP功能进行网络流量嗅探:1pymobiledevice3 pcap备份与恢复创建完整设备备份:1pymobiledevice3 backup2 backup --full 备份目录从备份恢复设备:1pymobiledevice3 backup2 restore 备份目录开发者功能启用开发者模式后,可以使用高级功能:屏幕截图:pymobiledevice3 developer dvt screenshot 保存路径位置模拟:设置虚拟地理位置性能监控:查看设备性能和能耗数据进阶技巧开发者模式配置iOS 17及以上版本需要使用新的CoreDevice框架:12345# 启用远程配对pymobiledevice3 remote pair # 启动隧道服务sudo pymobiledevice3 remote tunneld网络隧道配置建立TCP端口转发:1pymobiledevice3 usbmux forward 主机端口 设备端口自动化测试结合WebInspector进行Web自动化测试:12pymobiledevice3 webinspector js-shellpymobiledevice3 webinspector launch URL注意事项权限要求:部分功能需要root或管理员权限设备连接:确保设备已信任连接的计算机iOS版本兼容性:某些功能需要特定iOS版本支持开发者模式:高级功能需要先在设备上启用开发者模式故障排除如果遇到连接问题:检查USB连接线是否正常确认设备已解锁并信任计算机验证相关服务(如usbmuxd)是否正常运行PyMobileDevice3为iOS设备管理提供了强大的Python接口,无论是日常设备管理还是深度开发调试,都能提供全面的解决方案。
  • [技术干货] Python flash URL访问参数配置【转载】
    1. 路径参数(Route Parameters)路径参数指的是 URL 路径中的一部分被当作变量传递给视图函数。示例1234567from flask import Flask  app = Flask(__name__)  @app.route('/user/<username>')def show_user_profile(username):    return f'User: {username}'访问 /user/alice,返回 User: alice<username> 是路径参数类型转换可以指定参数类型:<int:id>:只匹配整数<float:score>:只匹配浮点数<path:subpath>:匹配路径(可包含 /)123@app.route('/post/<int:post_id>')def show_post(post_id):    return f'Post ID: {post_id}'2. 查询参数(Query Parameters)查询参数是 URL 中 ?key=value 的部分,常用于 GET 请求。示例1234567from flask import request  @app.route('/search')def search():    keyword = request.args.get('keyword', '')    page = request.args.get('page', 1)    return f'Search: {keyword}, Page: {page}'访问 /search?keyword=python&page=2,keyword 和 page 就能从 request.args 获取。3. 表单参数(Form Parameters)用于 POST 请求,通过表单提交的数据。示例1234567from flask import request  @app.route('/login', methods=['POST'])def login():    username = request.form.get('username')    password = request.form.get('password')    return f'Logging in: {username}'4. JSON 参数用于 POST 请求,客户端以 JSON 格式发送数据。示例123456from flask import request  @app.route('/api/data', methods=['POST'])def api_data():    data = request.get_json()    return f'Received: {data}'5. 多参数/默认值/类型转换request.args.get('key', default, type=type) 可以设置默认值和类型路径参数类型见前文1page = request.args.get('page', 1, type=int)6. 路径参数进阶多个参数你可以在路由中定义多个参数:123@app.route('/book/<int:book_id>/chapter/<int:chapter_id>')def show_chapter(book_id, chapter_id):    return f'Book: {book_id}, Chapter: {chapter_id}'可选参数Flask 的路由不支持直接可选参数,但可以通过多个路由实现:1234567@app.route('/item/')@app.route('/item/<int:item_id>')def show_item(item_id=None):    if item_id:        return f'Item ID: {item_id}'    else:        return 'No Item ID'7. 查询参数进阶获取所有参数request.args 是一个类似字典的对象,可以获取所有参数:1234@app.route('/params')def params():    all_params = request.args.to_dict()    return str(all_params)多值参数如果一个参数可能有多个值,比如 ?tag=python&tag=flask:tags = request.args.getlist('tag')8. 表单参数进阶获取所有表单数据1234@app.route('/submit', methods=['POST'])def submit():    form_data = request.form.to_dict()    return str(form_data)文件上传12345@app.route('/upload', methods=['POST'])def upload():    file = request.files['file']    file.save(f'./uploads/{file.filename}')    return 'File uploaded!'9. JSON参数进阶校验 JSON 数据可以用 Flask 的 request.get_json(force=True) 强制解析 JSON:123456@app.route('/json', methods=['POST'])def json_view():    data = request.get_json(force=True)    if not data or 'name' not in data:        return 'Missing name!', 400    return f"Hello, {data['name']}"10. 路由中的 URL 构建Flask 推荐使用 url_for 来生成 URL,避免硬编码:12345678from flask import url_for  @app.route('/profile/<username>')def profile(username):    return f'Profile: {username}'  # 在其他地方url = url_for('profile', username='alice')11. 常见问题与调试技巧路由冲突:多个路由路径一致时,只有第一个生效。参数类型错误:比如 <int:id>,如果访问 /user/abc 会 404。使用 request.args.get('key', type=int) 可以避免类型转换错误。推荐使用 Flask 的调试模式:app.run(debug=True)12. 最佳实践路由参数尽量加类型限制,提升安全性和可读性。查询参数建议设置默认值和类型转换。表单和 JSON 数据建议做数据校验。使用 url_for 生成 URL,避免硬编码。对外暴露的 API 建议使用 RESTful 风格。13. 典型应用场景举例RESTful API 路由设计1234567891011@app.route('/api/users/<int:user_id>', methods=['GET', 'PUT', 'DELETE'])def user_api(user_id):    if request.method == 'GET':        # 查询用户信息        ...    elif request.method == 'PUT':        # 更新用户信息        ...    elif request.method == 'DELETE':        # 删除用户        ...搜索分页接口1234567@app.route('/search')def search():    keyword = request.args.get('keyword', '')    page = request.args.get('page', 1, type=int)    size = request.args.get('size', 10, type=int)    # 返回搜索结果    ...14. 参数校验与错误处理路径参数校验Flask 路由定义时已做基本类型校验(如 <int:id>),但有时需要更复杂的校验,可以在视图函数内处理:123456@app.route('/user/<username>')def user_profile(username):    if not username.isalnum():        return "用户名不合法", 400    # 继续处理    ...查询参数校验常见做法是判断参数是否存在、类型是否正确:123456789@app.route('/search')def search():    keyword = request.args.get('keyword')    if not keyword:        return "缺少搜索关键词", 400    page = request.args.get('page', default=1, type=int)    if page < 1:        return "页码必须大于0", 400    ...JSON 参数校验建议结合 pydantic 或 marshmallow 进行结构化校验:123456789101112131415from flask import requestfrom marshmallow import Schema, fields, ValidationError  class UserSchema(Schema):    name = fields.Str(required=True)    age = fields.Int(required=True)  @app.route('/api/user', methods=['POST'])def create_user():    try:        data = UserSchema().load(request.get_json())    except ValidationError as err:        return err.messages, 400    # data 是校验后的字典    ...15. RESTful 风格参数设计GET 用于查询(通过路径参数、查询参数)POST 用于创建(通过 JSON、表单参数)PUT/PATCH 用于更新(通过路径参数+JSON)DELETE 用于删除(通过路径参数)示例:1234567891011@app.route('/api/items/<int:item_id>', methods=['GET', 'PUT', 'DELETE'])def item_api(item_id):    if request.method == 'GET':        # 查询        ...    elif request.method == 'PUT':        # 更新        ...    elif request.method == 'DELETE':        # 删除        ...16、Flask 2.0 及以上版本提供的新路由注册方式(1). 基本用法@app.get注册一个只响应 GET 请求的路由:12345678from flask import Flask, request  app = Flask(__name__)  @app.get('/hello')def hello():    name = request.args.get('name', 'World')    return f'Hello, {name}!'等价于:123@app.route('/hello', methods=['GET'])def hello():    ...@app.post注册一个只响应 POST 请求的路由:1234@app.post('/submit')def submit():    data = request.form.get('data')    return f'You submitted: {data}'等价于:123@app.route('/submit', methods=['POST'])def submit():    ...(2). 混合用法如果你希望同一路由支持多种方法(比如 GET 和 POST),还是需要用 @app.route:1234567@app.route('/login', methods=['GET', 'POST'])def login():    if request.method == 'GET':        return 'Login Page'    else:        username = request.form.get('username')        return f'Welcome, {username}'(3). 适用场景@app.get('/xxx') 适合只读接口(查询、页面渲染等)。@app.post('/xxx') 适合只写接口(表单提交、数据创建等)。多方法共用时,仍建议用 @app.route()。(4). 版本要求需要 Flask 2.0 及以上版本。低于 2.0 的 Flask 没有 @app.get 和 @app.post,只能用 @app.route()。(5). 代码示例123456789101112from flask import Flask, request  app = Flask(__name__)  @app.get('/api/info')def get_info():    return {'info': 'This is a GET endpoint'}  @app.post('/api/info')def post_info():    data = request.get_json()    return {'received': data}(6). 总结@app.get('/path') == @app.route('/path', methods=['GET'])@app.post('/path') == @app.route('/path', methods=['POST'])让代码更简洁、语义更明确只在 Flask 2.0+ 可用17. 使用 Flask 扩展简化参数处理Flask-RESTful简化 REST API 的参数获取和校验:1234567891011121314from flask import Flaskfrom flask_restful import Resource, Api, reqparse  app = Flask(__name__)api = Api(app)  class Hello(Resource):    def get(self):        parser = reqparse.RequestParser()        parser.add_argument('name', type=str, required=True, help='Name cannot be blank')        args = parser.parse_args()        return {'hello': args['name']}  api.add_resource(Hello, '/hello')Flask-Swagger / Flask-apispec自动生成接口文档,并支持参数校验。18. 参数默认值与类型转换技巧request.args.get('key', default=xxx, type=xxx)request.form.get('key', default=xxx, type=xxx)示例:1limit = request.args.get('limit', default=10, type=int)19. 复杂数据结构的参数处理有时候前端会以数组、字典等复杂结构传参,常见方式:查询参数:?ids=1&ids=2&ids=3,用 getlistJSON 参数:直接传递复杂结构12ids = request.args.getlist('ids')# JSON: request.get_json()['items']20. 参数安全与防注入对路径参数、查询参数、表单参数都要做校验(长度、格式、类型、特殊字符)对 SQL 查询要用 ORM 或参数化防止 SQL 注入对文件上传要检查文件类型和大小21. 实际项目中的参数设计建议路由设计要简洁、语义清晰参数命名统一,避免歧义必填参数要明确说明,选填参数要有合理默认值错误返回要有明确提示(如 400 Bad Request)22. 常见问题答疑参数获取不到? 检查请求方法、参数名和数据格式是否一致。类型转换失败? 用 type=int 等参数,或在代码里 try/except 捕获异常。参数冲突? 路由和参数名要避免重名,优先使用 RESTful 风格。
  • [技术干货] Python获取Docker容器实时资源占用(CPU、内存、IO等)5种实现方式【转载】
    一、使用docker stats --no-stream最简版(适合快速查看)12345678910111213# -*- encoding: utf-8 -*-from subprocess import Popen, PIPE, STDOUT def Run_Cmd(cmd):    p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)    stdout, _ = p.communicate()    return p.returncode, stdout.strip().decode() if __name__ == "__main__":    cmd = 'docker stats --no-stream'        # 获取所有容器    # cmd = 'docker stats 92d1f89c5bb4 --no-stream'  # 指定容器    code, out = Run_Cmd(cmd)    print(out)输出示例:CONTAINER ID   NAME             CPU %     MEM USAGE / LIMIT     MEM %     NET I/O         BLOCK I/O       PIDS7d0d088b44e6   centos7-novnc2   0.02%     144.2MiB / 7.774GiB   1.81%     2.44kB / 0B     249MB / 403MB   99优点:简单直接缺点:输出是人类可读的表格,不利于程序解析二、使用--format自定义输出 + 结构化解析(推荐)12345678910111213141516171819202122232425262728293031323334# -*- encoding: utf-8 -*-from subprocess import Popen, PIPE, STDOUT def Run_Cmd(cmd):    p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)    stdout, _ = p.communicate()    return stdout.strip() if __name__ == "__main__":    cmd = ('docker stats --no-stream --format '           '"{{.BlockIO}}#{{.CPUPerc}}#{{.Container}}#{{.ID}}#'           '{{.MemPerc}}#{{.MemUsage}}#{{.Name}}#{{.NetIO}}#{{.PIDs}}##"')     result = Run_Cmd(cmd).decode("utf-8")    container_list = []     for line in result.split("##"):        if not line:            continue        fields = line.split("#")        info = {            'BlockIO':   fields[0],            'CPUPerc':   fields[1],            'Container': fields[2],            'ID':        fields[3],            'MemPerc':   fields[4],            'MemUsage':  fields[5],            'Name':      fields[6],            'NetIO':     fields[7],            'PIDs':      fields[8]        }        container_list.append(info)     print(container_list)输出:[{'BlockIO': '249MB / 403MB', 'CPUPerc': '0.02%', 'Container': 'centos7-novnc2', ...}]优点:结构化数据、易于转为 JSON、前后端交互友好三、使用 subprocess 列表方式(更安全,避免 shell 注入)1234567891011121314151617181920212223242526272829from subprocess import Popen, PIPEimport json try:    shell = [        'docker', 'stats', 'centos7-novnc2', '--no-stream', '--format',        '{{.BlockIO}}#{{.CPUPerc}}#{{.Container}}#{{.ID}}#'        '{{.MemPerc}}#{{.MemUsage}}#{{.Name}}#{{.NetIO}}#{{.PIDs}}'    ]         p = Popen(shell, stdout=PIPE, stderr=PIPE)    response = {"code": 200, "msg": "success", "data": []}         for line in p.stdout.readlines():        line = line.decode("utf-8").strip()        if not line:            continue        ls = line.split("#")        info = {            'BlockIO':   ls[0], 'CPUPerc': ls[1], 'Container': ls[2],            'ID':        ls[3], 'MemPerc': ls[4],  'MemUsage': ls[5],            'Name':      ls[6], 'NetIO':   ls[7],  'PIDs':    ls[8].strip()        }        response["data"].append(info) except FileNotFoundError:    response = {"code": 500, "msg": "docker 未安装"} print(json.dumps(response, ensure_ascii=False, indent=2))推荐用于 Web 接口返回 JSON 数据四、自动生成--format模板的小工具(偷懒神器)12345678910p = {"BlockIO":"249MB / 403MB","CPUPerc":"0.02%","Container":"centos7-novnc2",     "ID":"7d0d088b44e6","MemPerc":"1.81%","MemUsage":"144.2MiB / 7.774GiB",     "Name":"centos7-novnc2","NetIO":"2.44kB / 0B","PIDs":"99"} pd = []for i, k in enumerate(p.keys()):    pd.append(f"{{{{.{k}}}}}#")    print(f"p.update({{'{k}': ls[{i}]}})")print("\n生成的 format 字符串:")print("".join(pd))运行后自动输出:docker stats --no-stream --format "{{.BlockIO}}#{{.CPUPerc}}#{{.Container}}#..."以后想加新字段,直接改字典再运行即可五、持续监控 + 计算平均内存使用率(适合压测报告)1234567891011121314151617181920212223242526272829# -*- encoding: utf-8 -*-from subprocess import Popen, PIPE, STDOUTimport time def get_mem_usage(container_name):    cmd = f'docker stats {container_name} --no-stream'    p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)    output = p.stdout.read().decode("utf-8")    lines = output.strip().split("\n")    if len(lines) < 2:        return 0.0    # 第2行是数据,MemPerc 在第5列(索引4)    mem_perc = lines[1].split()[4]  # 例如: 1.81%    return float(mem_perc.rstrip("%")) if __name__ == "__main__":    container = "centos7-novnc2"    total = 0.0    count = 120     print("开始监控容器内存使用率(每3秒采样一次,共120次)\n")    for i in range(1, count + 1):        mem = get_mem_usage(container)        total += mem        avg = total / i        print(f"第{i:3d}次 | 当前: {mem:5.2f}% | 累计平均: {avg:.2f}%")        time.sleep(3)     print(f"\n120次采样平均内存使用率:{total/count:.2f}%") 适用于:压测前后资源占用对比自动化报告生成容器资源预警总结对比方式是否结构化是否安全是否适合生产推荐场景直接 shell=True 输出表格否一般调试用快速查看--format + split("#")是推荐强烈推荐前后端、监控系统subprocess 列表传参是高生产首选Web API 接口自动生成模板脚本--开发辅助快速扩展字段循环采样统计平均值是推荐压测/报告性能测试分析
  • [技术干货] Python基于OpenPyxl实现Excel转PDF并精准控制分页【转载】
    在 Python 自动化办公(RPA)的场景中,我们经常需要自动生成带有图表或图片的 Excel 报表,并最终将其导出为 PDF。但你是否遇到过这种情况:代码跑得很欢,生成的 Excel 也很完美,但一转成 PDF,精美的图表刚好被切成了两半,一半在第一页页脚,另一半在第二页页眉?这不仅难看,还显得非常不专业。今天,我们就来聊聊如何利用 openpyxl 中的 Break 对象,精准控制分页,让你的报表“指哪打哪”。核心原理:手动管理分页符Excel 本身是基于单元格(Grid)流式布局的,图片是悬浮在单元格之上的层(Layer)。默认情况下,Excel 的自动分页逻辑只看单元格高度,完全不管上面有没有压着图片。要解决这个问题,我们需要“强行”告诉 Excel:“这里不仅是图片结束的地方,也是这一页结束的地方。”这就需要用到 openpyxl.worksheet.pagebreak.Break。简单来说,我们的策略是:在插入图片之前和之后,分别插入一个 Row Break(行分页符),给图片划定一个独立的“安全区”。实战代码我们需要用到 openpyxl 库。如果你还没有安装,请执行:1pip install openpyxl pillow1. 基础实现:不跨页的核心逻辑下面的代码演示了如何在一个 Excel 中插入图片,并确保每张图片都独占一页(或者至少保证图片头部是从新的一页开始)。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263from openpyxl import Workbookfrom openpyxl.drawing.image import Imagefrom openpyxl.worksheet.pagebreak import Breakfrom openpyxl.utils import get_column_letter def create_pdf_friendly_report():    wb = Workbook()    ws = wb.active    ws.title = "图片不跨页示例"     # 假设我们有一组图片路径    image_paths = ["chart1.png", "chart2.png", "chart3.png"] # 请确保目录下有这些图片,或替换为实际路径         current_row = 1         for idx, img_path in enumerate(image_paths):        try:            img = Image(img_path)        except FileNotFoundError:            print(f"找不到图片: {img_path},跳过")            continue         # --- 核心步骤 1: 插入前置分页符 (Before Break) ---        # 如果不是第一张图,我们在图片开始前强制换页,保证图片从页首开始        if idx > 0:            # 注意:Break 的 id 对应的是行索引。            # 在 current_row - 1 处打断,意味着 current_row 将是新的一页的开始            page_break = Break(id=current_row - 1)            ws.row_breaks.append(page_break)         # --- 步骤 2: 放置图片 ---        # 定位单元格,例如 A1, A20, A40...        cell_location = f"A{current_row}"        ws.add_image(img, cell_location)                 # 添加一些描述文字(可选)        ws[cell_location] = f"图表 {idx + 1}: 销售数据分析"         # --- 步骤 3: 计算图片占用的行数 ---        # 这是一个估算。Excel默认行高约 15 像素(20 units)。        # 我们需要根据图片高度计算它大概跨越了多少行,以便更新 current_row        # img.height 是像素值        rows_to_skip = int(img.height / 20) + 2 # +2 是留一点余量                 # --- 核心步骤 4: 插入后置分页符 (After Break) ---        # 计算图片结束的行        end_row = current_row + rows_to_skip                 # 在图片结束后强制换页(如果你希望一页只有一张图)        # 如果你希望紧接着放文字,这步可以省略,只依赖“前置分页符”即可        break_after = Break(id=end_row)        ws.row_breaks.append(break_after)         # 更新下一张图的起始位置        current_row = end_row + 1     # 保存结果    wb.save("完美分页报表.xlsx")    print("Excel 生成完毕,请打开打印预览查看分页效果。") if __name__ == "__main__":    # 为了演示,请先准备几张名为 chart1.png 等的图片,或者修改代码中的路径    create_pdf_friendly_report()2. 代码解析1.from openpyxl.worksheet.pagebreak import Break: 这是主角。它是 OpenPyxl 用来标记分页符的类。2.ws.row_breaks.append(...): 工作表对象有一个 row_breaks 列表。我们将创建好的 Break 对象添加进去即可。注意: 还有一个 col_breaks,那是用于横向分页的(列宽不够时),但处理图片跨页通常使用的是行分页。3.Break(id=row_index): 这里的 id 是关键。OpenPyxl 的逻辑是:当你把 id 设为 10,Excel 会在第 10 行之后不仅是一条分界线,第 11 行将成为下一页的第一行。进阶技巧:动态计算与流式布局上面的代码是“一页一张图”的暴力解法。如果你希望文字和图片混排,仅在图片即将跨页时才插入分页符,该怎么办?这就需要计算“当前页剩余高度”。但这在纯 Python 端很难精确做到,因为 Excel 的渲染受打印机驱动、页边距设置影响很大。推荐的工程化方案:不要去计算“能不能塞得下”,而是防御性分页。策略:将“标题 + 图片 + 图片说明”视为一个原子块(Block)。操作:在这个原子块开始之前,无条件插入一个 Break(除非它是文档的开头)。虽然这可能会导致上一页留有较多空白,但它能 100% 保证图片完整展示。12345678910111213141516171819def insert_atomic_block(ws, img_path, title, start_row):    """    插入一个原子块,并强制在块之前分页    """    # 1. 强制分页(开启新的一页)    if start_row > 1:        ws.row_breaks.append(Break(id=start_row - 1))         # 2. 写入标题    ws.cell(row=start_row, column=1, value=title)         # 3. 插入图片    img = Image(img_path)    ws.add_image(img, f"A{start_row + 1}")         # 4. 返回下一个可用的行号    # 估算高度:标题1行 + 图片高度/20 + 余量    height_rows = 1 + int(img.height / 20) + 2    return start_row + height_rows总结利用 openpyxl.worksheet.pagebreak.Break,我们不再是被动接受 Excel 的默认打印行为,而是掌握了主动权。原理:Break(id=row) 也是对象,添加到 ws.row_breaks 列表。技巧:在图片插入前及插入后计算出的位置,分别通过代码插入分页符。效果:生成的 Excel 在打印预览或导出 PDF 时,图片将拥有独立且完整的页面空间。
  • [技术干货] Python实现将PDF转DOCX的超简单教程(附源码)【转载】
    一、环境准备使用 pdf2docx 库前,需要安装它:1pip install pdf2docx如果你使用的是国内源(推荐):1pip install pdf2docx -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后即可使用。二、PDF 转 DOCX 完整示例代码下面是一段直接可运行的示例代码,仅需三步即可完成 PDF → Word:123456789101112131415from pdf2docx import Converter pdf_file = "1.pdf"docx_file = "2.docx" # 创建转换器对象cv = Converter(pdf_file) # 执行转换cv.convert(docx_file, start=0, end=None) # 关闭转换器cv.close() print("转换完成!")代码说明pdf_file:要转换的 PDF 文件路径docx_file:需要输出的 Word 文件路径cv.convert():start=0 表示从第一页开始end=None 表示转换到最后一页转换完成后需要执行 cv.close() 释放资源三、运行效果运行后将在当前目录生成一个 2.docx 文件,格式尽可能保持与原 PDF 一致,非常适合文字类文档。四、常见问题PDF 转换后格式不完美这是 PDF → Word 转换的常见问题,尤其是复杂排版或扫描件。你可以尝试:使用 ocrmypdf 处理扫描件提升 PDF 清晰度使用 Adobe Acrobat 或 WPS 的转换功能对比效果五、方法补充Python使用pdf2docx和os模块实现批量将PDF转Word文档注意事项:1、PDF文档的后缀务必是“.pdf”,否则转换不成功2、大部分的PDF文档都可用这个程序来转换,如果是图片生成的Pdf文档,则转换不成功,原因是要将图片里的文字转换成文档涉及到人工智能的知识,它已超出这个程序的能力范围。但也不用慌,遇到此情况,可以用QQ的文件助手来帮忙,此处不赘述。完整代码:12345678910111213141516171819202122232425262728import osfrom pdf2docx import Converter  def pdf_docx():    # 获取当前工作目录    file_path = r'C:\Users\test'    # 遍历所有文件    for file in os.listdir(file_path):        # 获取文件后缀        suff_name = os.path.splitext(file)[1]        # 过滤非pdf格式文件        if suff_name != '.pdf':            continue        # 获取文件名称        file_name = os.path.splitext(file)[0]        # pdf文件名称        pdf_name = file_path + '\\' + file        # 要转换的docx文件名称        docx_name = file_path + '\\' + file_name + '.docx'        # 加载pdf文档        cv = Converter(pdf_name)        cv.convert(docx_name)        cv.close()  if __name__ == '__main__':    pdf_docx()Python使用pdf2docx模块实现PDF到Word的批量转换以下是一个可以批量将 PDF 文件转换为 Word 文档的 Python 代码示例,代码实现了遍历指定文件夹下的所有 PDF 文件,并逐个进行转换的功能:123456789101112131415161718192021222324252627282930313233import osfrom pdf2docx import Converter  def pdf_to_docx(pdf_folder, docx_folder):    """    将指定文件夹下的PDF文件批量转换为Word文档    :param pdf_folder: PDF文件所在文件夹路径    :param docx_folder: 转换后Word文档存放的文件夹路径    """    # 检查目标文件夹是否存在,不存在则创建    if not os.path.exists(docx_folder):        os.makedirs(docx_folder)      # 遍历PDF文件夹下的所有文件    for file in os.listdir(pdf_folder):        if file.endswith('.pdf'):            pdf_file_path = os.path.join(pdf_folder, file)            docx_file_path = os.path.join(docx_folder, os.path.splitext(file)[0] + '.docx')            try:                # 创建Converter对象开始转换                cv = Converter(pdf_file_path)                cv.convert(docx_file_path)                cv.close()                print(f"{pdf_file_path} 已成功转换为 {docx_file_path}")            except Exception as e:                print(f"转换 {pdf_file_path} 时出现错误: {e}")  if __name__ == "__main__":    # 指定PDF文件所在文件夹路径    pdf_folder_path = r'C:\Users\example\pdfs'    # 指定转换后Word文档存放的文件夹路径    docx_folder_path = r'C:\Users\example\docxs'    pdf_to_docx(pdf_folder_path, docx_folder_path)代码解析函数定义部分:定义了pdf_to_docx函数,它接受两个参数,pdf_folder表示存放 PDF 文件的文件夹路径,docx_folder表示转换后要存放 Word 文档的文件夹路径。在函数内部,首先检查docx_folder是否存在,如果不存在就创建该文件夹,用于确保后续能正常存放转换后的文件。文件遍历与转换部分:通过os.listdir函数遍历pdf_folder下的所有文件,对于以.pdf结尾的文件,先拼接出其完整路径(pdf_file_path),再根据文件名(去除.pdf后缀后)拼接出转换后 Word 文档的路径(docx_file_path)。接着使用Converter类创建对象并调用convert方法进行转换,转换完成后关闭对象。如果在转换过程中出现任何异常,会通过try-except语句捕获并打印出错误信息。主程序部分:在if __name__ == "__main__"语句块中,指定了实际的pdf_folder_path(存放 PDF 文件的文件夹路径)和docx_folder_path(存放 Word 文档的文件夹路径),然后调用pdf_to_docx函数开始批量转换操作。
  • [技术干货] Python多进程中避免死锁问题的六种策略【转载】
    一、先搞懂:多进程死锁到底是什么?1. 死锁的核心定义死锁是指两个或多个进程互相持有对方需要的锁(或资源),且都不释放自己持有的锁,导致所有进程都陷入“等待对方释放资源”的无限阻塞状态。2. 死锁产生的4个必要条件(缺一不可)只有同时满足以下4个条件,才会触发死锁,打破任意一个条件就能避免死锁:互斥条件:资源(如锁、文件)只能被一个进程占用;请求与保持条件:进程持有一个资源的同时,又请求另一个被占用的资源;不剥夺条件:进程已持有的资源不能被强制剥夺,只能主动释放;循环等待条件:多个进程形成“你等我、我等你”的循环等待链。3. 多进程死锁典型场景(新手高频踩坑)123456789101112131415161718192021222324252627282930313233343536import multiprocessingimport time  场景:两个进程互相等待对方的锁def process1(lock1, lock2):     进程1先拿lock1,再尝试拿lock2    lock1.acquire()    print("进程1获取了lock1,等待lock2...")    time.sleep(1)   放大死锁概率    lock2.acquire()   此时lock2已被进程2持有,进程1阻塞    print("进程1获取了lock2,执行任务")    lock1.release()    lock2.release() def process2(lock1, lock2):     进程2先拿lock2,再尝试拿lock1    lock2.acquire()    print("进程2获取了lock2,等待lock1...")    time.sleep(1)    lock1.acquire()   此时lock1已被进程1持有,进程2阻塞    print("进程2获取了lock1,执行任务")    lock1.release()    lock2.release() if __name__ == "__main__":    lock1 = multiprocessing.Lock()    lock2 = multiprocessing.Lock()         p1 = multiprocessing.Process(target=process1, args=(lock1, lock2))    p2 = multiprocessing.Process(target=process2, args=(lock1, lock2))         p1.start()    p2.start()    p1.join()    p2.join()    print("程序结束")   永远不会执行到这一行现象:程序输出“进程1获取了lock1,等待lock2...”和“进程2获取了lock2,等待lock1...”后卡死,无法继续执行。二、避免死锁的6个核心策略(从易到难)1. 策略1:使用with语句自动释放锁(最推荐)with语句会在代码块执行完成后自动释放锁,即使代码抛出异常也能保证锁释放,从根本上避免“忘记release()”导致的死锁。修复上述死锁案例(仅改锁的使用方式):12345678910111213def process1(lock1, lock2):    with lock1:   自动acquire(),代码块结束自动release()        print("进程1获取了lock1,等待lock2...")        time.sleep(1)        with lock2:            print("进程1获取了lock2,执行任务") def process2(lock1, lock2):    with lock2:        print("进程2获取了lock2,等待lock1...")        time.sleep(1)        with lock1:            print("进程2获取了lock1,执行任务")注意:这个修改仅解决“锁未释放”的问题,但上述场景仍会因“循环等待”触发死锁,需结合策略2使用。2. 策略2:统一锁的获取顺序(打破循环等待)死锁的核心诱因之一是“进程获取锁的顺序不一致”,只要让所有进程按相同的顺序获取锁,就能打破循环等待条件。最终修复死锁案例:123456789101112131415def process1(lock1, lock2):     统一先拿lock1,再拿lock2    with lock1:        print("进程1获取了lock1,等待lock2...")        time.sleep(1)        with lock2:            print("进程1获取了lock2,执行任务") def process2(lock1, lock2):     同样先拿lock1,再拿lock2(不再先拿lock2)    with lock1:        print("进程2获取了lock1,等待lock2...")        time.sleep(1)        with lock2:            print("进程2获取了lock2,执行任务")执行结果:进程1先获取lock1,进程2等待lock1;进程1执行完成释放锁后,进程2获取lock1和lock2,无死锁。3. 策略3:给锁添加超时时间(避免无限等待)multiprocessing.Lock本身不支持超时,但可使用multiprocessing.RLock(可重入锁)或threading.Lock(多进程中需通过Manager传递)的acquire(timeout)方法,设置超时时间,超时后放弃获取锁,避免无限阻塞。示例:带超时的锁获取123456789101112131415161718192021222324252627282930313233343536373839404142434445import multiprocessingimport time def process1(lock1, lock2):     获取lock1,超时时间3秒    if lock1.acquire(timeout=3):        print("进程1获取了lock1,等待lock2...")        time.sleep(1)         获取lock2,超时时间3秒        if lock2.acquire(timeout=3):            print("进程1获取了lock2,执行任务")            lock2.release()        else:            print("进程1获取lock2超时,释放lock1")            lock1.release()    else:        print("进程1获取lock1超时") def process2(lock1, lock2):    if lock2.acquire(timeout=3):        print("进程2获取了lock2,等待lock1...")        time.sleep(1)        if lock1.acquire(timeout=3):            print("进程2获取了lock1,执行任务")            lock1.release()        else:            print("进程2获取lock1超时,释放lock2")            lock2.release()    else:        print("进程2获取lock2超时") if __name__ == "__main__":     通过Manager创建支持超时的锁    manager = multiprocessing.Manager()    lock1 = manager.Lock()    lock2 = manager.Lock()         p1 = multiprocessing.Process(target=process1, args=(lock1, lock2))    p2 = multiprocessing.Process(target=process2, args=(lock1, lock2))         p1.start()    p2.start()    p1.join()    p2.join()    print("程序结束")执行结果:进程1获取lock1,进程2获取lock2;双方等待对方的锁超时后,释放自己持有的锁,程序正常结束,无死锁。4. 策略4:减少锁的使用范围(最小化锁持有时间)只在“必须保护共享资源”的代码块加锁,执行完核心逻辑后立即释放锁,缩短锁的持有时间,降低多个进程同时争用锁的概率。反面案例(锁持有时间过长):1234567def write_file(num, lock):    lock.acquire()     非核心逻辑(耗时),却持有锁    time.sleep(5)   模拟耗时操作    with open("test.txt", "a") as f:        f.write(f"进程{num}写入\n")    lock.release()正面案例(仅核心逻辑加锁):1234567def write_file(num, lock):     非核心逻辑(耗时),不持有锁    time.sleep(5)     仅写入文件时加锁    with lock:        with open("test.txt", "a") as f:            f.write(f"进程{num}写入\n")5. 策略5:使用单锁替代多锁(简化资源竞争)如果多个锁的作用是保护同一类共享资源(如多个文件都属于“数据文件”),可合并为一个全局锁,避免多锁嵌套导致的死锁。示例:单锁替代多锁12345678910111213141516171819202122232425262728import multiprocessingimport time  全局锁(替代多个文件锁)global_lock = multiprocessing.Lock()  写入文件Adef write_file_a(num):    with global_lock:        with open("file_a.txt", "a") as f:            f.write(f"进程{num}写入文件A\n")            time.sleep(1)  写入文件Bdef write_file_b(num):    with global_lock:        with open("file_b.txt", "a") as f:            f.write(f"进程{num}写入文件B\n")            time.sleep(1) if __name__ == "__main__":    p1 = multiprocessing.Process(target=write_file_a, args=(1,))    p2 = multiprocessing.Process(target=write_file_b, args=(2,))    p1.start()    p2.start()    p1.join()    p2.join()    print("写入完成")6. 策略6:使用死锁检测工具(进阶)对于复杂的多进程场景,可通过工具检测潜在的死锁:内置工具:multiprocessing.active_children()查看活跃进程,结合日志定位阻塞的进程;第三方工具:py-spy(进程分析工具),可实时查看进程调用栈,定位死锁位置:1234安装py-spypip install py-spy 分析进程(替换为你的进程ID)py-spy dump --pid 12345三、死锁排查:快速定位问题的3个方法查看进程状态:用ps -ef | grep python查看进程是否处于“D状态”(不可中断睡眠,大概率死锁);添加日志:在每个acquire()和release()前后打印日志,定位哪个锁导致阻塞;简化场景:将复杂的多进程逻辑拆分为最小可复现的demo,逐步排查死锁诱因。四、总结:避免死锁的核心原则自动释放:优先用with语句管理锁,杜绝“忘记release()”;顺序一致:所有进程按相同顺序获取多把锁,打破循环等待;超时兜底:给锁添加超时时间,避免无限阻塞;最小持有:仅在核心逻辑加锁,缩短锁的持有时间;简化锁结构:能用单锁就不用多锁,减少嵌套争用。遵循这些原则,99%的多进程死锁问题都能被规避。新手建议从“with语句+统一锁顺序”这两个最基础的策略入手,先保证程序无死锁,再根据场景优化性能。
  • [技术干货] Python实现将.py代码转换为带语法高亮的Word和PDF【转载】
    为什么 Python 代码需要语法高亮语法高亮对于提高源代码的可读性至关重要。通过使用不同的颜色区分关键字、变量、字符串和注释等元素,语法高亮帮助读者快速识别和理解代码的结构和逻辑。无论您是在编写文档、教程,还是报告,保留语法高亮可以确保您的 Python 代码清晰易懂,易于访问。前提条件在使用本指南中的任何方法之前,请确保您已安装所需的 Python 包。这些库将帮助生成带语法高亮的代码并处理文档:Pygments - 语法高亮库。Spire.Doc - 用于处理 Word 文档的 Python 库。Pillow(仅限方法 3) - 处理图像的库。您可以使用 pip 安装所需的库:123pip install pygmentspip install Spire.Docpip install pillow # 仅方法 3 需要安装完前提条件后,您就可以开始使用以下方法将 Python 代码转换为带语法高亮的格式化 Word 或 PDF 文档了。将 Python 代码转换为带语法高亮的 Word 和 PDF 的方法在本节中,我们将介绍几种将 Python 代码以语法高亮的方式嵌入到 Word 或 PDF 文档中的方法:方法 1: 将 Python 代码转换为 RTF 格式并保存为 Word。方法 2: 将 Python 代码转换为 HTML 格式并保存为 Word。方法 3: 将 Python 代码导出为图像并插入到 Word 中。方法 4(可选): 将 Python 代码保存为 PDF。每种方法都有其优点和适用场景,您可以根据需求选择最合适的方法。方法 1:将 Python 代码转换为 RTF 并保存为 Word此方法使用 Pygments 将 Python 代码转换为 RTF 格式,接着将其加载到 Spire.Doc 中并保存为 Word 文档。它提供了一种简单可靠的方式来创建带语法高亮的 Word 文档。使用场景:需要在 Word 中插入可编辑的 Python 代码。希望采用简单的方式,设置最少。优点:代码在 Word 中完全可编辑。清晰的语法高亮。可靠的报告和文档格式。示例代码:1234567891011121314151617181920212223242526from pygments import highlightfrom pygments.lexers import PythonLexerfrom pygments.formatters import RtfFormatterfrom spire.doc import * # 定义 Python 代码code = """def greet(name):    print("Hello, " + name)""" # 将代码转换为带语法高亮的 RTF 字符串rtf_text = highlight(code, PythonLexer(), RtfFormatter()) # 创建 Spire.Doc 文档对象doc = Document() # 添加段落para = doc.AddSection().AddParagraph() # 将 RTF 字符串添加到段落para.AppendRTF(rtf_text) # 将文档保存为 Word DOCX 格式doc.SaveToFile("HighlightedCode.docx", FileFormat.Docx2016)doc.Close()方法 2:将 Python 代码转换为 HTML 并保存为 Word此方法通过将 Python 代码转换为带语法高亮的 HTML 格式,并将其保存为 Word 文档,为格式提供更多控制。适合需要更精细布局、字体和间距控制的情况。使用场景:需要在格式上使用 CSS 控制。想要包含多个代码块。优点:完全控制代码的布局和样式。支持文档中的多个代码块。适合文章和手册。示例代码:1234567891011121314151617181920212223242526from pygments import highlightfrom pygments.lexers import PythonLexerfrom pygments.formatters import HtmlFormatterfrom spire.doc import * # 定义 Python 代码code = """def greet(name):    print("Hello, " + name)""" # 将代码转换为带语法高亮的 HTML 字符串html_text = highlight(code, PythonLexer(), HtmlFormatter(full=True)) # 创建 Spire.Doc 文档对象doc = Document() # 添加段落para = doc.AddSection().AddParagraph() # 将 HTML 字符串添加到段落para.AppendHTML(html_text) # 保存为 Word DOCX 格式doc.SaveToFile("HighlightedCode.docx", FileFormat.Docx2016)doc.Close()方法 3:将 Python 代码导出为图像并插入到 Word此方法将 Python 代码转换为带语法高亮的高质量图像,并将图像插入到 Word 文档中。该方法提供最佳的视觉效果,适合用于教程和书籍。使用场景:需要最佳的视觉质量。不需要在 Word 中编辑代码。优点:视觉效果最一致,呈现最佳。看起来像从 IDE 截取的屏幕截图。示例代码:123456789101112131415161718192021222324252627282930from pygments import highlightfrom pygments.lexers import PythonLexerfrom pygments.formatters import ImageFormatterfrom spire.doc import * # 定义 Python 代码code = """def greet(name):    print("Hello, " + name)""" # 将 Python 代码转换为带语法高亮的图像img_bytes = highlight(code, PythonLexer(), ImageFormatter(font_name="Consolas")) # 保存图像with open("highlight.png", "wb") as f:    f.write(img_bytes) # 创建文档对象doc = Document() # 添加段落para = doc.AddSection().AddParagraph() # 将图像添加到段落para.AppendPicture("highlight.png") # 保存为 Word DOCX 格式doc.SaveToFile("HighlightedCode.docx", FileFormat.Docx2016)doc.Close()方法 4:将 Python 代码保存为 PDF如果您希望以 PDF 格式共享 Python 代码,Spire.Doc 可以通过一行代码轻松将高亮代码转换为 PDF。使用场景:需要将带语法高亮的 Python 代码分享或发布为 PDF 格式。优点:保留格式、高亮和布局。非常适合发布、分享或打印。示例代码:12# 保存为 PDF doc.SaveToFile("HighlightedCode.pdf", FileFormat.PDF)选择最适合您的方法为了帮助您决定哪种方法最适合您的需求,以下是每种选项的比较,基于输出类型、可编辑性和视觉质量等关键因素:方法输出类型可编辑性视觉质量最适合用途Python →  RTF → DOCX文本✔ 可编辑良好报告、文档Python →  HTML → DOCX文本✔ 可编辑非常好文章、手册Python →  Image → DOCXPNG✘ 不可编辑卓越教程、书籍、博客Python →  PDFPDF✘ 不可编辑非常好分享、打印
  • [技术干货] python爬虫脚本HTTP 403 Forbidden错误怎么办?【转载】
    一、遭遇403:程序员最熟悉的陌生人“什么?昨天还能正常运行的爬虫脚本今天突然报403?!”(抓狂)相信每个和网络请求打过交道的开发者,都曾被这个HTTP 403 Forbidden错误搞得焦头烂额。就像你明明有办公室的门禁卡,但某天突然被挡在门外一样(简直让人怀疑人生)。今天我们就来彻底解剖这个"门禁系统故障",手把手带你突破403封锁!二、403错误的四大元凶(附实战解决方案)1. 权限不足:服务器说"你不配"12# 查看Nginx错误日志的正确姿势tail -f /var/log/nginx/error.log | grep 403典型症状:静态资源加载失败直接访问文件路径被拒日志出现"permission denied"解决三部曲:检查文件权限:chmod 755 /path/to/file(超级重要!)确认Nginx/Apache运行用户权限禁用目录浏览(在配置文件中加autoindex off;)2. IP黑名单:你被服务器拉黑了!检测方法:12345import requeststry:    response = requests.get('https://target.com', timeout=5)except requests.exceptions.ProxyError:    print("完蛋!IP被彻底封杀了!")破解方案:使用代理池轮换(推荐ProxyMesh服务)设置随机请求间隔(千万别用固定频率!)伪装成浏览器访问(User-Agent大全见文末)3. 请求头缺失:服务器觉得你是机器人必须携带的三大件:12345headers = {    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit...',    'Referer': 'https://www.google.com/',    'Accept-Language': 'zh-CN,zh;q=0.9'}进阶技巧:添加Cookies模拟登录状态设置合理的Accept-Encoding使用fake_useragent库自动生成UA4. 防盗链机制:你以为穿上马甲就不认识你了?反防盗链实战:1234567# Nginx配置示例(允许指定域名引用)location ~* \.(jpg|png|gif)$ {    valid_referers none blocked *.yourdomain.com;    if ($invalid_referer) {        return 403;    }}绕过方法:设置Referer为目标网站信任的域名使用Base64编码图片通过中间服务器代理资源三、那些年我踩过的403坑(血泪经验)案例1:神秘的Cloudflare防护某次爬取电商网站时,明明header设置完美,仍然收到403。最后发现是Cloudflare的JavaScript挑战(解决方法:用selenium模拟浏览器执行JS)案例2:AWS的Region限制调用AWS API时突然403,排查两小时发现是服务区域设置错误(教训:仔细检查API网关的region配置)案例3:诡异的CSRF保护Django项目本地测试正常,上线后403频发。原来是CSRF中间件把Ajax请求拦了(解决方案:在header添加X-CSRFToken)四、防患于未然的六大黄金法则尊重robots.txt:别当网络世界的野蛮人设置指数退避重试:像这样👇12345from tenacity import retry, wait_exponential @retry(wait=wait_exponential(multiplier=1, max=10))def safe_request(url):    return requests.get(url)使用官方API:能走正门就别翻墙监控速率限制:关注header里的X-RateLimit-*信息定期更换User-Agent:就像每天换衣服一样自然善用HEAD请求:先探路再正式访问五、当所有方法都失效时…试试这些终极大招:切换HTTP/HTTPS协议(有些网站对两者处理不同)改用POST请求(虽然不符合REST规范,但有时就是能过)使用移动端API(很多网站对APP端更宽容)借助Puppeteer渲染(彻底模拟真人操作)六、工具推荐(亲测好用) httpstatus.io - 深度解析HTTP状态码Postman Echo - 测试请求头的神器ScrapingBee - 无头浏览器即服务curlconverter - 将cURL命令转成各种语言代码七、写在最后遇到403错误时,记住三个关键点:不要慌:这只是一个HTTP状态码看日志:服务器其实已经把答案告诉你了换位思考:想想服务器为什么要拒绝你
  • [技术干货] python数组按中文拼音顺序排序
    在 Python 中,要对包含中文字符串的列表按照拼音顺序进行排序,可以使用 pypinyin 库将中文转换为拼音,然后基于拼音进行排序。以下是具体实现方法:方法一:使用 pypinyin 库首先安装 pypinyin 库:pip install pypinyin代码示例:from pypinyin import pinyin, Style def sort_chinese_list(lst): # 使用pypinyin获取每个字符串的拼音,并保留原字符串 decorated = [(item, pinyin(item, style=Style.NORMAL)) for item in lst] # 根据拼音排序 decorated.sort(key=lambda x: x[1]) # 提取排序后的原字符串 return [item[0] for item in decorated] # 示例列表 chinese_list = ["张三", "李四", "王五", "赵六", "阿七"] sorted_list = sort_chinese_list(chinese_list) print(sorted_list) 输出:['阿七', '李四', '王五', '张三', '赵六'] 方法二:使用 locale 模块(仅限部分系统)如果系统支持中文 locale,可以使用 locale.strcoll 进行本地化排序:import locale def sort_chinese_list(lst): # 设置中文locale(根据系统可能需要调整) locale.setlocale(locale.LC_COLLATE, 'zh_CN.UTF-8') return sorted(lst, key=lambda x: locale.strxfrm(x)) chinese_list = ["张三", "李四", "王五", "赵六", "阿七"] sorted_list = sort_chinese_list(chinese_list) print(sorted_list) 注意:locale 方法依赖系统配置,可能在某些环境中不生效,推荐优先使用 pypinyin 方法。方法三:简化版(仅首字母排序)如果只需要按首字母排序:from pypinyin import pinyin, Style chinese_list = ["张三", "李四", "王五", "赵六", "阿七"] sorted_list = sorted(chinese_list, key=lambda x: pinyin(x, style=Style.FIRST_LETTER)[0][0]) print(sorted_list) 关键点说明pypinyin 的 Style.NORMAL 会生成完整拼音(如 “张三” → [['zhang'], ['san']])如果字符串包含非中文字符,pypinyin 会保留原字符对于多音字,pypinyin 默认使用常见读音,可通过参数调整性能优化对于大型列表,可以预先计算拼音并缓存:from pypinyin import lazy_pinyin chinese_list = ["张三", "李四", "王五", "赵六", "阿七"] # 预先生成拼音映射 pinyin_map = {item: lazy_pinyin(item) for item in chinese_list} sorted_list = sorted(chinese_list, key=lambda x: pinyin_map[x]) print(sorted_list) 选择哪种方法取决于你的具体需求和运行环境。pypinyin 是最通用可靠的解决方案。
  • [技术干货] python 字符串数组删除另一个字符串数组中同样的元素
    在 Python 中,要从一个字符串数组(列表)中删除另一个字符串数组中存在的相同元素,可以使用列表推导式(List Comprehension)或集合(Set)操作。以下是几种实现方法:方法 1:列表推导式(保留顺序)list1 = ["apple", "banana", "cherry", "date"] list2 = ["banana", "date", "fig"] # 删除 list1 中存在于 list2 的元素 result = [item for item in list1 if item not in list2] print(result) # 输出: ['apple', 'cherry'] 说明:遍历 list1,仅保留不在 list2 中的元素。保持原始顺序,适合对顺序敏感的场景。方法 2:集合操作(高效去重)list1 = ["apple", "banana", "cherry", "date"] list2 = ["banana", "date", "fig"] # 转换为集合后求差集,再转回列表(顺序可能丢失) result = list(set(list1) - set(list2)) print(result) # 输出顺序可能变化,如: ['cherry', 'apple'] 说明:集合操作效率更高(O(1) 查找),但会丢失原始顺序和重复元素。适合不关心顺序且元素唯一的场景。方法 3:使用 filter 函数list1 = ["apple", "banana", "cherry", "date"] list2 = ["banana", "date", "fig"] result = list(filter(lambda x: x not in list2, list1)) print(result) # 输出: ['apple', 'cherry'] 说明:功能与列表推导式类似,但可读性稍差。方法 4:处理重复元素(保留 list1 的重复项)如果 list1 有重复元素且需全部保留(即使与 list2 重复):from collections import defaultdict list1 = ["apple", "banana", "cherry", "date", "banana"] list2 = ["banana", "date"] # 统计 list2 的元素出现次数 count_dict = defaultdict(int) for item in list2: count_dict[item] += 1 # 仅删除 list1 中与 list2 匹配的次数 result = [] for item in list1: if count_dict[item] > 0: count_dict[item] -= 1 else: result.append(item) print(result) # 输出: ['apple', 'cherry', 'banana'] 说明:仅删除 list1 中与 list2 等数量的重复项(例如 list2 有 1 个 "banana",则删除 list1 中的 1 个 "banana")。总结推荐方法 1(列表推导式):简单直观,保留顺序。高效去重:用方法 2(集合操作),但注意顺序和重复项。复杂需求(如保留部分重复项):用方法 4。