💡 Exemplo completo em funcionamento disponível no GitHub:
sanitize-office-document-pii-python
Os Dados que Ninguém Revê Antes de Enviar
Um relatório trimestral do conselho é enviado a um auditor externo. O texto está impecável; três ciclos de revisão garantiram isso. O próprio arquivo conta outra história. Suas propriedades ainda nomeiam o analista que o redigiu, o gerente que o revisou, a subsidiária da empresa que possui o modelo, um carimbo de data/hora LastPrinted da noite anterior ao prazo e um ID de aprovador do SharePoint proveniente do fluxo interno de aprovação. Nada disso aparece em nenhuma página. Tudo viaja junto com o arquivo.
A remoção de PII é um fluxo de trabalho do GroupDocs.Metadata para Python via .NET que elimina programaticamente essas propriedades que carregam identidade de arquivos Word, Excel e PowerPoint. Este artigo compara as três abordagens que a API oferece: remoção orientada por tags para campos de identidade, remoção por padrão de nome para famílias de propriedades como comentários e revisões, e a chamada única sanitize() que limpa tudo. Você também verá a etapa que a maioria dos scripts de sanitização ignora, uma varredura de verificação que comprova que a limpeza realmente ocorreu.
Por que o PII em Metadados merece seu próprio pipeline
Ferramentas de revisão de conteúdo verificam o que as pessoas leem. Elas não verificam o que os sistemas de arquivos armazenam, e essa lacuna é onde surgem incidentes de conformidade. Uma solicitação de GDPR cobre dados pessoais nos campos Author e Manager tanto quanto os dados no texto. Descobertas legais leem contadores de revisão e totais de tempo de edição para reconstruir quanto tempo um documento de posição foi negociado. Revisores de licitação podem mapear a estrutura da sua organização a partir das propriedades do fluxo de trabalho do SharePoint, e os campos de comentário de um comunicado de imprensa preservam os nomes dos revisores ao lado de observações de rascunho. Cada um desses é uma descoberta. Nenhum deles é visível no corpo do documento.
Pré‑requisitos
Antes de começar, certifique‑se de que você tem:
- Python 3 com pip
- GroupDocs.Metadata para Python via .NET, fixado no repositório de exemplo na versão 26.5
- Um arquivo Office com propriedades reais para praticar
Instalação
pip install groupdocs-metadata-net==26.5
O repositório complementar fornece um DOCX de exemplo e executa cada trecho abaixo como um pipeline verificado.
Método 1: Remoção de Identidade Orientada por Tag
Os quatro campos mais sensíveis — Author, LastSavedBy, Manager e Company — têm nomes internos diferentes entre os formatos Office. O sistema de tags resolve isso: em vez de nomear propriedades, o predicado solicita tudo que está marcado como pessoa ou empresa.
# Match identity properties by meaning, not by format-specific name
with Metadata("board-report.docx") as metadata:
removed = metadata.remove_properties(lambda p:
Tags.person.creator in list(p.tags) # Author, LastSavedBy
or Tags.person.editor in list(p.tags)
or Tags.person.manager in list(p.tags)
or Tags.corporate.company in list(p.tags))
metadata.save("board-report-clean.docx")
print(f"{removed} identity properties removed")
Pontos principais:
- Independência de formato: a mesma lambda limpa DOCX, XLSX e PPTX porque as tags classificam por função.
- Resultado contável:
remove_propertiesdevolve quantas propriedades corresponderam, o que deve constar no seu log de auditoria. - Semântica de cópia: salvar em um novo caminho mantém o original para seus registros.
💡 Dica: esta passagem preserva Title, Subject e outros campos descritivos, de modo que o arquivo continua amigável para busca e indexação em DMS.
Método 2: Remoção por Padrão de Nome para Famílias de Propriedades
As tags cobrem conceitos classificados. Famílias inteiras de campos “vazadores” ficam fora dessa classificação: propriedades de comentário, contadores de revisão, carimbos de fluxo de trabalho do SharePoint. Para esses, combine pelo próprio nome da propriedade.
# Comment fields often live in custom properties the tag system
# does not classify, so match them by name substring
with Metadata("board-report.docx") as metadata:
removed = metadata.remove_properties(lambda p:
p.name is not None and (
"Comment" in p.name
or "Reviewer" in p.name
or "Reviewed" in p.name))
metadata.save("board-report-no-comments.docx")
A mesma estrutura trata as outras duas famílias; apenas a lista de substrings muda:
| Família | Substrings a combinar |
|---|---|
| Rastro de revisão | Revision, TrackedChange, LastPrinted, TotalEditingTime, EditTime |
| Servidor / fluxo de trabalho | Server, Workflow, Approver, ContentType, Template |
Isso troca precisão por alcance: "Comment" também captura Comments e CommentCount, que geralmente é o que uma passagem de sanitização deseja. Substrings amplas podem coincidir com campos de modelo inofensivos também, portanto audite a contagem retornada contra as expectativas.
💡 Dica: execute cada família como sua própria passagem quando seu log de auditoria precisar de contagens por categoria; una os substrings em um único predicado quando isso não for necessário.
Método 3: A Chamada Única sanitize()
Quando o arquivo está deixando a organização e nada na camada de metadados deve sobreviver, pare de escrever predicados.
# One call, every detected metadata package
with Metadata("board-report.docx") as metadata:
removed = metadata.sanitize()
metadata.save("board-report-final.docx")
print(f"sanitize() removed {removed} properties")
sanitize() limpa todos os pacotes que a biblioteca detecta: campos de identidade de informações do documento, comentários, histórico de revisões, autores de alterações rastreadas e partes OOXML personalizadas. O comportamento está documentado na página Clean metadata. Sua força também é seu custo. Title e Subject desaparecem junto com o PII, por isso a chamada deve ser feita no ponto de exportação, e não no meio de um fluxo de colaboração.
Preciso de todas as quatro passagens direcionadas?
Não. Cada passagem existe porque uma equipe diferente detém o risco. Campos de identidade incomodam os oficiais de privacidade, trilhas de comentários incomodam o jurídico, contadores de revisão incomodam negociadores, e campos de servidor incomodam a segurança. Execute as passagens que correspondam aos seus revisores, em qualquer ordem, já que cada uma grava sua própria cópia de saída. Quando ninguém precisa de campos sobreviventes, vá direto para sanitize() e verifique.
Comparando as Três Abordagens
| Abordagem | Melhor para | Principais Vantagens | Limitações |
|---|---|---|---|
| Remoção orientada por tag | Cópias de trabalho, pipelines multi‑formato | Independente de formato, preserva campos descritivos | Cobre apenas conceitos classificados por tag |
| Remoção por padrão de nome | Comentários, revisões, campos de servidor | Alcança propriedades personalizadas que as tags perdem | Substrings precisam ser ajustadas por ambiente |
sanitize() completo |
Exportação final fora da organização | Não deixa nenhuma propriedade esquecida | Apaga campos inofensivos também |
As abordagens se combinam naturalmente: passagens direcionadas enquanto o documento está ativo, sanitize() quando ele for enviado.
Verifique Antes de Confiar
Uma chamada de remoção que devolve uma contagem não é prova de que o arquivo está limpo. O repositório encerra cada execução reabrindo a saída sanitizada e escaneando-a com find_properties, usando um predicado que combina as regras de tag e de nome de todas as passagens acima.
def is_pii(p):
if p.name is None:
return False
return (
Tags.person.creator in list(p.tags)
or Tags.person.editor in list(p.tags)
or Tags.person.manager in list(p.tags)
or Tags.corporate.company in list(p.tags)
or any(n in p.name for n in (
"Comment", "Reviewer", "Revision", "TrackedChange",
"Classification", "Department", "Server", "Workflow")))
with Metadata("board-report-final.docx") as metadata:
for p in metadata.find_properties(is_pii):
value = (str(p.interpreted_value) if p.interpreted_value is not None
else (str(p.value) if p.value is not None else ""))
if value and value not in ("0", "0.0"):
print(f"LEAK {p.name}={value}")
A versão completa no repositório separa os sobreviventes em dois grupos, e a distinção importa. Vazamentos de metadados devem ser zero. Resquícios de conteúdo, balões de comentário do Word e alterações rastreadas dentro de word/document.xml, são conteúdo do corpo que a API de metadados não pode alcançar; removê‑los requer uma biblioteca de edição de conteúdo como Aspose.Words. Um relatório honesto nomeia ambos os grupos em vez de declarar vitória apenas no primeiro. Na primeira vez que executei essa varredura em um arquivo “limpo”, ela sinalizou um campo Department que um modelo corporativo havia re‑adicionado silenciosamente por meses.
Melhores Práticas e Dicas
- Sanitizar cópias, nunca originais: cada trecho aqui grava em um novo caminho, mantendo a fonte para seus registros e políticas de retenção.
- Logar as contagens: os valores retornados por
remove_propertiesesanitize()são seu rastro de auditoria. Armazene‑os por arquivo, por passagem. - Integrar verificação ao CI: um teste de vazamento que falha a build captura regressões de modelo no dia em que acontecem, não no dia em que o cliente percebe.
- Atentar à fronteira metadados/conteúdo: nunca declare um arquivo limpo enquanto comentários no corpo permanecem; apresente‑os como uma constatação separada.
- Licenciamento: o modo de avaliação reproduz tudo neste artigo; use uma licença em produção para que nenhuma marca de avaliação toque os arquivos enviados.
Conclusão
Três abordagens, uma regra de decisão. Use tag quando o conceito estiver classificado e o arquivo precisar permanecer útil. Use nome quando a família viver em propriedades personalizadas. Chame sanitize() quando o arquivo cruzar a fronteira de confiança, e verifique com uma varredura de leitura de volta, independentemente da rota escolhida.
Pronto para aprofundar? Aqui estão os próximos passos:
- Estude a superfície de predicados na página de documentação Remove metadata properties
- Siga o guia passo a passo de caso de uso construído com o mesmo código
- Clone o repositório de exemplo e execute o pipeline verificado contra seus próprios arquivos
Recursos Adicionais
- GroupDocs.Metadata Documentation
- API Reference
- Sample Projects on GitHub
- GroupDocs.Metadata Blog Category
Tem perguntas ou quer compartilhar sua implementação? Entre em contato no support forum.