לפני השקת קמפיין אפשר לעבד רשימה של חשבונות IG באמצעות סקריפט ולקבל דוח JSON עם תשובת ה-API לכל שם משתמש. הנתיב IG Scraper API של jsonscraper מחזיר סטטוס חיצוני ואובייקט פרופיל; בסכמה שנצפתה מופיעים שם המשתמש, סימוני פרטיות ואימות, מספר הפוסטים, העוקבים והחשבונות במעקב. שדות אלה מסייעים למיין רשומות לבדיקה ידנית, אך אינם מסבירים כשלעצמם מדוע התקבלה תשובה חסרה או בלתי צפויה.

הבעיה: רשימת החשבונות נראית תקינה, אבל האם היא מוכנה לעבודה?
בטבלת העבודה של קמפיין עשויים להופיע חשבונות ששינו את שמם, שגיאות הקלדה ופרופילים פרטיים. אם הצוות מתחיל לנתח את הרשימה בלי בדיקה מקדימה, מישהו נדרש לפתוח את החשבונות בזה אחר זה. מעבר אוטומטי מצמצם את העבודה הידנית ומשאיר יומן אחיד של מה שה-API החזיר לכל שם שהתבקש.
מטרת התהליך הזה מוגבלת: לעבור על הרשימה, לשמור את תגובות ה-HTTP ואת JSON כפי שהתקבלו, ולהעביר לבדיקה ידנית פרופילים שיש בהם סימנים הרלוונטיים לקמפיין. הדוח מתעד את הנתונים שנצפו; הוא אינו קובע מדוע פרופיל לא הוחזר או מדוע הבקשה נכשלה.
מה הבקשה בודקת
בתיעוד של jsonscraper מצוין הנתיב GET \/v1\/user\/by\/username. הפרמטר הנדרש הוא username; המפתח מועבר בפרמטר license_key. הפרמטר האופציונלי cache_timeout מפעיל שמירה במטמון למשך מספר השניות שהוגדר, והערך 0 משאיר אותה כבויה. בסכמה שנצפתה, תשובה מוצלחת כוללת status חיצוני ואובייקט ig עם שדות הפרופיל.
לצורכי אבחון, הפרידו בין שלוש עובדות: האם בקשת HTTP הצליחה; האם JSON שפוענח מכיל אובייקט ig; ואילו שדות מופיעים באובייקט. אם שלב כלשהו לא הסתיים כצפוי, הסקריפט יכול לתעד את התוצאה הטכנית ואת התשובה המקורית. תוצאה כזו מצביעה על צורך בבדיקה, אך אינה קובעת את סיבת התקלה.
הכנת נתוני הקלט והמפתח
צרו קובץ usernames.txt, ובו שם משתמש אחד בכל שורה, ללא התו @. הסירו שורות ריקות וכפילויות והשאירו רק חשבונות הקשורים לקמפיין. לצורך השוואה עתידית של התוצאות, שמרו בנפרד את תאריך הבדיקה ואת מזהה הפרויקט.
שמרו את המפתח במשתנה סביבה בשם JSONSCRAPER_INSTAGRAM_LICENSE_KEY, ולא בקוד המקור או במאגר:
export JSONSCRAPER_INSTAGRAM_LICENSE_KEY="המפתח_שלכם"
python3 check_profiles.py
הדוגמה משתמשת בספרייה הסטנדרטית של Python 3.8 ומעלה, ואינה דורשת התקנה של חבילות HTTP.
דוגמה: שליפת פרופילים וכתיבת דוח
הסקריפט עובר על הרשימה, שם אחד בכל פעם. במקרה של תשובת JSON מוצלחת, הוא שומר את גוף התשובה כפי שהתקבל ואת שדות הפרופיל הזמינים; במקרה של שגיאת HTTP או רשת, הוא מתעד אותה כתוצאה טכנית. שדות חסרים נשארים null, וגוף התשובה הגולמי נשמר אם ניתן היה לקרוא אותו.
import json
import os
import time
from datetime import datetime, timezone
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
API_KEY = os.environ.get("JSONSCRAPER_INSTAGRAM_LICENSE_KEY")
if not API_KEY:
raise SystemExit("הגדירו את JSONSCRAPER_INSTAGRAM_LICENSE_KEY")
BASE_URL = "https:\/\/ig.jsonscraper.com\/v1\/user\/by\/username"
with open("usernames.txt", encoding="utf-8") as f:
usernames = list(dict.fromkeys(
line.strip().lstrip("@") for line in f if line.strip()
))
results = []
for username in usernames:
params = urlencode({"username": username, "license_key": API_KEY})
request = Request(f"{BASE_URL}?{params}", method="GET")
checked_at = datetime.now(timezone.utc).isoformat()
try:
with urlopen(request, timeout=30) as response:
http_status = response.status
raw_body = response.read().decode("utf-8")
try:
payload = json.loads(raw_body)
json_error = None
except json.JSONDecodeError as exc:
payload = None
json_error = str(exc)
profile = payload.get("ig") if isinstance(payload, dict) else None
record = {
"requested_username": username,
"checked_at": checked_at,
"http_status": http_status,
"api_status": payload.get("status") if isinstance(payload, dict) else None,
"check_result": "profile_returned" if isinstance(profile, dict) else "unexpected_or_missing_profile_object",
"response": payload if payload is not None else raw_body,
}
if json_error:
record["json_error"] = json_error
if isinstance(profile, dict):
record["returned_username"] = profile.get("username")
record["is_private"] = profile.get("is_private")
record["is_verified"] = profile.get("is_verified")
record["media_count"] = profile.get("media_count")
record["follower_count"] = profile.get("follower_count")
record["following_count"] = profile.get("following_count")
results.append(record)
except HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
results.append({
"requested_username": username,
"checked_at": checked_at,
"check_result": "http_error",
"http_status": exc.code,
"response": body,
})
except (URLError, TimeoutError) as exc:
results.append({
"requested_username": username,
"checked_at": checked_at,
"check_result": "request_error",
"detail": str(exc),
})
time.sleep(0.5)
with open("profile-check.json", "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"מספר התוצאות שנשמרו: {len(results)}")
זוהי דוגמת שילוב, ולא דיווח על בדיקה שבוצעה. המפתח מועבר בפרמטר license_key, אך אינו מודפס. התשובה המלאה עשויה להכיל מידע שיש להגביל את הגישה אליו בהתאם לכללי שמירת הנתונים של הצוות שלכם.
איך לקרוא את התוצאה
רשומה עם profile_returned פירושה שהסקריפט קיבל אובייקט JSON בשם ig. השוו בין requested_username ל-returned_username ובדקו את הסימנים החשובים לתהליך הקמפיין. לדוגמה, אפשר להעביר is_private: true לבדיקה ידנית אם הקמפיין דורש פרופיל ציבורי.

התוצאות http_error, request_error ו-unexpected_or_missing_profile_object מציינות רק את השלב שבו הסקריפט לא קיבל את המבנה הצפוי. הן אינן מוכיחות שהחשבון נמחק, הפך לפרטי או אינו זמין מסיבה מסוימת. שמרו את התשובה, בדקו את שם המשתמש ואת המפתח, ואז שלחו את הבקשה שוב או פנו לתמיכה הרשמית של השירות.
אם שדה חסר, השאירו אותו כלא ידוע — אל תפרשו את החסר כאפס או כ-false. מוני הפרופיל מתארים את המצב שהוחזר בזמן הבקשה. חותמת הזמן מאפשרת להבחין בין תמונת מצב זו לבין תוצאות של הרצה נוספת.
אוטומציה בלי לאבד את יכולת המעקב
העבירו את ההרצה למתזמן משימות או לשלב בתהליך ETL קיים. שמרו את תאריך הבדיקה, את שם המשתמש שהתבקש, את התוצאה, את הסטטוס ואת גוף התשובה. בשלב נפרד אפשר לטעון את JSON לטבלה ולשלוח למומחה רק את הרשומות שדורשות בדיקה.
כדי לזהות שינויים, השוו תמונות מצב של אותו פרופיל לפי שדות שנבחרו. שינוי במספר הפוסטים הוא סיבה לפתוח את הפרופיל ולבדוק אותו, לא תאריך מדויק שבו פורסם פוסט. גם מונה העוקבים הוא ערך שנמדד בזמן הבקשה, ולכן היסטוריית התצפיות נבנית מתמונות מצב שנשמרו.
כשיש רשימה גדולה, קבעו קצב מבוקר, הוסיפו ניסיונות חוזרים במספר מוגבל ותעדו שגיאות. אל תכללו את המפתח ביומני כתובות URL. אחסון נפרד של רשימת הקלט ושל התוצאות מקל לזהות אילו חשבונות כבר עובדו.
התוצאה הצפויה
הפלט הוא קובץ JSON עם תוצאת העיבוד של כל שם משתמש שסופק, חותמת זמן, מאפיינים זמינים ותשובה שנשמרה. לפני העברת הרשימה לקמפיין, אפשר לסנן שמות תואמים, פרופילים פרטיים ומקרים טכניים לבדיקה ידנית. הצוות עצמו מגדיר את הקריטריונים לשלב הבא.
הנתיב והפרמטרים מתוארים בתיעוד IG API; מידע על המוצר מופיע בעמוד IG Scraper API. התחילו במדגם קטן, בדקו את המבנה בפועל של התשובות והתאימו את כללי הדוח לתהליך העבודה שלכם.