يمكنك مطابقة قائمة حسابات IG مع موجز الحملة تلقائيًا قبل إطلاقها، والحصول على ملف CSV لا يضم إلا السجلات التي تستدعي الانتباه. يطلب البرنامج النصي بيانات كل ملف شخصي، ويقارن اسم المستخدم وحالة الخصوصية والتوثيق بالقيم المتوقعة، ويحفظ أيضًا أعداد المتابعين المتاحة. وهكذا تتحول عملية التحقق اليدوية المتكررة إلى خطوة مراجعة واضحة قبل بدء العمل على الحملة.
المهمة: اكتشاف حالات الاختلاف قبل النشر
يتضمن جدول الحملة عادةً اسم الحساب وعددًا من التوقعات: أن يكون الملف الشخصي عامًا، وأن يطابق اسم المستخدم الاسم المتفق عليه، وأن تتوافق علامة التوثيق مع ما ورد في الموجز. وقد يغيّر الحساب اسمه أو يصبح خاصًا أو يتبين أنه ملف آخر يحمل اسمًا مشابهًا، وذلك بين إعداد القائمة وإطلاق الحملة. ويصعب تكرار عملية التحقق يدويًا أو إبراز الحالات الاستثنائية بسرعة.
يكفي لهذا الفحص الأولي جلب الملف الشخصي باستخدام اسم المستخدم. وتحدد وثائق jsonscraper المنشورة المسار GET /v1/user/by/username مع الوسيط username، كما يتوفر الوسيط الاختياري cache_timeout. وقد تتضمن الاستجابة اسم المستخدم والاسم الكامل ومؤشري الخصوصية والتوثيق، وأعداد المنشورات والمتابعين والحسابات المتابَعة، فضلًا عن النبذة التعريفية. ينبغي قراءة الحقول من الاستجابة الفعلية: فلقطة المخطط تؤكد وجودها في استجابة جرى رصدها، لكن القيم قد تختلف أو تغيب.
إعداد الجدول وقواعد التحقق
أنشئ ملف CSV باسم profiles.csv يتضمن الأعمدة username وexpected_private وexpected_verified. أدخل في العمودين الأخيرين القيم المتوقعة true أو false، واكتب اسم المستخدم من دون الرمز @. وإذا لم يكن التوقع معروفًا لملف ما، فاترك الخلية فارغة؛ إذ يجب ألا يحوّل البرنامج غياب التوقع إلى خطأ.
username,expected_private,expected_verified
examplebrand,false,true
anotheraccount,false,false
ينفذ هذا الفحص مهمتين محددتين: التحقق من مطابقة اسم المستخدم المسترجع للاسم المطلوب، وكشف الاختلافات عن التوقعات المسجلة بشأن الخصوصية والتوثيق. أما أعداد المتابعين والنبذة التعريفية فتُحفظ لتوفير سياق للمراجعة اليدوية، ولا تُعامل بوصفها دليلًا على جودة الجمهور أو ملاءمة صاحب الحساب للحملة.
الاتصال بـ IG Scraper API
احفظ مفتاح الوصول في متغير البيئة JSONSCRAPER_INSTAGRAM_LICENSE_KEY. لا تضع السر في ملف CSV أو الشيفرة المصدرية أو سجلات التشغيل. وتوضح وثائق نقطة نهاية IG المسار وأسماء المعاملات؛ أما عنوان API الأساسي فهو https://ig.jsonscraper.com، واسم معامل المفتاح هو license_key.
قبل معالجة القائمة كاملة، نفّذ طلبًا تجريبيًا واحدًا لسجل اختباري، وتحقق من بنية JSON وتأكد من أن حسابك يملك صلاحية الوصول. وبما أن نقطة النهاية تقبل اسم المستخدم، فلا حاجة في هذا السيناريو البسيط إلى معرّف معروف للملف الشخصي أو إلى مسارات إضافية.
مثال: الطلبات والمقارنة وإخراج CSV بالحالات الاستثنائية
يتوافق البرنامج النصي التالي مع Python 3.8 والإصدارات الأحدث. يقرأ ملف CSV، وينفذ طلب GET واحدًا لكل ملف شخصي، ويتحقق من حالة استجابة HTTP، ويحفظ الحقول المهمة الأصلية مع نتيجة المقارنة. ثبّت الاعتمادية بالأمر python -m pip install requests، ثم صدّر المفتاح قبل التشغيل.

import csv
import os
import time
from pathlib import Path
import requests
BASE_URL = "https://ig.jsonscraper.com/v1/user/by/username"
API_KEY = os.environ["JSONSCRAPER_INSTAGRAM_LICENSE_KEY"]
INPUT_FILE = Path("profiles.csv")
OUTPUT_FILE = Path("preflight_results.csv")
def parse_expected(value):
value = (value or "").strip().lower()
if value == "true":
return True
if value == "false":
return False
return None
def profile_from_response(payload):
# The documented observed response wraps profile fields in "ig".
if payload.get("status") != "ok":
raise ValueError("API response status is not ok")
profile = payload.get("ig")
if not isinstance(profile, dict):
raise ValueError("Response has no profile object under 'ig'")
return profile
with INPUT_FILE.open(newline="", encoding="utf-8") as source:
rows = list(csv.DictReader(source))
results = []
for row in rows:
requested = (row.get("username") or "").strip().lstrip("@")
if not requested:
results.append({
"requested_username": "",
"result": "missing_username",
"error": "username is empty",
})
continue
try:
response = requests.get(
BASE_URL,
params={"username": requested, "license_key": API_KEY},
timeout=30,
)
response.raise_for_status()
profile = profile_from_response(response.json())
actual_username = profile.get("username")
actual_private = profile.get("is_private")
actual_verified = profile.get("is_verified")
expected_private = parse_expected(row.get("expected_private"))
expected_verified = parse_expected(row.get("expected_verified"))
checks = []
if actual_username and actual_username.casefold() != requested.casefold():
checks.append("username_mismatch")
if expected_private is not None and actual_private != expected_private:
checks.append("privacy_mismatch")
if expected_verified is not None and actual_verified != expected_verified:
checks.append("verification_mismatch")
results.append({
"requested_username": requested,
"username": actual_username,
"full_name": profile.get("full_name"),
"is_private": actual_private,
"is_verified": actual_verified,
"media_count": profile.get("media_count"),
"follower_count": profile.get("follower_count"),
"following_count": profile.get("following_count"),
"result": "review" if checks else "matched",
"checks": ";".join(checks),
"error": "",
})
except (requests.RequestException, ValueError, KeyError) as exc:
results.append({
"requested_username": requested,
"result": "request_or_response_error",
"error": str(exc),
})
# A small delay spaces requests; it is not a documented quota guarantee.
time.sleep(0.5)
fieldnames = sorted({key for item in results for key in item})
with OUTPUT_FILE.open("w", newline="", encoding="utf-8") as destination:
writer = csv.DictWriter(destination, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)
print("Saved", len(results), "rows to", OUTPUT_FILE)
يتحقق البرنامج من غلاف الاستجابة المرصود تحديدًا: قيمة status الخارجية وكائن الملف الشخصي ig. إذا غيّر مزود الخدمة التنسيق، فسيتوقف التحقق من البنية عند معالجة السجل المعني ويحفظ الخطأ بدلًا من إنشاء تطابق غير صحيح بصمت. ولا يطبع البرنامج المفتاح ولا يدرجه في الملف الناتج.
كيفية قراءة النتائج
اجتازت السجلات ذات الحالة matched المقارنات المحددة في preflight_results.csv. وتشير القيمة review إلى اختلاف معيار واحد أو أكثر عن موجز الحملة؛ ويبين عمود checks المعايير المعنية. أما أخطاء الطلب أو الاستجابة فتُسجل على نحو منفصل، كي لا يبدو تعذر الوصول إلى البيانات كأنه تطابق مؤكد.
تساعد أعداد المتابعين والمنشورات على رؤية لقطة الملف الشخصي الحالية إلى جانب الطلب. وهذه القيم مأخوذة من الاستجابة لحظة الطلب. ولتقييم التغييرات بمرور الوقت، احفظ عمليات تشغيل منفصلة مؤرخة؛ إذ لا يتضمن الفحص الواحد سجلًا تاريخيًا. وقد تكون بعض الحقول فارغة، وعندها يظل السجل صالحًا للتحقق من الهوية والسمات الأخرى المتاحة، لكن لا يمكن مقارنته وفق عدّاد غير متوفر.
أتمتة الفحص قبل إطلاق الحملة
بعد التحقق يدويًا من ملف CSV اختباري، أضف البرنامج النصي إلى جدول زمني أو إلى خطوة إعداد الحملة. ولإجراء فحص قابل للتكرار، احتفظ بالقائمة الأصلية منفصلة، وسجّل تاريخ التشغيل، واحفظ ملفات CSV الناتجة في مساحة عمل تخزين محمية. وإذا كان اسم المستخدم قد يتغير، فمن المفيد استخدام معرّف ثابت للسجل من نظامك.
عند زيادة حجم القائمة، أضف حدًا للتنفيذ المتوازي ومحاولات إعادة تقتصر على أخطاء الشبكة المؤقتة وسجلًا مستقلًا لرموز الأخطاء يخلو من الأسرار. لا تكرر المحاولات بلا نهاية عند استخدام مفتاح غير صالح أو اسم مستخدم غير صحيح. ويمكن إضافة cache_timeout بما يتوافق مع سياسة حداثة البيانات المطلوبة فقط؛ إذ توضح الوثائق أن التخزين المؤقت معطل افتراضيًا في IG، وأن تعيين قيمة أكبر من صفر يفعّل التخزين المؤقت للفترة المحددة.
يقلّص فحص الملف الشخصي المراجعة اليدوية إلى قائمة محددة بالحالات الاستثنائية: فتظهر الأسماء والخصوصية والتوثيق وأعداد المتابعين المتاحة في جدول واحد قبل بدء الحملة. ولمعرفة معاملات API وخيارات التكامل الحالية، راجع صفحة IG Scraper API ووثائق المسارات.