import os from docx import Document import pandas as pd def extract_table_texts(docx_path, max_rows=30): """提取单个docx文件所有表格的前max_rows行文本""" doc = Document(docx_path) file_texts = [] # 存储当前文件所有表格的前30行文本 for table in doc.tables: table_texts = [] # 遍历表格的每一行,最多取max_rows行 for row_idx, row in enumerate(table.rows): if row_idx >= max_rows: break # 超过30行时停止 row_text = [] for cell in row.cells: text = cell.text.strip() if text: row_text.append(text) # 合并当前行的单元格文本(用逗号分隔) table_texts.append(", ".join(row_text)) # 合并当前表格的文本(用分号分隔不同行) file_texts.append("; ".join(table_texts)) # 合并所有表格的文本(用换行符分隔不同表格) return "\n".join(file_texts) def process_folder(folder_path, output_file="output.xlsx"): """处理文件夹中所有docx文件,每个文件占Excel一行""" data = [] # 遍历文件夹 for filename in os.listdir(folder_path): if filename.lower().endswith(".docx"): file_path = os.path.join(folder_path, filename) try: # 提取文本并添加到数据列表 combined_text = extract_table_texts(file_path) data.append({"文件名": filename, "表格内容(前30行)": combined_text}) except Exception as e: print(f"处理文件 {filename} 时出错: {str(e)}") # 创建DataFrame df = pd.DataFrame(data) # 保存结果(无需去重) df.to_excel(output_file, index=False) return df # 使用示例 if __name__ == "__main__": input_folder = "/path/to/your/documents" # 替换为实际路径 output_file = "extracted_texts.xlsx" result_df = process_folder(input_folder, output_file) print(f"完成!共处理 {len(result_df)} 个文件,已保存至 {output_file}")请改进代码,仅提取docx表格前42行,并且在xlsx中将基数行作一列排列,偶数行作一列排列
时间: 2025-06-23 16:18:47 浏览: 11
<think>好的,我需要帮用户改进现有的Python代码,实现两个主要目标:提取docx表格的前42行,并且在Excel中将基数行和偶数行分列排列。首先,我得仔细分析用户提供的原始代码,理解其结构和功能,然后找出需要修改的地方。
首先看原始代码中的`extract_table_texts`函数,现在它提取的是前30行,用户要求改为前42行。这个应该比较简单,把`max_rows=30`参数改成42,同时相关注释和变量名里的30也要改过来。不过要注意变量名可能不需要改,因为变量名是`max_rows`,所以参数名改成42即可,其他内部的注释可能需要调整。
接下来是更复杂的部分:在Excel中将基数行和偶数行分列排列。用户希望每个表格的基数行放在一列,偶数行放在另一列。这里需要明确,基数行和偶数行是指行号从1开始计数,即第1、3、5...行是基数行,第2、4、6...行是偶数行。需要将每个表格的这些行分别合并成字符串,然后放在不同的列中。
原来的代码中,每个表格被处理成一个用分号分隔的字符串,然后不同表格用换行分隔。现在需要将每个表格的基数行和偶数行分开存储。例如,对于每个表格,遍历每一行时,判断行号的奇偶,然后分别收集到`odd_rows`和`even_rows`两个列表中。处理完所有行后,将这两个列表用分号连接,作为两个不同的字段。
但需要考虑每个表格可能有不同的基数行和偶数行,所以每个表格处理完后,应该生成两个字符串:一个包含所有基数行,另一个包含偶数行。然后,在最终的Excel中,每个文件的这两个字符串应该怎么组织呢?用户的要求是每个文件占一行,所以可能需要将每个文件的所有表格的基数行合并到一个列,偶数行合并到另一列,或者每个表格的基数行和偶数行分开列?这需要进一步明确。
假设用户的意思是,对于每个表格,基数行放在一列,偶数行放在另一列,那么每个表格会有两列。但这样的话,多个表格会导致多列,这可能不太适合DataFrame的结构,因为每个文件对应一行,而每个表格需要两列。但用户可能希望每个文件的所有表格的基数行合并到一个列,偶数行合并到另一个列。例如,如果一个文件有3个表格,每个表格的基数行合并成一个字符串,放在“基数行”列,偶数行合并到“偶数行”列,每个文件占一行,两列。这样可能更合理。
所以,修改后的`extract_table_texts`函数需要为每个表格生成两个字符串:基数行和偶数行。然后,在`process_folder`函数中,每个文件的各个表格的基数行合并到一个字段,偶数行合并到另一个字段。或者,可能每个表格的基数行和偶数行单独存储,但这样会导致每个文件有多行数据,这不符合用户说的“每个文件占一行”。
因此,可能正确的做法是,对于每个文件,将所有表格的基数行合并成一个字符串(例如,用换行分隔不同表格),偶数行同理。这样在最终的Excel中,每个文件对应一行,两列:一列是所有表格的基数行,另一列是所有表格的偶数行。
但原代码中,每个表格的内容是用换行符分隔的,现在可能需要将基数行和偶数行分别收集,然后合并每个表格的基数行和偶数行,再合并所有表格的结果。例如,每个表格的基数行用分号分隔,偶数行也用分号分隔,然后不同表格之间用换行分隔。或者,可能每个表格的基数行和偶数行单独处理,但需要保持对应关系。
需要明确用户的需求:在Excel中,每个文件一行,其中基数行放在一列,偶数行放在另一列。每个表格的前42行中,基数行合并到基数列,偶数行合并到偶数列。例如,假设一个表格有5行,那么基数行是1、3、5行,偶数是2、4行。这些行会被收集到各自的列表中,然后用分号连接,作为该表格的基数行和偶数列。然后,所有表格的基数行部分合并成一个字符串(可能用换行分隔不同表格),偶数列同理。或者,可能每个表格的基数行和偶数列分别作为该文件的两个列中的内容,表格之间用某种分隔符分开。
原代码中,每个表格的处理结果是合并成一个字符串,不同表格用换行分隔。现在,每个表格需要拆分成两个字符串:基数行和偶数行。所以在处理每个表格时,需要生成两个字符串,然后将这两个字符串分别收集到整个文件的基数列和偶数列中,或者将每个表格的基数行和偶数列分开存储,再在合并时处理。
例如,修改后的`extract_table_texts`函数应该返回两个列表:一个包含所有表格的基数行合并后的字符串,另一个包含所有表格的偶数行合并后的字符串。或者,每个表格的基数行和偶数列分别合并,然后在文件级别将它们合并,用换行分隔不同表格的基数行和偶数列。
可能需要这样的结构:对于每个文件,收集所有表格的基数行,每个表格的基数行用分号连接,然后不同表格之间用换行分隔;同样处理偶数行。这样,最终每个文件在Excel中有两列,一列是所有表格的基数行,另一列是所有表格的偶数行,每个表格的基数行和偶数列用换行分隔。
那么,具体修改步骤如下:
1. 修改`extract_table_texts`函数,将max_rows参数改为42,并处理每个表格的前42行。
2. 在处理每个表格的行时,将基数行和偶数行分别收集到两个列表中。
3. 对于每个表格,将基数行用分号连接成字符串,偶数行同理。
4. 将每个表格的基数字符串和偶数字符串保存,然后在文件级别,将所有表格的基数行字符串用换行连接,偶数字符串同样用换行连接。这样,每个文件在最终的DataFrame中会有两列:“基数行”和“偶数行”,每个列中的内容是各个表格对应的基数或偶数行,表格之间用换行分隔。
但原来的代码中,`extract_table_texts`返回的是所有表格合并后的字符串,用换行分隔。现在需要返回两个字符串:所有表格的基数行合并,以及所有表格的偶数行合并。因此,修改`extract_table_texts`的返回值,使其返回两个字符串,然后在`process_folder`函数中将这两个字符串分别存储到DataFrame的两列中。
具体来说,修改后的`extract_table_texts`函数可能返回一个元组,包含基数行和偶数行的合并字符串。例如:
def extract_table_texts(docx_path, max_rows=42):
# 处理每个表格,收集基数和偶数行
all_odd = [] # 存储每个表格的基数行文本
all_even = [] # 存储每个表格的偶数行文本
for table in doc.tables:
odd_rows = []
even_rows = []
for row_idx, row in enumerate(table.rows, start=1): # 行号从1开始
if row_idx > max_rows:
break
# 处理单元格文本...
if row_idx % 2 == 1: # 基数行
odd_rows.append(row_text_joined)
else: # 偶数行
even_rows.append(row_text_joined)
# 将当前表格的基数和偶数行合并成字符串
table_odd = "; ".join(odd_rows)
table_even = "; ".join(even_rows)
all_odd.append(table_odd)
all_even.append(table_even)
# 合并所有表格的结果,用换行分隔
combined_odd = "\n".join(all_odd)
combined_even = "\n".join(all_even)
return combined_odd, combined_even
然后,在`process_folder`函数中,对于每个文件,调用这个函数,得到两个字符串,将它们添加到data列表中:
data.append({"文件名": filename, "基数行": combined_odd, "偶数行": combined_even})
这样,DataFrame会有三列:文件名、基数行、偶数行。每个文件的每个表格的基数行和偶数行分别存放在对应的列中,表格之间用换行分隔,每个表格内的行用分号分隔。
这样应该符合用户的需求。需要注意原来的处理方式中,每个表格的行是用分号分隔,不同表格用换行分隔。现在同样保持这种结构,但每个表格分成基数和偶数两部分。
现在,检查原始代码中的合并方式。原代码中,每个表格的行用分号分隔,不同表格用换行分隔。现在需要每个表格的基数行和偶数行分别处理,因此每个表格生成两个字符串,然后合并所有表格的基数行字符串,用换行分隔,同理偶数行。
例如,假设有两个表格:
表格1有3行(行1,2,3),则基数行是1、3,偶数行是2。合并后,表格1的基数行是“row1; row3”,偶数是“row2”。
表格2有4行(行1,2,3,4),基数是1、3,偶数是2、4。合并为“row1; row3”和“row2; row4”。
然后,所有表格的基数行合并为“表格1的基数行\n表格2的基数行”,偶数列同理。这样在Excel中,每个文件的基数列显示为两行,每个对应一个表格的内容。
这样处理后,输出Excel的结构就是每个文件一行,两列分别包含所有表格的基数行和偶数行,表格之间用换行分隔,每个表格内的行用分号分隔。
现在需要考虑如何处理没有基数行或偶数行的情况。例如,某个表格只有基数行,没有偶数行,那么对应的偶数列会是空字符串吗?代码需要处理这种情况,避免错误。
此外,在遍历行时,原代码使用`enumerate(table.rows)`,但`table.rows`的索引是从0开始还是从1开始?在Python中,`enumerate`默认从0开始,所以如果用户希望行号从1开始计算基数行和偶数行,需要设置`start=1`。例如:
for row_idx, row in enumerate(table.rows, start=1):
这样,第一行的row_idx是1,第二行是2,依此类推。这样判断`row_idx % 2 == 1`就能正确识别基数行(1、3、5...)。
综上,修改后的`extract_table_texts`函数需要:
- 参数max_rows改为42
- 遍历行时,从1开始计数
- 分别收集基数行和偶数行
- 每个表格的基数行和偶数行用分号连接
- 所有表格的基数和偶数列用换行连接
同时,在`process_folder`函数中,收集这两个字符串作为两列。
现在,检查原代码的其他部分是否需要调整。例如,原来的`file_texts`变量被用来收集所有表格的文本,现在需要替换为收集基数和偶数行的两个列表。因此,`extract_table_texts`函数的结构需要调整。
现在编写修改后的代码:
在`extract_table_texts`函数中:
初始化两个列表,`all_odd`和`all_even`,用于存储每个表格的基数和偶数行文本。
对于每个表格,初始化`current_odd`和`current_even`列表,遍历每一行,根据行号的奇偶性将行文本添加到对应的列表。处理完所有行后,将`current_odd`和`current_even`分别用分号连接,作为该表格的基数和偶数行字符串,并添加到`all_odd`和`all_even`中。最后,将`all_odd`和`all_even`用换行符连接,返回这两个字符串。
然后,在`process_folder`函数中,data列表中的每个字典包含“文件名”、“基数行”、“偶数行”三个键。
这样,生成的DataFrame会有这三列,保存到Excel时,每个文件占一行,基数和偶数列分开。
现在,测试可能的边界情况:
- 表格行数超过42行:只取前42行。
- 表格行数不足42行:取所有行。
- 行数为0:不添加任何内容。
- 某个表格只有基数行或只有偶数行:对应的列会有内容,另一列为空字符串。
- 多个表格的情况:每个表格的基数和偶数列用换行分隔。
最后,确保代码的异常处理部分仍然有效,例如在读取文件时出错,会跳过并打印错误信息。
现在,将这些修改整合到代码中,并替换原来的逻辑。</think>以下是改进后的代码,实现以下功能:
1. 提取表格前42行
2. 基数行和偶数行分列存储
3. 保留异常处理机制
4. 优化数据结构处理
```python
import os
from docx import Document
import pandas as pd
def extract_table_texts(docx_path, max_rows=42):
"""提取单个docx文件所有表格的前max_rows行,并分离基数/偶数行"""
doc = Document(docx_path)
all_odd_tables = [] # 所有表格的基数行集合
all_even_tables = [] # 所有表格的偶数行集合
for table in doc.tables:
odd_rows = [] # 当前表格的基数行(1,3,5...)
even_rows = [] # 当前表格的偶数行(2,4,6...)
# 遍历行时从1开始计数(人类可读序号)
for row_idx, row in enumerate(table.rows, start=1):
if row_idx > max_rows:
break
# 提取单元格文本
cell_texts = [cell.text.strip() for cell in row.cells if cell.text.strip()]
row_str = ", ".join(cell_texts) # 行内单元格用逗号连接
# 按行号奇偶分类
if row_idx % 2 == 1:
odd_rows.append(row_str)
else:
even_rows.append(row_str)
# 当前表格处理结果(分号连接行)
all_odd_tables.append("; ".join(odd_rows))
all_even_tables.append("; ".join(even_rows))
# 合并所有表格结果(换行分隔不同表格)
return "\n".join(all_odd_tables), "\n".join(all_even_tables)
def process_folder(folder_path, output_file="output.xlsx"):
"""处理文件夹生成Excel,含基数/偶数列"""
data = []
for filename in os.listdir(folder_path):
if filename.lower().endswith(".docx"):
file_path = os.path.join(folder_path, filename)
try:
# 获取分离后的行数据
odd_col, even_col = extract_table_texts(file_path)
data.append({
"文件名": filename,
"基数行(1,3,5...)": odd_col,
"偶数行(2,4,6...)": even_col
})
except Exception as e:
print(f"处理 {filename} 失败: {e}")
# 创建并保存DataFrame
df = pd.DataFrame(data)
df.to_excel(output_file, index=False)
return df
# 使用示例
if __name__ == "__main__":
input_folder = "/path/to/your/documents" # 替换实际路径
output_name = "分离行列结果.xlsx"
result = process_folder(input_folder, output_name)
print(f"处理完成!成功处理 {len(result)} 个文件,输出文件:{output_name}")
```
改进亮点说明(使用Markdown表格展示):
| 改进点 | 原代码 | 新代码 |
|-----------------------|---------------------------------|----------------------------------------------------------------------|
| 提取行数 | 前30行 | 前42行 |
| 行分类方式 | 所有行合并 | 基数行、偶数行分列存储 |
| 表格分隔方式 | 仅用换行符 | 基数/偶数列内部用分号连接行,表格间用换行分隔 |
| 数据结构 | 单列存储 | 双列结构(符合需求描述) |
| 行号计算方式 | 从0开始计数 | **从1开始计数**(符合人类阅读习惯) |
| 容错处理 | 保留原有try-catch | 增强错误信息可读性 |
代码使用说明:
1. 修改`input_folder`为实际文档路径
2. 输出Excel将包含三列:
- 文件名
- 基数行(1,3,5...):所有表格的奇数行数据
- 偶数行(2,4,6...):所有表格的偶数行数据
3. 每个表格数据在Excel中用换行符分隔,同一表格内的行用分号分隔
阅读全文
相关推荐










