💡 דוגמה מלאה עובדת זמינה ב‑GitHub:
sanitize-office-document-pii-python
הנתונים שאף אחד לא בודק לפני שליחה
דוח רבעוני של ההנהלה נשלח לרואה חשבון חיצוני. הטקסט ללא פגמים; שלושה מחזורי ביקורת וידאו זאת. הקובץ עצמו הוא סיפור אחר. המאפיינים שלו עדיין כוללים את שם האנליסט שכתב אותו, המנהל ששינה אותו, החברה הבת שבבעלותה תבנית הקובץ, חותמת זמן LastPrinted מהלילה שלפני המועד, ו‑ID של מאשר ב‑SharePoint מתהליך האישור הפנימי. שום דבר מכאן אינו מופיע בעמודים. כל זה נוסע יחד עם הקובץ.
הסרת PII היא זרימת עבודה של GroupDocs.Metadata עבור Python דרך .NET שמסירה את המאפיינים הנושאים זהות מקבצי Word, Excel ו‑PowerPoint באופן תכנותי. מאמר זה משווה בין שלוש הגישות שה‑API מציע: הסרה מונחית תגיות לשדות זהות, הסרה על‑פי תבנית‑שם למשפחות מאפיינים כגון תגובות וגרסאות, והקריאה האחת sanitize() שמוחקת הכול. תראו גם את הצעד שרוב סקריפטי הסניטציה מדלגים עליו, סריקת אימות שמוכיחה שהניקוי אכן נשמר.
למה PII במטא‑דטה ראוי לצינור משלו
כלי ביקורת תוכן בודקים מה אנשים קוראים. הם אינם בודקים מה מערכת הקבצים שומרת, ופער זה הוא מקור תקריות הציות. בקשת GDPR כוללת נתונים אישיים בשדות Author ו‑Manager בדיוק כמו בטקסט. גילוי משפטי קורא מונים של גרסאות וסיכומי זמן עריכה כדי לשחזר כמה זמן נמשך משא ומתן על נייר עמדה. מבקרי מכרזים יכולים למפות את מבנה הארגון שלכם משדות תהליך העבודה ב‑SharePoint, ושדות ההערה של הודעת עיתונות משמרים שמות מבקרים לצד הערות שלב הטיוטה. כל אחד מהאלו הוא מציאה. אף אחד מהם אינו גלוי בגוף המסמך.
דרישות מוקדמות
לפני שמתחילים, ודאו שיש ברשותכם:
- Python 3 עם pip
- GroupDocs.Metadata עבור Python דרך .NET, נעול במאגר הדוגמה לגרסה 26.5
- קובץ Office עם מאפיינים אמיתיים לתרגול
התקנה
pip install groupdocs-metadata-net==26.5
המאגרים המלוים ב‑repo המלווה מספקים קובץ DOCX לדוגמה ומריצים כל קטע קוד למטה כצינור מאומת.
שיטה 1: הסרת זהות מונחית תגיות
ארבעת השדות הרגישים ביותר – 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")
נקודות מפתח:
- עצמאות פורמט: אותה lambda מנקה DOCX, XLSX ו‑PPTX מכיוון שהתגים מסווגים לפי תפקיד.
- תוצאה ניתנת לספירה:
remove_propertiesמחזירה כמה מאפיינים התאימו, מה שמומלץ לתיעוד הביקורת. - העתקה: שמירת הקובץ בנתיב חדש משאירה את המקור עבור הרישומים שלכם.
💡 טיפ: מעבר זה משמר את השדות Title, Subject ושדות תיאוריים אחרים, כך שהקובץ נשאר ידידותי לחיפוש ולאינדקסינג של DMS.
שיטה 2: הסרת תבנית‑שם למשפחות מאפיינים
תגים מכסים מושגים מסווגים. משפחות של שדות דולפים יושבות מחוץ לסיווג זה: מאפייני תגובה, מונים של גרסאות, חותמות תהליך עבודה של 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")
הצורה זהה מתמודדת עם שתי המשפחות הנוספות; רק רשימת תתי‑המחרוזות משתנה:
| משפחה | תתי‑מחרוזות להתאמה |
|---|---|
| עקבות גרסה | Revision, TrackedChange, LastPrinted, TotalEditingTime, EditTime |
| שרת / תהליך עבודה | Server, Workflow, Approver, ContentType, Template |
זהו ויתור על דיוק לטובת היקף: "Comment" תופסת גם Comments וגם CommentCount, מה שרוב הסניטציות רוצות. תתי‑מחרוזות רחבות עלולות לתפוס גם שדות תבנית חפים מפשע, ולכן יש להשוות את הספירה שהוחזרה לציפיות.
💡 טיפ: הריצו כל משפחה כמעבר נפרד כאשר יומן הביקורת שלכם דורש ספירות לפי קטגוריה; מיזגו את תתי‑המחרוזות לתוך תנאי אחד כאשר אין צורך.
שיטה 3: קריאה אחת – 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, ולכן היא מתאימה לשער היצוא ולא לתווך של זרימת עבודה שיתופית.
האם אני צריך את כל ארבעת המעברים הממוקדים?
לא. כל מעבר קיים מכיוון שצוות שונה אחראי על הסיכון. שדות זהות מטרידים קציני פרטיות, עקבות תגובה מטרידות משפטיים, מוני גרסאות מטרידים משא ומתן, ושדות שרת מטרידים אבטחה. הריצו את המעברים המתאימים לבודקים שלכם, בכל סדר, מכיוון שכל אחד כותב עותק פלט משלו. כאשר אין צורך לשמור על שדות, דלגו ישר ל‑sanitize() ובצעו אימות.
השוואת שלוש הגישות
| שיטה | מתאים ל‑ | יתרונות מרכזיים | מגבלות |
|---|---|---|---|
| הסרה מונחית תגיות | עותקים פעילים, צינורות מרובי‑פורמט | עצמאות פורמט, משמר שדות תיאוריים | מכסה רק מושגים מסווגים בתגים |
| הסרה על‑פי תבנית‑שם | תגובות, גרסאות, שדות שרת | מגיע למאפיינים מותאמים שהתגים מפספסים | יש לכוונן תתי‑מחרוזות לכל סביבה |
sanitize() מלאה |
יצוא סופי מחוץ לארגון | לא מפספס אף מאפיין | מוחקת גם שדות חפים מפשע |
הגישות משולבות בטבען: מעברים ממוקדים בזמן שהמסמך חי, sanitize() כשזה נשלח.
אימות לפני שמאמינים
קריאת הסרה שמחזירה ספירה איננה הוכחה שהקובץ נקי. המאגר מסיים כל ריצה בפתיחה מחדש של הפלט המנוקה וסורק אותו עם 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 שתבנית תאגידית הייתה מוסיפה בשקט במשך חודשים.
שיטות עבודה מומלצות וטיפים
- ניקו עותקים, לא מקורות: כל קטע קוד כאן כותב לנתיב חדש, משאיר את המקור לרשומות ולכללי השימור שלכם.
- תעדו את הספירות: ערכי ההחזרה של
remove_propertiesו‑sanitize()הם מסלול הביקורת שלכם. שמרו אותם לכל קובץ, לכל מעבר. - שלבו אימות ב‑CI: בדיקת דליפה שמפסיקה את הבנייה תופסת רגרסיות בתבניות ביום שבו הן מתרחשות, לא ביום שבו הלקוח מבחין.
- שמרו על גבול מטא‑דטה/תוכן: אל תדווחו קובץ נקי בעוד שהערות בגוף נשארות; הציגו אותן כממצא נפרד.
- רישוי: מצב הערכה משחזר את כל מה שמופיע במאמר; השתמשו ברישיון בייצור כדי שמסמנים של הערכה לא יגעו בקבצים היוצאים.
סיכום
שלוש גישות, כלל החלטה אחד. התאימו לפי תג כאשר המושג מסווג והקובץ צריך להישאר שימושי. התאימו לפי שם כאשר המשפחה חיה במאפיינים מותאמים. קראו sanitize() כאשר הקובץ חוצה את גבול האמון, ואמתו עם סריקת קריאה‑חזרה לא משנה באיזו דרך בחרתם.
מוכנים להעמיק? הנה כמה צעדים הבאים:
- חקרו את משטח התנאי ב‑Remove metadata properties
- עקבו אחרי step‑by‑step use case guide המבוסס על אותו קוד
- שיבטו את sample repository והפעילו את הצינור המאומת על הקבצים שלכם
משאבים נוספים
- GroupDocs.Metadata Documentation
- API Reference
- Sample Projects on GitHub
- GroupDocs.Metadata Blog Category
יש לכם שאלות או רוצים לשתף את המימוש שלכם? פנו אלינו ב‑support forum.