💡 مثال کامل قابل اجرا در GitHub موجود است:
sanitize-office-document-pii-python

The Data Nobody Reviews Before Hitting Send

یک گزارش فصلی هیئت مدیره برای حسابرس خارجی ارسال می‌شود. متن آن بی‌نقص است؛ سه دوره بازبینی این را تضمین کرده‌اند. اما خود فایل داستان دیگری دارد. ویژگی‌های آن هنوز نام تحلیل‌گری که آن را تهیه کرده، مدیرِی که بازنویسی کرده، زیرمجموعه شرکت که قالب را مالک است، زمان‌مهر LastPrinted از شب قبل از مهلت و شناسه تأییدکننده SharePoint از جریان کاری داخلی را شامل می‌شود. هیچ‌یک از این موارد در صفحه‌ای ظاهر نمی‌شود. همهٔ آن‌ها همراه فایل می‌روند.

حذف PII یک جریان کاری GroupDocs.Metadata برای Python از طریق .NET است که این ویژگی‌های حاوی هویت را به‌صورت برنامه‌نویسی از فایل‌های Word، Excel و PowerPoint حذف می‌کند. این مقاله سه رویکردی را که API ارائه می‌دهد مقایسه می‌کند: حذف مبتنی بر برچسب برای فیلدهای هویتی، حذف مبتنی بر الگوی نام برای خانواده‌های ویژگی مانند نظرات و بازنگری‌ها، و فراخوانی تک‌مرحله‌ای sanitize() که همه چیز را پاک می‌کند. همچنین مرحله‌ای که اکثر اسکریپت‌های پاک‌سازی از آن عبور می‌کنند، یعنی اسکن تأییدیه‌ای که ثابت می‌کند پاک‌سازی واقعاً انجام شده است، را می‌بینید.

Why Metadata PII Deserves Its Own Pipeline

ابزارهای بازبینی محتوا آنچه افراد می‌خوانند را بررسی می‌کنند. آنچه سیستم‌های فایل ذخیره می‌کنند را بررسی نمی‌کنند و همین فاصله منبع حوادث انطباق است. یک درخواست GDPR داده‌های شخصی موجود در فیلدهای Author و Manager را به همان اندازه‌ای که در متن هستند، پوشش می‌دهد. کشف قانونی شمارنده‌های بازنگری و مجموع زمان‌های ویرایش را می‌خواند تا مدت زمان مذاکره یک موقعیت‌نامه را بازسازی کند. بازبینان مناقصه می‌توانند ساختار سازمانی شما را از ویژگی‌های جریان کاری SharePoint استخراج کنند و فیلدهای نظرات یک اطلاعیه مطبوعاتی نام بازبین‌ها را همراه با نظرات مرحله پیش‌نویس حفظ می‌کند. هر یک از این‌ها یک یافته است. هیچ‌یک از آن‌ها در بدنهٔ سند قابل مشاهده نیست.

Prerequisites

قبل از شروع، مطمئن شوید که موارد زیر را دارید:

  • Python 3 به همراه pip
  • GroupDocs.Metadata برای Python از طریق .NET، که در مخزن نمونه به نسخه 26.5 قفل شده است
  • یک فایل Office با ویژگی‌های واقعی برای تمرین

Installation

pip install groupdocs-metadata-net==26.5

مخزن همراه یک فایل DOCX نمونه می‌سازد و هر قطعه کد زیر را به‌عنوان یک خط لوله تأیید شده اجرا می‌کند.

Method 1: Tag-Driven Identity Removal

چهار فیلد حساس‌ترین، Author, LastSavedBy, Manager و Company، نام‌های داخلی متفاوتی در قالب‌های Office دارند. سیستم برچسب این مشکل را حل می‌کند: به‌جای نام‌گذاری ویژگی‌ها، پیش‌شرط همهٔ مواردی را که به‌عنوان شخص یا شرکت برچسب‌گذاری شده‌اند، می‌گیرد.

# 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")

نکات کلیدی:

  • استقلال از قالب: همان لامبدا برای DOCX، XLSX و PPTX کار می‌کند زیرا برچسب‌ها بر اساس نقش طبقه‌بندی می‌شوند.
  • نتیجه‌گیری قابل شمارش: remove_properties تعداد ویژگی‌های منطبق را برمی‌گرداند که باید در لاگ حسابرسی شما ثبت شود.
  • معنای کپی: ذخیره در مسیر جدید، اصل را برای سوابق شما حفظ می‌کند.

💡 نکته: این عبور، فیلدهای Title, Subject و سایر فیلدهای توصیفی را حفظ می‌کند، بنابراین فایل برای جستجو و ایندکس‌گذاری DMS دوستانه می‌ماند.

Method 2: Name-Pattern Removal for Property Families

برچسب‌ها مفاهیم طبقه‌بندی‌شده را پوشش می‌دهند. خانواده‌های کامل فیلدهای نشت‌کننده خارج از این طبقه‌بندی قرار دارند: ویژگی‌های نظرات، شمارنده‌های بازنگری، مهرهای کاری SharePoint. برای این‌ها، بر روی نام ویژگی خود مطابقت می‌دهیم.

# 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")

همین شکل برای دو خانوادهٔ دیگر نیز کار می‌کند؛ تنها لیست زیررشته‌ها تغییر می‌کند:

Family Substrings to match
Revision trail Revision, TrackedChange, LastPrinted, TotalEditingTime, EditTime
Server / workflow Server, Workflow, Approver, ContentType, Template

این روش دقت را برای پوشش گسترده‌تر تعویض می‌کند: "Comment" همچنین Comments و CommentCount را می‌گیرد که معمولاً همان چیزی است که یک عبور پاک‌سازی می‌خواهد. زیررشته‌های گسترده می‌توانند فیلدهای قالب بی‌ضرر را نیز بگیرند، بنابراین تعداد بازگشتی را نسبت به انتظارات خود بررسی کنید.

💡 نکته: هر خانواده را به‌عنوان یک عبور جداگانه اجرا کنید وقتی لاگ حسابرسی شما به شمارش‌های دسته‌ای نیاز دارد؛ وقتی این‌طور نیست، زیررشته‌ها را در یک پیش‌شرط ترکیب کنید.

Method 3: The One-Call Full Sanitize

وقتی فایل در حال خروج از سازمان است و هیچ‌یک از لایهٔ متادیتا باید باقی بماند، نوشتن پیش‌شرط‌ها را متوقف کنید.

# 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() تمام بسته‌های متادیتایی که کتابخانه شناسایی می‌کند را پاک می‌کند: فیلدهای هویتی اطلاعات سند، نظرات، تاریخچه بازنگری، نویسندگان تغییرات ردیابی‌شده و بخش‌های سفارشی OOXML. رفتار آن در صفحهٔ Clean metadata مستند شده است. قوت آن همان هزینه‌اش است. Title و Subject همراه با PII ناپدید می‌شوند، به همین دلیل این متد بهتر است در نقطهٔ خروج نهایی به‌کار رود نه در میانهٔ یک جریان کاری همکاری.

Do I need all four targeted passes?

خیر. هر عبور به دلیل اینکه تیم متفاوتی خطر را در اختیار دارد وجود دارد. فیلدهای هویتی حریم خصوصی را به‌چالش می‌کشند، ردپای نظرات مسائل قانونی، شمارنده‌های بازنگری مذاکرات‌کنندگان و فیلدهای سرور امنیت را به‌چالش می‌کشند. عبورهایی را اجرا کنید که با بازبینان شما مطابقت دارند، به هر ترتیبی، چون هر کدام نسخهٔ خروجی خود را می‌نویسند. وقتی هیچ فیلد زنده‌ای لازم نیست، مستقیماً به sanitize() بروید و تأیید کنید.

Comparing the Three Approaches

Method Best For Key Advantages Limitations
Tag-driven removal Working copies, multi-format pipelines Format-independent, preserves descriptive fields Only covers tag-classified concepts
Name-pattern removal Comments, revisions, server fields Reaches custom properties tags miss Substrings need tuning per environment
Full sanitize() Final export outside the organization Cannot miss a forgotten property Wipes harmless fields too

این رویکردها به‌صورت طبیعی ترکیب می‌شوند: عبورهای هدفمند در حالی که سند زنده است، sanitize() هنگام ارسال.

Verify Before You Trust It

یک فراخوانی حذف که عددی برمی‌گرداند، شواهدی نیست که فایل پاک باشد. مخزن هر اجرا را با باز کردن خروجی پاک‌شده و اسکن آن با find_properties که پیش‌شرطی ترکیبی از قوانین برچسب و نام تمام عبورهای بالا را اعمال می‌کند، پایان می‌دهد.

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}")

نسخهٔ کامل در مخزن بقاهای پیدا شده را به دو سبد تقسیم می‌کند و این تمایز مهم است. نشت‌های متادیتا باید صفر باشند. باقی‌مانده‌های سطح محتوا، حباب‌های نظرات Word و تغییرات ردیابی‌شده داخل word/document.xml، محتوای بدنه هستند که API متادیتا نمی‌تواند به آن‌ها دسترسی داشته باشد؛ حذف آن‌ها نیاز به کتابخانهٔ ویرایش محتوا مانند Aspose.Words دارد. یک گزارش صادقانه هر دو سبد را نام می‌برد به‌جای اینکه پیروزی را فقط در اولین سبد اعلام کند. اولین باری که این اسکن را روی یک فایل «تمیز» اجرا کردم، فیلد Department را که یک قالب شرکتی به‌صورت ساکتانه ماه‌ها اضافه می‌کرد، شناسایی کرد.

Best Practices and Tips

  • کپی‌های پاک‌شده، نه اصل‌ها: هر قطعه کد اینجا به مسیر جدید می‌نویسد، منبع را برای سوابق و قوانین نگهداری شما حفظ می‌کند.
  • ثبت شمارش‌ها: مقادیر بازگشتی remove_properties و sanitize() ردپای حسابرسی شما هستند. آن‌ها را برای هر فایل و هر عبور ذخیره کنید.
  • ادغام تأییدیه در CI: یک بررسی نشت که ساخت را متوقف می‌کند، رگرسیون‌های قالب را همان روزی که رخ می‌دهند می‌گیرد، نه روزی که مشتری متوجه می‌شود.
  • مرز متادیتا/محتوا: هرگز فایلی را «تمیز» گزارش ندهید در حالی که نظرات سطح بدنه باقی مانده‌اند؛ آن‌ها را به‌عنوان یک یافتهٔ جداگانه نشان دهید.
  • مجوز: حالت ارزیابی همه چیز را در این مقاله بازتولید می‌کند؛ در محیط تولید از یک لایسنس استفاده کنید تا هیچ علامت ارزیابی‌ای به فایل‌های خروجی نچسبد.

Conclusion

سه رویکرد، یک قانون تصمیم‌گیری. وقتی مفهوم طبقه‌بندی شده است و فایل باید مفید بماند، با برچسب مطابقت دهید. وقتی خانواده در ویژگی‌های سفارشی زندگی می‌کند، با نام مطابقت دهید. وقتی فایل از مرز اعتماد عبور می‌کند، sanitize() را فراخوانی کنید و با اسکن بازخوانی مسیر انتخابی خود را تأیید کنید.

آماده‌اید عمیق‌تر بروید؟ گام‌های بعدی عبارتند از:

Additional Resources

سوال دارید یا می‌خواهید پیاده‌سازی خود را به اشتراک بگذارید؟ در forum پشتیبانی مراجعه کنید.