如何用Python与Pandas解析Outlook *.msg邮件中的复杂表格?
还原带单元格内换行的Outlook邮件表格到Pandas DataFrame
首先,要解决这个问题,核心在于邮件表格的结构信息在纯文本中已经丢失——ExtractMsg的body属性返回的是纯文本内容,会把单元格内的硬换行和表格的行分隔符混在一起,导致直接拆分后无法正确分组。
最优方案是优先提取邮件的HTML正文(因为Outlook邮件的表格通常是HTML格式渲染的),通过HTML解析来完整保留表格结构,这比纯文本还原靠谱得多。下面是具体步骤:
方法1:解析HTML正文(推荐)
邮件的HTML版本会完整保留<table>、<td>等标签,能准确区分单元格和单元格内的换行。代码如下:
import ExtractMsg from bs4 import BeautifulSoup import pandas as pd # 读取.msg文件 msg_file = "your_email.msg" # 替换成你的文件路径 email = ExtractMsg.Message(msg_file) # 获取HTML正文(如果邮件包含HTML内容) html_content = email.htmlBody if html_content: # 用BeautifulSoup解析HTML soup = BeautifulSoup(html_content, "html.parser") # 找到目标表格(假设是邮件中的第一个表格,可根据实际调整) target_table = soup.find("table") # 逐行解析表格 table_rows = [] for row in target_table.find_all("tr"): # 提取单元格内容,保留原始换行(把<br>转成换行符) cells = [cell.get_text(strip=False).replace("\r\n", "\n").replace("<br>", "\n") for cell in row.find_all(["td", "th"])] table_rows.append(cells) # 转换为Pandas DataFrame df = pd.DataFrame(table_rows[1:], columns=table_rows[0]) print(df) else: print("该邮件没有HTML正文,将尝试纯文本还原方案")
这个方法能100%还原表格结构,包括单元格内的换行,因为HTML本身就记录了哪些换行属于单元格内部。
方法2:纯文本内容还原(当没有HTML正文时)
如果邮件只有纯文本版本,我们需要根据内容规律手动识别单元格边界。从你提供的正文内容来看,能找到几个规律:
- 表头是
A、B、C - 每一行的起始是数字(1、2、3、4、5)
C列的内容通常以c结尾(1c、2c等)
基于这些规律,我们可以合并单元格内的换行:
import ExtractMsg import pandas as pd msg_file = "your_email.msg" email = ExtractMsg.Message(msg_file) email_body = email.body # 清理纯文本:去掉空行和首尾空格 clean_lines = [line.strip() for line in email_body.split("\r\n") if line.strip()] # 提取表头和数据部分 header = clean_lines[:3] data_lines = clean_lines[3:] # 找到所有行的起始索引(数字开头的行) row_start_indices = [i for i, line in enumerate(data_lines) if line.isdigit()] row_start_indices.append(len(data_lines)) # 添加末尾标记,方便切片 # 逐行合并单元格内容 processed_rows = [] for i in range(len(row_start_indices) - 1): start = row_start_indices[i] end = row_start_indices[i+1] current_row_parts = data_lines[start:end] # A列是第一个元素 col_a = current_row_parts[0] # 找到C列的结束位置(最后一个以'c'结尾的元素) col_c_index = None for idx in range(len(current_row_parts)-1, 0, -1): if current_row_parts[idx].endswith("c"): col_c_index = idx break # 合并B、C列的内容(保留换行) if col_c_index: col_b = "\n".join(current_row_parts[1:col_c_index]) col_c = "\n".join(current_row_parts[col_c_index:]) else: # 兜底:如果没找到规律,按默认方式拆分 col_b = "\n".join(current_row_parts[1:-1]) col_c = current_row_parts[-1] processed_rows.append([col_a, col_b, col_c]) # 转换为DataFrame df = pd.DataFrame(processed_rows, columns=header) print(df)
运行后,你会得到还原后的表格,其中单元格内的换行被保留在对应的单元格中(显示为\n,在Pandas中查看时会自动换行)。
内容的提问来源于stack exchange,提问作者Ethan




