pd.read_table读取非表格内容且数据全存入单列如何解决
问题原因
- 内容未做范围截取:直接传入全量邮件正文给解析函数,开头提示语、末尾落款等非表格内容会被全部读入
- 解析逻辑失效:预先定义的表格行匹配正则未被调用,使用
\s+作为分隔符会将所有空白字符识别为列分割标记,直接导致字段错位、内容合并 - 写入逻辑错误:文件在循环中被反复覆盖,仅会保留最后一封邮件的解析结果,初始化的
csv.writer对象未被实际使用 - 正文提取不严谨:未过滤HTML、附件类part,容易引入非正文冗余内容
修复后完整代码
import csv import re import io import email from email.header import decode_header import pandas as pd import smtplib # 常量统一定义在循环外 SENDER_EMAIL = '***@outlook.com' SENDER_PASSWORD = '***' ALERT_RECEIVER = '***@gmail.com' PO_TABLE_PATTERN = re.compile(r"([a-zA-Z]{3}[0-9]+) Line ([0-9]+) Seq ([0-9]+) ([0-9]+/[0-9]+/[0-9]+)") # 初始化CSV文件,写入表头 with open("data.csv", "w", newline='', encoding='utf-8') as f_out: writer = csv.writer(f_out) writer.writerow(["PO#", "Line#", "Seq", "Date"]) for i in range(messages, messages-N, -1): res, msg = imap.fetch(str(i), "(RFC822)") for response in msg: if not isinstance(response, tuple): continue # 解析邮件内容 msg = email.message_from_bytes(response[1]) # 解码邮件主题 subject, encoding = decode_header(msg["Subject"])[0] if isinstance(subject, bytes): subject = subject.decode(encoding if encoding else 'utf-8') # 解码发件人 From, encoding = decode_header(msg.get("From"))[0] if isinstance(From, bytes): From = From.decode(encoding if encoding else 'utf-8') print("Subject:", subject) print("From:", From) body = "" # 仅提取纯文本正文,跳过附件、HTML内容 for part in msg.walk(): content_type = part.get_content_type() content_disposition = str(part.get("Content-Disposition")) if content_type != 'text/plain' or content_disposition.startswith('attachment'): continue payload = part.get_payload(decode=True) if payload: body = payload.decode(encoding if encoding else 'utf-8', errors='ignore') break try: # 预处理表头空格,用正则提取所有有效表格行,自动过滤无关文本 processed_body = body.replace(' #', '#') table_records = PO_TABLE_PATTERN.findall(processed_body) if not table_records: raise ValueError("未匹配到有效订单表格内容") # 追加写入CSV writer.writerows(table_records) print(f"邮件解析完成,共写入{len(table_records)}条订单记录") except Exception as e: # 解析失败发送告警邮件 mail_content = 'Subject: {}\n\n{}'.format(subject, body) server = smtplib.SMTP('smtp-mail.outlook.com', 587) server.starttls() server.login(SENDER_EMAIL, SENDER_PASSWORD) server.sendmail(SENDER_EMAIL, ALERT_RECEIVER, mail_content) server.quit() print(f"解析失败,已发送告警邮件,错误:{str(e)}") imap.close() imap.logout()
关键改动说明
- 正文提取阶段仅保留
text/plain类型的非附件内容,从源头过滤HTML代码、附件内容等冗余数据 - 调用预先定义的正则做全正文匹配,仅提取符合PO行格式的内容,自动过滤前后的提示语、落款等无关文本;正则分组返回结果直接对应
PO#/Line#/Seq/Date四个目标字段,不会出现列错位、内容合并到同一列的问题 - 调整CSV写入逻辑,文件打开后先写入固定表头,后续解析到的订单行直接追加写入,不会出现循环覆盖文件的问题
- 补全编码兜底、SMTP连接关闭等边缘逻辑,避免因编码异常、连接泄漏导致的运行错误
内容的提问来源于stack exchange,提问作者LaunchCoder33
相关产品推荐
相关产品推荐

