繁体   English   中英

Python 脚本需要很长时间才能运行

[英]Python Script takes very long time to run

我设法编写了一段代码(由网络上的多个来源组成,并适应我的需要),它应该执行以下操作:

  • 读取一个excel文件
  • 从 A 列搜索来自特定文件夹的邮件主题中每个单元格的值
  • 如果匹配(单元格值等于主题的前 9 个字符),则将带有单元格值的附件(每封邮件只有一个附件,不多也不少)保存在“输出”文件夹中。
  • 如果不匹配,则转到下一封邮件,分别转到下一个单元格值。
  • 最后,显示运行时间(不是很重要,仅供我了解)

该代码实际上有效(使用只有 9 封电子邮件的电子邮件文件夹进行测试)。 我的问题是运行时间。

该脚本的实际范围是在包含 32700 封电子邮件的文件夹中查找 2539 个值并保存附件。

我已经完成了 2 次运行,如下所示:

  1. 32700 封电子邮件中的 2539 个值(约 1 小时后停止)
  2. 32700 封电子邮件中的 10 个值(约 40 分钟后停止;此时脚本处理了 4 个值)

我想知道/学习,是否有办法使脚本更快,或者它是否因为写得不好等而变慢。

下面是我的代码:

from pathlib import Path
import win32com.client
import os
from datetime import datetime
import time
import openpyxl

#name of the folder created for output
output_dir = Path.cwd() / "Orders"

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

folder = outlook.Folders.Item("Shared Mailbox Name")
inbox = folder.Folders.Item("Inbox")

messages = inbox.Items

wb = openpyxl.load_workbook(r"C:\Users\TEST\Path-to-excel\FolderName\ExcelName.xlsx")
sheet = wb['Sheet1']
names=sheet['A'] 

for cellObj in names:
    ordno = str(cellObj.value)
    print(ordno)

    for message in messages:
        subject = message.Subject
        body = message.body
        attachments = message.Attachments

        if str(subject)[:9] == ordno:
            output_dir.mkdir(parents=True, exist_ok=True)
            for attachment in attachments:
                attachment.SaveAsFile(output_dir / str(attachment))
        else:
            pass

start = time()
print(f'Time taken to run: {time() - start} seconds')

我需要提一下,我是 Python 的新手,因此欢迎社区提供任何帮助,尤其是在澄清我做错了什么以及为什么做错之后。

我也读过一些类似的问题,但没有任何帮助,或者至少我不知道如何采用这些方法。

谢谢!

您的用例过于具体,任何人都无法重新创建,并且仅提供通用性能提示,但您的主要问题是“O x N”和同步处理的组合:目前您正在处理一个值,一次处理一条消息,其中包括用于获取电子邮件的磁盘 IO。

您当然可以通过从工作簿创建单个值列表来改进事情。 然后,您可以将此列表与处理池一起使用(请参阅 Python 文档)来一次阅读多封电子邮件。

但是如果您可以使用主题来查询邮件服务器,情况可能会更好。

如果您有后续问题,请将它们分解为任务的特定部分。

首先,而不是遍历文件夹中的所有项目:

 for message in messages:
        subject = message.Subject

然后检查一个主题是从指定的字符串开始还是包含这样的字符串:

if str(subject)[:9] == ordno:

相反,您需要使用 Items 类的Find / FindNext或 Restrict methods of the ,您可以在其中获取与您的搜索条件相对应的项目集合。 在以下文章中阅读有关这些方法的更多信息:

例如,您可以对集合使用以下限制(取自 VBA 示例):

criteria = "@SQL=" & Chr(34) & "urn:schemas:httpmail:subject" & Chr(34) & " ci_phrasematch 'question'" 

有关详细信息,请参阅使用字符串比较过滤项目


此外,您可能会发现Application类的AdvancedSearch方法很有帮助。 在 Outlook 中使用AdvancedSearch方法的主要好处是:

  • 搜索在另一个线程中执行。 您不需要手动运行另一个线程,因为AdvancedSearch方法会在后台自动运行它。
  • 可以在任何位置(即超出某个文件夹的范围)搜索任何项目类型:邮件、约会、日历、便笺等。 RestrictFind / FindNext方法可以应用于特定的Items集合(请参阅 Outlook 中Folder类的Items属性)。
  • 完全支持 DASL 查询(自定义属性也可用于搜索)。 为了提高搜索性能,如果为商店启用了即时搜索,则可以使用即时搜索关键字(请参阅Store类的IsInstantSearchEnabled属性)。
  • 您可以使用Search类的Stop方法随时停止搜索过程。

有关详细信息,请参阅Outlook 中的高级搜索以编程方式:C#、VB.NET

在我看来,您的程序的主要问题是当您只需要遍历邮件并检查它们的主题是否在值列表中时,您有两个嵌套循环(一个在值上,一个在邮件上)。

首先,您需要使用以下内容构建价值列表:

ordno_values = [str(cellObj.value) for cellObj in names]

然后,在您的邮件循环中,您只需要将条件调整为:

if str(subject)[:9] in ordno_values:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM