RPA+AI实现邮箱自动下载解析附件

背景:因为每个月有报销发票的需求,但每次到报销发票的时候,都需要去邮箱上一个个把发票下载下来,然后分类整理。这些都是耗时且重复的动作,就想着能不能把它自动化,同时看看能不能结合上最近大火的AI
目标:能够按要求自动下载发票文件,同时解析重命名发票文件

可以先Star一下 autoEmail

自动下载邮件中附件

这一步是很简单的啦,用Selenium就可以实现,我的是QQ邮箱。我们只需要打开浏览器按下F12一步步的查找从登录到进入邮件下载附件都需要点击哪些元素,然后用Selenium代替我们操作就行

登录

python 复制代码
BASE_URL = 'https://mail.qq.com/'
def begin():
    global origin_window_handle
    driver.get(Constant.BASE_URL)
    origin_window_handle = driver.current_window_handle

这里登录就没有做的那么麻烦,自己扫码或者输入账号密码即可。

获取邮件

登录到QQ邮箱后,通过F12可以看到主要功能区是在iframe里面,因此我们要先点击收件箱然后切换到iframe中,否则没法找到元素

python 复制代码
def switch_to_frame():
    recv_option = util.getDelayElement(By.PARTIAL_LINK_TEXT, "收件箱")
    recv_option.click()
    main_frame = util.getDelayElement(By.CSS_SELECTOR, "#mainFrame")
    driver.switch_to.frame(main_frame)

接着就获取邮件,每次只能获取当前页数的邮件,我这里是把未读和已读都获取到了

python 复制代码
def get_mail_list():
    return driver.find_elements_by_class_name("M") + driver.find_elements_by_class_name("F")

处理邮件

因为我只要处理发票的邮件,用了最简单的方式,只处理当前邮件标题是否包含发票两字,同时发票邮件包括两种,带有附件和不带有附件的,带有附件的是邮件里直接附上了发票文件。不带有附件的是邮件里给了一个链接,需要点击后才能下载或者跳转到其他网站下载。因为两种方式的处理方式不同,所以需要分开存储哪些是带有附件的哪些没带有附件。同时为了避免同名标题不同发票的情况,我们使用mailId来进行存储,后续通过mailId来定位每一个邮件

python 复制代码
def handle_mail():
    global end_flag
    invoice_list = []
    mail_list = get_mail_list()
    mail_num = len(mail_list)
    print(f'mail_num:{mail_num}, page: {current_page}')
    for mail in mail_list:
        mailid = mail.find_element(By.CSS_SELECTOR, 'td.tl.tf ').find_element(By.TAG_NAME, 'nobr').get_attribute(
            'mailid')
        title = mail.find_element_by_class_name("tt").text
        if '发票' in title:
            try:
                mail.find_element(By.CSS_SELECTOR, 'div.cij.Ju')
                invoice_list.append({'title': title, 'mailId': mailid})
            except NoSuchElementException as e:
                invoice_list.append({'title': title, 'mailId': mailid})
    print(f'-------发票: {len(invoice_list)}-------')
    for item in invoice_list:
        monitor.reset_create()
        mailId = item["mailId"]
        title = item["title"]
        tag = driver.find_element_by_xpath(f"//nobr[@mailid='{mailId}']")
        tag.click()
        time.sleep(1)
        if is_out_date():
            end_flag = True
            break
        try:
            if exist_element(By.ID, 'attachment'):
                download_attach()
                check_file(item)
            else:
                handle_no_attach()
                check_file(item)
        except Exception as e:
            record_fail(item)
        switch_to_frame()
        time.sleep(3)

处理带有附件的邮件

附件可能会有多个附件,我们只需要下载PDF文件即可

python 复制代码
def download_attach():
    attachment = util.getDelayElement(By.ID, 'attachment')
    attach_items = attachment.find_elements(By.CSS_SELECTOR, 'div.att_bt.attachitem')
    for attach in attach_items:
        util.getDelayElement(By.CSS_SELECTOR, 'div.name_big')
        if '.pdf' in attach.find_element(By.CSS_SELECTOR, 'div.name_big').find_element(By.TAG_NAME, 'span').text:
            attach.find_element_by_partial_link_text('下载').click()
            break
    time.sleep(3)
    # driver.back()
    driver.refresh()
    switch_to_frame()
    time.sleep(4)

处理没有附件的邮件

这个才是本次的重点,对于没有附件只有下载链接的邮件,如何让selenium知道该点哪里。不同的邮件他们的展示也不同

解决方法就是让AI来告诉selenium该点哪里,通过F12可以发现,邮件的内容都是在一个固定的Div里面

那我们就可以获取这个Div里面的HTML片段,然后告诉AI,让它根据HTML片段解析出带有发票下载链接的标签文本,然后返回,selenium根据这个文本点击,以下是对于prompt

python 复制代码
prompt = '''
你是一名HTML解析助手,你需要解析用户上传的HTML片段。
1.解析出片段中带有发票下载链接的超链接标签文本。
2.如果有多个下载链接,则找出下载为PDF格式的超链接标签文本即可。
例如: 
输入: 
<p style="display: flex;justify-content: flex-start;align-items: flex-start;font-size:14px;line-height:20px;">
          <span style="white-space: nowrap;color: #333">下载PDF文件:</span>
          <img width="20" src="https://img.pdd-fapiao.com/biz/bG9uZ2p1bmd3YW5n.png">
          <a href="https://www.hxpdd.com/s/Q3QQGcH49TCm" style="word-break:break-all;margin-left: 10px;color: #3786c7" rel="noopener" target="_blank">HelloWorld</a>
</p>
输出:
{"text":"HelloWorld"}
注意只需要返回对应的标签文本即可,不需要其他内容。结果输出为JSON:{'text':'xxx'}"}
'''

点击过后,一般会有两种结果,一种是点击后能够直接下载发票,另一种是跳转到其他网站后,再点击下载才能下载

针对这种我们就可以全文搜索带有下载字样的标签进行点击下载。经过上面这一套下来,基本90%的都能成功下载下来

解析整理发票

下载下来的发票命名各异

我希望能够通过文件名就能知道该发票的类型,金额和开票日期,这里用上了OCR+AI,用OCR来解析发票文件,然后将解析结果送给AI让其根据结果分析该发票属于哪种类别。最后再重命名发票

python 复制代码
def parse_invoice():
    invoice_list = get_invoice_list()
    location = config.get_location()
    for invoice in invoice_list:
        file_path = os.path.join(location, invoice)
        invoice_info = OcrUtil.ocr_invoice(file_path)
        new_file_name = get_new_file_name(invoice_info)
        util.rename(invoice, new_file_name)
        print(f'{invoice} : {new_file_name}')


def get_new_file_name(invoice_info):
    date = util.parse_date(invoice_info['Date'], '%Y年%m月%d日', '%Y%m%d')
    summary = get_summary(invoice_info)
    return summary + '_' + invoice_info['Number'] + '_' + invoice_info['Total'].split('.')[0] + '_' + date


def get_summary(item):
    if 'VatElectronicItems' in item:
        info = json.loads(json.dumps(item['VatElectronicItems']))
    else:
        info = json.loads(json.dumps(item['VatInvoiceItemInfos']))
    return AI.ai_summary(info[0]['Name'])

最后就是这个样子

使用方法

在config.json文件设置文件下载地址和日期,日期的作用是在下载附件时只下载日期之后的附件,在OcrUtil.py文件里设置腾讯云的secret_id和secret_key,在AI.py文件里设置GPT的api_key后,然后运行main.py,等待浏览器拉起后,手动登录后即可

目前只实现了下载和解析重命名,邮箱目前只支持QQ邮箱,AI目前只支持GPT,后续会支持多个邮箱和AI 同时还在考虑可以加入哪些功能,有建议和优化欢迎大家在GitHub给我提,如果有帮助的话帮忙Star一下

地址:GitHub-autoEmail

相关推荐
止语Lab2 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活2 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困2 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn2 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
用户298698530142 小时前
Python 实现 Excel 与 Markdown 互转的实用指南
后端·python·excel
用户77283104908402 小时前
krono-job:零侵入、单二进制交付的分布式任务调度平台(开源)
后端
Conan在掘金2 小时前
鸿蒙报错速查:Function lacks ending return statement,返回路径漏 return 就炸,根因 + 真解法
后端
人间凡尔赛3 小时前
AI-Native 云原生架构:2026 年从容器编排到智能体编排的范式革命
后端·云原生·架构
IT_陈寒3 小时前
Vue的响应式让我加班到凌晨3点,原来问题出在这
前端·人工智能·后端
卷无止境3 小时前
提升 Python 代码健壮性的方法大盘点
后端·python