Python脚本在Excel中不断出错

dkqlctbz  于 2023-03-20  发布在  Python
关注(0)|答案(1)|浏览(161)

我正在寻找一些帮助和指导与Python脚本,因为我在我的智慧结束试图让它工作。
在某些情况下,每天早上都会有一封电子邮件从一个指定的电子邮件地址发来,里面有一个Excel附件。我的工作要求我打开Excel附件,删除第一行和所有空行,然后用新文件名将附件保存到一个新位置。
上周脚本99%的工作,它做的一切,但会损坏Excel文件的过程中-抛出以下错误:
https://i.stack.imgur.com/kwess.png
https://i.stack.imgur.com/aZIZF.png
更糟糕的是,我花了一个星期左右的时间中断这个脚本,因为我无法理解它--尽管没有任何代码更改,但脚本现在抛出了以下错误:
“* 第112行,在电子邮件_项目=共享_收件箱.项目.限制(文件““,第2行,在限制pywintypes.com中_错误:(-2147352567,'发生异常。',(4096,'Microsoft Outlook','条件无效。',无,0,-2147352567),无)*”

import win32com.client
import datetime
import os
import openpyxl

# 'medocc_path' is a variable containing the path of the MedOCC shared drive folder.
medocc_path = r"S:\File\Path"

# Get the previous day's date in the format yyyymmdd which is required for
# job 'MFT_DW - MedOCC', represented by variable {yesterday}.
yesterday = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y%m%d")

# Define a function to check for Excel attachments to remove the first row and all blank rows.
def process_excel_attachment(file_path):
    # Save the attachment to a temporary folder
    temp_path = os.path.join(os.getcwd(), "temp")
    if not os.path.exists(temp_path):
        os.makedirs(temp_path)
    temp_file = os.path.join(temp_path, os.path.basename(file_path))
    with open(file_path, "rb") as f:
        data = f.read()
    with open(temp_file, "wb") as f:
        f.write(data)

    # Open the workbook and process it
    workbook = openpyxl.load_workbook(temp_file)
    sheet = workbook.active

    # Remove first row and blank rows
    sheet.delete_rows(1)
    counter = 0  # Initialize counter to zero
    for row in sheet.iter_rows():
        if all(cell.value is None for cell in row):
            sheet.delete_rows(row[0].row)
            # Subtract 1 from counter to account for deleted row
            counter -= 1

    # Remove all filters and freezed rows
    sheet.auto_filter.ref = None
    sheet.freeze_panes = None

    # Apply filter and freeze to the first row
    first_row = next(sheet.iter_rows(min_row=1, max_row=1))
    for cell in first_row:
        if cell.value:
            col_letter = cell.column_letter
            values = [
                sheet.cell(row=row, column=cell.column).value
                for row in range(2, sheet.max_row + 1)
                if sheet.cell(row=row, column=cell.column).value
            ]
            sheet.auto_filter.ref = f"{col_letter}1:{col_letter}{sheet.max_row}"
            sheet.auto_filter.add_filter_column(cell.col_idx, values)
            sheet.column_dimensions[cell.column_letter].auto_size = True
            sheet.freeze_panes = "A2"

    # Remove all blank rows
    for row in sheet.iter_rows(min_row=2):
        if all(cell.value is None for cell in row):
            sheet.delete_rows(row[0].row)

    # Remove the temporary file
    os.remove(temp_file)

    # Return the processed workbook
    return workbook

# Connect to Outlook
print("Connecting to Outlook...")
outlook = win32com.client.Dispatch("Outlook.Application.16").GetNamespace("MAPI")

# Open the shared inbox
print("Opening inbox...")
try:
    shared_inbox = outlook.Folders.Item(
        "TEAM"
    ).Folders.Item("Inbox")
    print("Successfully connected to shared inbox")
except:
    print("Error: Failed to connect to shared inbox")

# Search for emails from specific senders in the past 5 days
email_senders = [
    "email1@email.net",
    "email2@email.net",
    "email3@email.net",
]

# Define a time frame of the past 5 days
start_time = (datetime.datetime.now() - datetime.timedelta(days=5)).strftime(
    "%m/%d/%Y %I:%M %p"
)
end_time = datetime.datetime.now().strftime("%m/%d/%Y %I:%M %p")

# Update date format to match Outlook's format
start_time = datetime.datetime.strptime(start_time, "%m/%d/%Y %I:%M %p").strftime("%m/%d/%Y %I:%M %p")
end_time = datetime.datetime.strptime(end_time, "%m/%d/%Y %I:%M %p").strftime("%m/%d/%Y %I:%M %p")

# Check if the medocc_path folder exists
if not os.path.exists(medocc_path):
    print(f"Error: The folder {medocc_path} does not exist.")
    exit()

# Define a flag to check if an email with attachment has been found
email_with_attachment_found = False

for sender in email_senders:
    print(f"Searching for emails from sender '{sender}' in the past 5 days...")

    # Get the email items from the past 5 days
    email_items = shared_inbox.Items.Restrict(
        f"[ReceivedTime] >= '{start_time}' AND [ReceivedTime] <= '{end_time}' AND ([SenderName] = 'Person1' OR [SenderName] = 'Person2' OR [SenderName] = 'Person3') AND (SUBJECT LIKE '%type 3%')"
    )

    # Sort the email items by ReceivedTime in descending order
    email_items.Sort("[ReceivedTime]", True)

    email_item = None  # default value

    # Process only the most recent email
    if len(email_items) > 0:
        email_item = email_items[0]
        print("Processing email with subject:", email_item.Subject)

    # Set the flag to True if an email with attachment has been found
    if email_item.Attachments is not None and email_item.Attachments.Count > 0:
        email_with_attachment_found = True

        # Iterate over the attachments
        for attachment in email_item.Attachments:
            if attachment.FileName.endswith(".xlsx"):
                print(
                    "Found Excel attachment with filename",
                    attachment.FileName,
                    "from sender",
                    sender,
                    "with subject:",
                    email_item.Subject,
                )

                # Save the attachment temporarily...
                temp_path = os.path.join(os.getcwd(), "temp")
                if not os.path.exists(temp_path):
                    os.makedirs(temp_path)

                temp_file = os.path.join(temp_path, attachment.FileName)
                attachment.SaveAsFile(temp_file)

                # Process the attachment
                workbook = process_excel_attachment(temp_file)

                # Remove the temporary file
                if os.path.exists(temp_file):
                    os.remove(temp_file)

                # Save the processed workbook to the MedOCC folder
                new_file_name = os.path.join(medocc_path, f"MedOCC_{yesterday}.xlsx")
                workbook.save(new_file_name)

                # Check if the file has been saved in the path
                if os.path.exists(new_file_name):
                    print("Attachment processed and saved as:", new_file_name)
                else:
                    print(
                        "Error: The file could not be saved in the folder", medocc_path
                    )

    # Print a message if no email with attachment is found from the current sender
    if not email_with_attachment_found:
        print(
            f"No emails found from sender '{sender}' with the specified attachment file name in the past 5 days."
        )
    else:
        email_with_attachment_found = False
else:
    print("No email found.")

如果有人有空闲时间可以回顾一下脚本/澄清我所面临的错误,我将非常感激。
我试着提示ChatGPT提供答案,但似乎没有一个能修复脚本。

mzaanser

mzaanser1#

首先,您需要确保日期-时间比较字符串的格式符合Microsoft Outlook的要求,请使用Format函数(或编程语言中的等效函数)。下面的VBA示例创建一个Jet筛选器,以查找在2022年6月12日当地时间下午3:30之前修改过的所有联系人:

criteria = "[LastModificationTime] < '" _ 
         & Format$("6/12/2022 3:30PM","General Date") & "'"

在搜索条件行中,最后一个检查看起来未知:

# Get the email items from the past 5 days
    email_items = shared_inbox.Items.Restrict(
        f"[ReceivedTime] >= '{start_time}' AND [ReceivedTime] <= '{end_time}' AND ([SenderName] = 'Person1' OR [SenderName] = 'Person2' OR [SenderName] = 'Person3') AND (SUBJECT LIKE '%type 3%')"
    )

如果需要将Subject属性包括在搜索条件中,则需要使用方括号:

# Get the email items from the past 5 days
    email_items = shared_inbox.Items.Restrict(
        f"[ReceivedTime] >= '{start_time}' AND [ReceivedTime] <= '{end_time}' AND ([SenderName] = 'Person1' OR [SenderName] = 'Person2' OR [SenderName] = 'Person3') AND ([Subject] = '%type 3%')"
    )

在Jet查询中,只能对keywords属性执行短语匹配。不能对Jet查询执行开头为或子字符串匹配。要克服使用Jet查询语法的关键字限制的限制,请使用允许开头为或子字符串限制的DASL语法。例如:

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

因此,如果您想在搜索字符串中包含短语匹配搜索,则需要使用如上所示的DASL语法重写它。
第二步,获取Inbox文件夹,如下所示:

shared_inbox = outlook.Folders.Item(
        "TEAM"
    ).Folders.Item("Inbox")

使用Namespace类的GetDefaultFolder方法。该方法返回一个Folder对象,表示当前配置文件所请求类型的默认文件夹;例如,获取当前登录用户的默认日历文件夹。
此外,您可能会发现Store.GetDefaultFolder方法很有用。它返回Folder对象,该对象表示存储中的默认文件夹,并且具有FolderType参数指定的类型。此方法类似于NameSpace对象的GetDefaultFolder方法。不同之处在于,此方法获取与帐户关联的传递存储上的默认文件夹。而NameSpace.GetDefaultFolder返回当前配置文件的默认存储上的默认文件夹。

相关问题