
本教程详细介绍了如何利用Python自动化从Outlook邮件中提取特定信息。通过集成`win32com.client`库与Outlook交互,并结合强大的正则表达式,我们能够根据预设的父级和子级关键词,从邮件主题和正文中精准匹配并提取关联的段落文本及URL。文章纠正了常见的正则表达式提取错误,提供了一个优化方案,确保数据抓取准确、高效,并支持将结果保存至本地文件。
在日常工作中,我们经常需要从大量的邮件中筛选并提取特定信息,例如包含特定关键词的段落和相关的网页链接。手动操作不仅效率低下,且容易出错。本教程旨在提供一个Python解决方案,利用win32com.client库与Microsoft Outlook进行交互,并通过精细设计的正则表达式,实现对邮件内容的自动化、精准提取。我们将重点关注如何正确构建正则表达式,以解决在复杂文本(如包含多行日文和URL)中匹配特定模式的挑战。
在开始之前,请确保您的Python环境中已安装必要的库,并准备好一个配置文件。
pip install pywin32
{
  "folder_name": "调达プロジェクト",
  "output_file_path": "E:\output",
  "parent_keyword": "meeting",
  "child_keywords": ["土木一式工事", "産業用機器", "事務用品・機器"]
}Python通过win32com.client模块与Outlook应用程序建立连接。首先获取Outlook应用程序实例,然后访问其MAPI命名空间,进而定位到默认的收件箱(或指定文件夹)。
立即学习“Python免费学习笔记(深入)”;
import win32com.client
import os
import json
import logging
import re
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def read_config(config_file):
    """读取JSON配置文件。"""
    with open(config_file, 'r', encoding="utf-8") as f:
        config = json.load(f)
    return config
def get_outlook_folder(folder_name):
    """连接Outlook并获取指定名称的文件夹对象。"""
    try:
        outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
        inbox = outlook.GetDefaultFolder(6) # 6代表收件箱
        # 遍历收件箱下的所有子文件夹,查找目标文件夹
        for folder in inbox.Folders:
            if folder.Name == folder_name:
                logging.info(f"成功找到文件夹: '{folder_name}'")
                return folder
        logging.warning(f"文件夹 '{folder_name}' 未找到。请检查名称或其位置。")
        return None
    except Exception as e:
        logging.error(f"连接Outlook或获取文件夹时发生错误: {e}")
        return None在获取到目标Outlook文件夹后,我们会遍历其中的每封邮件。首先,根据配置文件中的parent_keyword对邮件主题进行初步筛选。
# ... (接上文代码)
def search_and_save_email(config):
    """根据配置搜索邮件并提取信息。"""
    folder_name = config.get("folder_name", "")
    output_file_path = config.get("output_file_path", "")
    parent_keyword = config.get("parent_keyword", "")
    child_keywords = config.get("child_keywords", [])
    os.makedirs(output_file_path, exist_ok=True) # 确保输出目录存在
    user_folder = get_outlook_folder(folder_name)
    if not user_folder:
        return
    # 编译父级关键词的正则表达式,用于主题匹配
    # 使用re.escape处理关键词中的特殊字符,确保精确匹配
    parent_keyword_pattern = re.compile(r'(?:' + '|'.join(map(re.escape, parent_keyword.split())) + r')', re.IGNORECASE)
    for item in user_folder.Items:
        # 检查邮件主题是否包含父级关键词
        if parent_keyword_pattern.findall(item.Subject):
            logging.info(f"在邮件主题中找到父级关键词: {item.Subject}")
            # ... (后续正文提取逻辑)
        # else:
        #     logging.debug(f"邮件主题 '{item.Subject}' 不包含父级关键词。")这是本教程的核心部分,也是原问题中出现逻辑错误的地方。原始代码尝试先根据子关键词找到段落,再从该段落中提取URL。但由于paragraph_text的定义过于狭窄(仅限于关键词所在行),导致URL无法被正确捕获。
原始代码中提取段落的逻辑如下:
# ...
paragraph_start = body_lower.rfind('
', 0, match.start())
paragraph_end = body_lower.find('
', match.end())
paragraph_text = item.Body[paragraph_start + 1:paragraph_end]
# ...
url_pattern = re.compile(r'http[s]?://S+')
urls = url_pattern.findall(paragraph_text)这种方法的问题在于,如果子关键词和其关联的URL不在同一行,或者URL在关键词之后的几行,那么paragraph_text就无法包含URL。在提供的邮件示例中,关键词和URL通常是分行显示的,因此需要一个能跨越多行进行匹配的正则表达式。
为了解决上述问题,我们需要一个能够同时捕获子关键词、其周围文本以及后续URL的正则表达式。关键在于允许正则表达式跨越多行进行匹配。
我们将使用以下正则表达式模式: rf'([^ ]*({"|".join(map(re.escape, child_keywords))})[^ ]*).*?(https?://S+)'
让我们分解这个模式:
re.S (re.DOTALL) 标志的重要性: 当使用re.S标志时,正则表达式中的.(点号)将匹配包括换行符在内的所有字符。这对于跨越多行提取信息至关重要,因为它允许.*?模式捕获关键词和URL之间的所有内容,无论中间有多少换行符。
结合这个优化后的正则表达式和re.findall函数,我们可以一次性从邮件正文中提取所有匹配的子关键词、关联文本和URL。
# ... (接上文代码)
            # 初始化用于存储结果的字符串
            output_text = ""
            # 编译子关键词和URL的复合正则表达式
            # re.escape 处理关键词中的特殊字符
            # re.S (re.DOTALL) 使 '.' 匹配包括换行符在内的所有字符
            child_keyword_url_pattern = re.compile(
                rf'([^
]*({"|".join(map(re.escape, child_keywords))})[^
]*).*?(https?://S+)',
                re.IGNORECASE | re.S
            )
            # 在邮件正文中查找所有匹配项
            # re.findall 返回一个列表,每个元素是一个元组,包含所有捕获组的内容
            matches = child_keyword_url_pattern.findall(item.Body)
            if not matches:
                logging.warning(f"在邮件正文 '{item.Subject}' 中未找到任何子关键词及其关联的URL。")
                continue # 跳过当前邮件,处理下一封
            for match_group in matches:
                # match_group 的结构为 (完整的段落文本, 子关键词, URL)
                # 例如: ('01 事務用品・機器', '事務用品・機器', 'https://...')
                # 提取捕获组内容
                paragraph_text_full = match_group[0].strip() # 包含关键词的整行文本
                found_child_keyword = match_group[1].strip() # 匹配到的子关键词
                found_url = match_group[2].strip() # 匹配到的URL
                logging.info(f"提取到: 关键词='{found_child_keyword}', 文本='{paragraph_text_full}', URL='{found_url}'")
                # 格式化结果
                output_text += f"Child Keyword: {found_child_keyword}
"
                output_text += f"Paragraph Text: {paragraph_text_full}
"
                output_text += f"URLs: {found_url}
"
            # 保存结果到文件
            # 使用邮件主题作为文件名,并替换掉不适合作为文件名的字符
            sanitized_subject = re.sub(r'[\/:*?"<>|]', '_', item.Subject)
            output_file = os.path.join(output_file_path, f"{sanitized_subject}.txt")
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(output_text)
            logging.info(f"结果已保存至: {output_file}")
        # else:
        #     logging.debug(f"邮件主题 '{item.Subject}' 不包含父级关键词。")将上述所有代码片段整合,并包含主执行逻辑,构成一个完整的Python脚本。
import win32com.client
import os
import json
import logging
import re
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def read_config(config_file):
    """
    读取JSON配置文件。
    Args:
        config_file (str): 配置文件的路径。
    Returns:
        dict: 包含配置信息的字典。
    """
    with open(config_file, 'r', encoding="utf-8") as f:
        config = json.load(f)
    return config
def get_outlook_folder(folder_name):
    """
    连接Outlook并获取指定名称的文件夹对象。
    Args:
        folder_name (str): Outlook中待搜索的文件夹名称。
    Returns:
        object: Outlook文件夹对象,如果未找到则返回None。
    """
    try:
        outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
        inbox = outlook.GetDefaultFolder(6) # 6代表收件箱
        # 遍历收件箱下的所有子文件夹,查找目标文件夹
        for folder in inbox.Folders:
            if folder.Name == folder_name:
                logging.info(f"成功找到Outlook文件夹: '{folder_name}'")
                return folder
        logging.warning(f"Outlook文件夹 '{folder_name}' 未找到。请检查名称或其位置。")
        return None
    except Exception as e:
        logging.error(f"连接Outlook或获取文件夹时发生错误: {e}")
        return None
def search_and_save_email(config):
    """
    根据配置文件搜索Outlook邮件,提取关键词、关联文本和URL,并保存结果。
    Args:
        config (dict): 包含配置信息的字典。
    """
    try:
        folder_name = config.get("folder_name", "")
        output_file_path = config.get("output_file_path", "")
        parent_keyword = config.get("parent_keyword", "")
        child_keywords = config.get("child_keywords", [])
        # 确保输出目录存在
        os.makedirs(output_file_path, exist_ok=True)
        user_folder = get_outlook_folder(folder_name)
        if not user_folder:
            return
        # 编译父级关键词的正则表达式,用于主题匹配
        # 使用re.escape处理关键词中的特殊字符,确保精确匹配
        parent_keyword_pattern = re.compile(r'(?:' + '|'.join(map(re.escape, parent_keyword.split())) + r')', re.IGNORECASE)
        # 编译子关键词和URL的复合正则表达式
        # re.escape 处理关键词中的特殊字符
        # re.S (re.DOTALL) 使 '.' 匹配包括换行符在内的所有字符
        child_keyword_url_pattern = re.compile(
            rf'([^
]*({"|".join(map(re.escape, child_keywords))})[^
]*).*?(https?://S+)',
            re.IGNORECASE | re.S
        )
        for item in user_folder.Items:
            # 检查邮件主题是否包含父级关键词
            if parent_keyword_pattern.findall(item.Subject):
                logging.info(f"在邮件主题中找到父级关键词: {item.Subject}")
                output_text = "" # 初始化用于存储结果的字符串
                # 在邮件正文中查找所有匹配项
                # re.findall 返回一个列表,每个元素是一个元组,包含所有捕获组的内容
                matches = child_keyword_url_pattern.findall(item.Body)
                if not matches:
                    logging.warning(f"在邮件正文 '{item.Subject}' 中未找到任何子关键词及其关联的URL。")
                    continue # 跳过当前邮件,处理下一封
                for match_group in matches:
                    # match_group 的结构为 (完整的段落文本, 子关键词, URL)
                    paragraph_text_full = match_group[0].strip() # 包含关键词的整行文本
                    found_child_keyword = match_group[1].strip() # 匹配到的子关键词
                    found_url = match_group[2].strip() # 匹配到的URL
                    logging.info(f"提取到: 关键词='{found_child_keyword}', 文本='{paragraph_text_full}', URL='{found_url}'")
                    # 格式化结果
                    output_text += f"Child Keyword: {found_child_keyword}
"
                    output_text += f"Paragraph Text: {paragraph_text_full}
"
                    output_text += f"URLs: {found_url}
"
                # 保存结果到文件
                # 使用邮件主题作为文件名,并替换掉不适合作为文件名的字符
                sanitized_subject = re.sub(r'[\/:*?"<>|]', '_', item.Subject)
                output_file = os.path.join(output_file_path, f"{sanitized_subject}.txt")
                with open(output_file, 'w', encoding='utf-8') as f:
                    f.write(output_text)
                logging.info(f"结果已保存至: {output_file}")
            # else:
            #     logging.debug(f"邮件主题 '{item.Subject}' 不包含父级关键词。")
    except Exception as e:
        logging.error(f"在 search_and_save_email 函数中发生错误: {e}")
if __name__ == "__main__":
    # 指定配置文件的路径
    config_file_path = "E:\config.json" # 请根据实际路径修改
    # 检查配置文件是否存在
    if not os.path.exists(config_file_path):
        logging.error(f"配置文件 '{config_file_path}' 不存在。请创建或修改路径。")
    else:
        # 读取配置
        config = read_config(config_file_path)
        # 执行搜索和保存操作
        search_and_save_email(config)通过本教程,我们学习了如何利用Python的win32com.client库与Outlook进行深度集成,并运用强大的正则表达式从邮件正文中精确提取关键词、关联文本和URL。关键在于构建一个能够跨越多行捕获所需信息的复合正则表达式,并配合re.S标志。这个解决方案不仅提高了数据提取的效率和准确性,也
以上就是使用Python和正则表达式从Outlook邮件中高效提取关键词、文本及URL的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号