如何在RHEL7-9系统用Python为Excel设置敏感度标签?
纯Python跨平台为Excel添加敏感度标签方案(适用于RHEL7-9,Python3.8+)
核心思路
Excel本质是OXML格式的压缩包,敏感度标签是微软的扩展特性,需要修改多个OXML部件才能被Office识别。我们可以通过直接操作压缩包内的XML文件,模拟Windows下xlwings的修改逻辑,实现跨平台支持。
方案一:基于zipfile+文件操作的原生实现
该方案无需额外依赖,直接通过Python标准库操作Excel压缩包,还原xlwings的修改逻辑:
import zipfile import os import tempfile def add_sensitivity_label(input_xlsx, output_xlsx, label_info_content): # 临时目录处理Excel文件 with tempfile.TemporaryDirectory() as tmpdir: # 解压原Excel文件 with zipfile.ZipFile(input_xlsx, 'r') as zf: zf.extractall(tmpdir) # 创建docMetadata目录并写入LabelInfo.xml doc_meta_dir = os.path.join(tmpdir, 'docMetadata') os.makedirs(doc_meta_dir, exist_ok=True) with open(os.path.join(doc_meta_dir, 'LabelInfo.xml'), 'w', encoding='utf-8') as f: f.write(label_info_content) # 更新[Content_Types].xml,添加LabelInfo的类型定义 content_types_path = os.path.join(tmpdir, '[Content_Types].xml') with open(content_types_path, 'r', encoding='utf-8') as f: content = f.read() insert_pos = content.find('</Types>') if insert_pos != -1: new_content = ( content[:insert_pos] + '\n <Override PartName="/docMetadata/LabelInfo.xml" ContentType="application/vnd.microsoft.office.documentformat.extensibility.part+xml"/>' + content[insert_pos:] ) with open(content_types_path, 'w', encoding='utf-8') as f: f.write(new_content) # 更新_rels/.rels,添加LabelInfo的关系映射 rels_path = os.path.join(tmpdir, '_rels', '.rels') with open(rels_path, 'r', encoding='utf-8') as f: rels_content = f.read() rels_insert_pos = rels_content.find('</Relationships>') if rels_insert_pos != -1: new_rels_content = ( rels_content[:rels_insert_pos] + '\n <Relationship Id="rIdLabelInfo" Type="http://schemas.microsoft.com/office/documentmanagement/2017/06/metadata/labelinfo" Target="docMetadata/LabelInfo.xml"/>' + rels_content[rels_insert_pos:] ) with open(rels_path, 'w', encoding='utf-8') as f: f.write(new_rels_content) # 重新打包为Excel文件 with zipfile.ZipFile(output_xlsx, 'w', zipfile.ZIP_DEFLATED) as zf: for root, _, files in os.walk(tmpdir): for file in files: file_path = os.path.join(root, file) arcname = os.path.relpath(file_path, tmpdir) zf.write(file_path, arcname) # ---------------------- 使用示例 ---------------------- # 替换为你手动添加敏感度标签后,从Excel解压得到的LabelInfo.xml内容 label_info = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <LabelInfo xmlns="http://schemas.microsoft.com/office/documentmanagement/2017/06/metadata/labelinfo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <LabelId>你的标签ID</LabelId> <LabelName>内部机密</LabelName> <LabelDescription>仅限内部员工查看</LabelDescription> <IsEnabled>true</IsEnabled> <SetId>你的标签集ID</SetId> <SiteId>你的站点ID</SiteId> <ActionId>你的操作ID</ActionId> <Method>Privileged</Method> <ContentBits>0</ContentBits> <LabelVersion>1.0</LabelVersion> </LabelInfo>''' add_sensitivity_label('原始文件.xlsx', '带标签文件.xlsx', label_info)
方案二:基于lxml的OXML结构化操作(更严谨)
如果需要更严谨的XML语法校验,可以使用lxml库处理XML节点,避免手动字符串拼接可能出现的格式错误:
from lxml import etree import zipfile import os import tempfile def add_label_via_oxml(input_xlsx, output_xlsx, label_info_content): # 定义OXML命名空间 ns = { 'ct': 'http://schemas.openxmlformats.org/package/2006/content-types', 'rel': 'http://schemas.openxmlformats.org/package/2006/relationships' } with tempfile.TemporaryDirectory() as tmpdir: # 解压Excel文件 with zipfile.ZipFile(input_xlsx, 'r') as zf: zf.extractall(tmpdir) # 写入LabelInfo.xml doc_meta_dir = os.path.join(tmpdir, 'docMetadata') os.makedirs(doc_meta_dir, exist_ok=True) with open(os.path.join(doc_meta_dir, 'LabelInfo.xml'), 'wb') as f: f.write(label_info_content.encode('utf-8')) # 更新[Content_Types].xml ct_path = os.path.join(tmpdir, '[Content_Types].xml') ct_tree = etree.parse(ct_path) ct_root = ct_tree.getroot() # 添加Override节点 override = etree.SubElement( ct_root, '{http://schemas.openxmlformats.org/package/2006/content-types}Override' ) override.set('PartName', '/docMetadata/LabelInfo.xml') override.set('ContentType', 'application/vnd.microsoft.office.documentformat.extensibility.part+xml') ct_tree.write(ct_path, encoding='utf-8', xml_declaration=True) # 更新_rels/.rels rels_path = os.path.join(tmpdir, '_rels', '.rels') rels_tree = etree.parse(rels_path) rels_root = rels_tree.getroot() # 添加Relationship节点 rel = etree.SubElement( rels_root, '{http://schemas.openxmlformats.org/package/2006/relationships}Relationship' ) rel.set('Id', 'rIdLabelInfo') rel.set('Type', 'http://schemas.microsoft.com/office/documentmanagement/2017/06/metadata/labelinfo') rel.set('Target', 'docMetadata/LabelInfo.xml') rels_tree.write(rels_path, encoding='utf-8', xml_declaration=True) # 重新打包 with zipfile.ZipFile(output_xlsx, 'w', zipfile.ZIP_DEFLATED) as zf: for root, _, files in os.walk(tmpdir): for file in files: file_path = os.path.join(root, file) arcname = os.path.relpath(file_path, tmpdir) zf.write(file_path, arcname)
关键注意事项
- LabelInfo.xml内容必须准确:直接从手动添加标签的Excel解压包中提取该文件,替换其中的标签名称、ID等字段,避免格式错误导致Office无法识别。
- XML语法校验:修改
[Content_Types].xml和_rels/.rels时,确保XML结构合法,否则会导致Excel文件损坏。 - 测试前备份原文件:操作前务必备份原始Excel,避免数据丢失。
内容的提问来源于stack exchange,提问作者Jim Palmer
相关产品推荐
相关产品推荐

