如何简化从Docx表格提取数据到Xlsx的重复代码段?
I've written the following code which perfectly extracts data from Docx tables and imports it into an Xlsx table. Is there a way to simplify the three repeated sections in the code to make it more concise?
Here's the code:
import pandas as pd import win32com.client as win32 import openpyxl from openpyxl import Workbook from openpyxl import load_workbook word = win32.Dispatch("Word.Application") word.Visible = 0 word.Documents.Open("C:/Users/documents/flie.docx") #Change document with tables name doc = word.ActiveDocument wb = Workbook() filepath = 'C:/Users/excel.xlsx' wb.save(filepath) wb=load_workbook(filepath) sheet=wb.active # Repeated section 1 a = [] b = [] c = [] d = [] e = [] f = [] for i in (list(range(3,9)) + list(range(11,42))): table = doc.Tables(i) # Repeated section 2 a.append(table.Cell(Row = 2, Column = 2).Range.Text) b.append(table.Cell(Row = 3, Column = 2).Range.Text) c.append(table.Cell(Row = 4, Column = 2).Range.Text) d.append(table.Cell(Row = 4, Column = 2).Range.Text) e.append(table.Cell(Row = 6, Column = 2).Range.Text) f.append(table.Cell(Row = 7, Column = 2).Range.Text) # Repeated section 3 combine_table = {(table.Cell(Row = 2, Column = 1).Range.Text) : a, (table.Cell(Row = 3, Column = 1).Range.Text) : b, (table.Cell(Row = 4, Column = 1).Range.Text) : c, (table.Cell(Row = 5, Column = 1).Range.Text) : d, (table.Cell(Row = 6, Column = 1).Range.Text) : e, (table.Cell(Row = 7, Column = 1).Range.Text) : f, } labels = [list(range(1,38))] df = pd.DataFrame(combine_table , index=labels) df.to_excel("excel.xlsx")
Great question! Those repetitive sections are perfect for refactoring with structured data mappings — this will eliminate redundant variables and make your code easier to maintain. Let's walk through the simplified version step by step:
Core Idea
Instead of manually creating separate lists (a, b, etc.) and writing duplicate append calls, we'll use a list of tuples to define exactly which rows we need to pull data and labels from. This lets us handle all extraction logic in a single loop.
Refactored Code
import pandas as pd import win32com.client as win32 from openpyxl import Workbook # Initialize Word app word = win32.Dispatch("Word.Application") word.Visible = 0 doc = word.Documents.Open("C:/Users/documents/flie.docx") # Update your file path # Define mappings: (data_row, label_row) # Fixed the d entry to use row 5 for data (matches your combine_table's label from row 5) row_mappings = [ (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7) ] # Initialize data storage combine_table = {} table_indices = list(range(3,9)) + list(range(11,42)) for idx, table_num in enumerate(table_indices): table = doc.Tables(table_num) # Set up dictionary keys on first iteration if idx == 0: for _, label_row in row_mappings: # Clean up Word's extra line break characters label = table.Cell(Row=label_row, Column=1).Range.Text.strip('\r\x07') combine_table[label] = [] # Populate data for each mapping for data_row, _ in row_mappings: value = table.Cell(Row=data_row, Column=2).Range.Text.strip('\r\x07') # Get the corresponding label key label_key = list(combine_table.keys())[row_mappings.index((data_row, _))] combine_table[label_key].append(value) # Create DataFrame and save # Dynamically generate index to match number of tables processed df = pd.DataFrame(combine_table, index=list(range(1, len(table_indices)+1))) df.to_excel("C:/Users/excel.xlsx") # Clean up Word process word.Quit()
Key Improvements
- No more redundant lists: All data is stored directly in the
combine_tabledictionary, so you don't needathroughfanymore. - Single loop for extraction: The
row_mappingslist lets us handle every data point with one loop, eliminating duplicateappendcalls. - Dynamic index: Instead of hardcoding
range(1,38), we generate the index based on how many tables we process — this makes the code flexible if your table count changes. - Cleaner text: Added
.strip('\r\x07')to remove the hidden characters Word adds to cell text (you'll often see these clutter your Excel output otherwise). - Proper cleanup: Added
word.Quit()to close the Word background process (your original code left it running).
Quick note: I adjusted the d entry to pull data from row 5 instead of row 4, to match your original combine_table where the label comes from row 5. If that duplicate row 4 was intentional, just tweak the row_mappings tuple back to (4,5)!
内容的提问来源于stack exchange,提问作者thrnma

