【问题标题】:Python - parse inconsistently delimted data tablePython - 解析不一致分隔的数据表
【发布时间】:2017-10-23 15:55:03
【问题描述】:

我有一个电子邮件文件夹,其中包含我需要提取并放入数据库的数据。这些电子邮件的格式都不同,所以我按照格式的相似程度对它们进行了分组。以下两封电子邮件正文是我现在尝试解析的示例:

1)

2)

因此,在我尝试提取有价值的数据(鱼群、重量、价格、部门、日期)时,我尝试了几种方法。我有一个所有可能的 30 多只股票的列表,我在整个电子邮件上运行了一个正则表达式。

fishy_re = re.compile(r'({}).*?([\d,]+)'.format('|'.join(stocks)), re.IGNORECASE|re.MULTILINE|re.DOTALL)

有人告诉我,这个 RegEx 将搜索任何出现的鱼,然后捕获后面的下一个数字,然后将两者组合在一起......它完美地完成了这项工作。但是,当我尝试添加一个额外的 .*?([\d,]+) 块来捕获 NEXT 数字(价格,如电子邮件 2 中所示)时,它无法做到这一点。

我的 RegEx 试图抢价格是不是错了?

此外,在尝试处理具有Package 交易(电子邮件 1)的电子邮件时,我再次尝试使用 RegEx 搜索包含单词 Package 的任何行,然后捕获其后面的下一个数字线。

word = ['package']
package_re = re.compile(r'({}).*?([\d,]+)'.format('|'.join(word)), re.IGNORECASE|re.MULTILINE|re.DOTALL)

但这不会产生任何结果......即使执行以下简单命令:

with open(file_path) as f:
    for line in f:
        for match in package2_re.finditer(f.read()):
            print("yes")

无法打印yes

那么有没有更有效的方法来提取Package的价格信息呢?

谢谢。

【问题讨论】:

  • 这些电子邮件是什么格式的?如果您查看“SNEMA Yellowtail”或“GB Haddock East ACE”上的文字环绕,它看起来像是某种嵌入式表格。您也许可以直接获取表格内容,而不是尝试通过文本解析来重构它。
  • 好吧对不起,如果这是一个愚蠢的问题,但我如何检查文本换行?我还认为它可能是一个嵌入式表格,但真的不知道如何将表格作为一个整体来处理
  • 我的意思是,如果你看一下上面的图片,“SNEMA Yellowtail”是文字环绕的,右边的数字是垂直居中的。这看起来像是某种形式的自动表格布局。如果您使用的是 Outlook,则可能是 HTML 表格(最有可能)或嵌入的 Excel 电子表格(不太可能但可能)。您可能已将电子邮件保存为 .msg 文件——这就是您通过拖放来保存它们时所得到的。在继续之前,您能确认一下吗?
  • 哦,明白了。好吧,右键单击并检查其属性,我发现它是一个 Thunderbird 文档 (.eml) 文件。那是你想要的信息吗?另外,在尝试解析这些电子邮件之前,我确实成功地用 BeautifulSoup 解析了 HTML 电子邮件......但是看着这些我确信它们不是相同的格式。

标签: python regex email


【解决方案1】:

我创建了自己的测试电子邮件并像这样解析它:

import bs4       # BeautifulSoup html parsing
import email     # built-in Python mail-parsing library

FNAME = "c:/users/Stephen/mail/test.eml"    # full path to saved email

# load message
with open(FNAME) as in_f:
    msg = email.message_from_file(in_f)

# message is multipart/MIME - payload 0 is text, 1 is html
html_msg = msg.get_payload(1)
# grab the body of the message
body = html_msg.get_payload(decode=True)
# convert from bytes to unicode
html = body.decode()

# now parse to get table
table = bs4.BeautifulSoup(html).find("table")
data = [[cell.text.strip() for cell in row.find_all("td")] for row in table.find_all("tr")]

返回类似的东西

[
    ['', 'LIVE WGT', ''],
    ['BGE COD', '746', ''],
    ['GBW CODE', '13,894', ''],
    ['GOM COD', '60', 'Package deal $52,500.00'],
    # etc
]

【讨论】:

  • 耶稣。在不到 10 行代码中,您完成的工作比我在 100 行代码和数小时内完成的要多。我想这就是为什么你是专家而我是初学者的原因。因此,如果可以的话,我想提出后续问题以更好地理解它:所以我尝试使用该 email 模块,但由于错误和奇怪的编码消息一直对我有用,我将不得不将电子邮件另存为 txt 文件只是为了获取其中的文本……但我认为是 body = html_msg.get_payload(decode=True) 行解决了这个问题。对吗?
  • ....因为我已经多次看到(并尝试过)该命令 a = msg.get_payload() 但它从未成功。但基本上,这段代码使用email 模块打开电子邮件,捕获电子邮件的正文并“解码”它以便阅读(我认为),然后我们使用 BeautifulSoup,因为它实际上是一个嵌入式HTML 表格,我们只需找到表格 ("table") 并提取包含数据的单元格 ("td"),其中包含 cell.text.strip()...简而言之...是吗?
  • 是的,完全正确。 msg 是一种递归结构 - 您可能需要稍微尝试一下才能找到您正在寻找的部分。在我创建的测试电子邮件中,get_payload(0) 是电子邮件的文本版本,get_payload(1) 是 html 版本(但经过 base64 编码)。第一个解码从 base64 转换为字节,第二个从字节转换为 unicode。
猜你喜欢
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-27
  • 1970-01-01
  • 2019-04-07
相关资源
最近更新 更多