جمع آلاف الصور لتدريب نموذج الرؤية الحاسوبية هو مهمة غالبًا ما تواجه مشكلتين: الحظر من مصدر البيانات (صور جوجل، بينتيريست، الأسواق، مواقع الصور) واستهلاك البيانات المرتفع بشكل غير متوقع. عنوان IP واحد يذهب بسرعة إلى الحظر، وقد تتجاوز تكلفة بيانات البروكسي تكلفة وضع العلامات على مجموعة البيانات نفسها. في هذه المقالة، سنناقش كيفية تصميم زاحف للصور لا يفقد البيانات بسبب الحظر، وكيفية حساب ميزانية البيانات مسبقًا.
لماذا البروكسي عند جمع الصور للرؤية الحاسوبية
نادرًا ما يتم جمع مجموعات البيانات للرؤية الحاسوبية من مصدر واحد. عادةً ما تكون مزيجًا من نتائج بحث الصور، بطاقات المنتجات في الأسواق، مواقع الصور، وسائل التواصل الاجتماعي وواجهات برمجة التطبيقات المفتوحة. تفرض جميع هذه المصادر تقريبًا قيودًا على عدد الطلبات من عنوان IP واحد: تظهر صور جوجل كابتشا بعد بضع مئات من الطلبات المتتالية، بينما تحظر بينتيريست الوصول إلى واجهة برمجة التطبيقات مؤقتًا، وتقدم Wildberries و Ozon بطاقات فارغة أو تعيد التوجيه إلى صفحة التحقق عند النشاط المشبوه.
بدون بروكسي، ستواجه سقفًا يتراوح بين عدة مئات أو آلاف الصور يوميًا من عنوان واحد. إذا كنت بحاجة إلى مجموعة بيانات تتكون من 50,000 إلى 500,000 صورة (وهو ما يتطلب عادةً للشبكات التلافيفية والمحولات في مهام التصنيف والكشف)، فمن المستحيل جمعها في وقت معقول بدون مجموعة موزعة من عناوين IP — إما أنك ستواجه باستمرار حظرًا، أو ستحصل على عينة مشوهة بشدة بسبب القيود الزمنية والموقع الجغرافي.
السبب الثاني هو التنوع الجغرافي للبيانات. إذا كان يجب على النموذج التعرف على الأشياء بنفس الكفاءة بغض النظر عن منطقة التصوير (مثل علامات المرور في دول مختلفة أو المنتجات في الأسواق المحلية)، يجب أن يتصل الزاحف بعناوين IP من دول مختلفة. لن يوفر مركز بيانات واحد مع عنوان IP خارجي واحد هذا التنوع.
كم من البيانات تستهلك فعليًا لمجموعة البيانات
غالبًا ما يتم التقليل من استهلاك البيانات عند جمع الصور. الأمر لا يتعلق فقط بحجم الصور نفسها — صفحات HTML، حزم JS، المعاينات، بكسلات التتبع و CSS أيضًا تمر عبر البروكسي إذا لم يتم ضبط الزاحف بدقة على URL المطلوبة.
| نوع المحتوى | الوزن المتوسط | البيانات لكل 10,000 وحدة |
|---|---|---|
| معاينة/صورة مصغرة (150–300 بكسل) | 15–40 كيلوبايت | ~250 ميغابايت |
| صور بدقة متوسطة (800–1200 بكسل) | 80–200 كيلوبايت | ~1.4 غيغابايت |
| صور بدقة عالية (2000+ بكسل) | 400 كيلوبايت – 1.5 ميغابايت | ~9.5 غيغابايت |
| صفحة HTML لبطاقة المنتج (بدون صور) | 150–400 كيلوبايت | ~2.7 غيغابايت |
في الممارسة العملية، إذا كنت تجمع 100,000 صورة بدقة متوسطة مع صفحات بطاقات المنتجات (لاستخراج العلامات — الفئات، الصناديق، السمات)، فإن استهلاك البيانات النهائي عادة ما يقع في نطاق 25–45 غيغابايت. إذا كنت بحاجة إلى صور بدقة عالية لمهام الكشف عن الأشياء الصغيرة — احسب على 80–150 غيغابايت لنفس العدد من الصور. يجب أخذ هذه الأرقام في الاعتبار عند اختيار خطة البروكسي مسبقًا، وليس بعد ذلك.
مراكز البيانات، السكنية والمحمولة: ماذا تختار
لجمع الصور، هناك ثلاثة معايير مهمة: السرعة، تكلفة البيانات ومرونة الحظر. تختلف هذه المعايير بشكل كبير بين أنواع البروكسي المختلفة.
| المعيار | مركز البيانات | السكنية | المحمولة |
|---|---|---|---|
| السرعة | عالية | متوسطة | منخفضة-متوسطة |
| مرونة الحظر | منخفضة | عالية | عالية جدًا |
| تكلفة البيانات | منخفضة | متوسطة-عالية | عالية |
| مناسب لـ | واجهات برمجة التطبيقات المفتوحة، مواقع بدون حماية صارمة | صور جوجل، بينتيريست، الأسواق | وسائل التواصل الاجتماعي مع حماية صارمة ضد الروبوتات |
لمعظم مهام جمع الصور، توفر البروكسي السكنية توازنًا مثاليًا — حيث تبدو عناوين IP كأنها مستخدمون عاديون، مما يجعل أنظمة الحماية ضد الروبوتات في الأسواق ومحركات البحث تعرض كابتشا بشكل أقل. إذا كان المصدر هو موقع صور مفتوح أو واجهة برمجة تطبيقات بدون حدود صارمة، فإن استخدام بروكسي مراكز البيانات يكون أرخص — فهي أسرع وتسمح بنقل كميات كبيرة من البيانات بتكلفة أقل لكل غيغابايت. لجمع الصور من التطبيقات المحمولة أو وسائل التواصل الاجتماعي ذات الحماية المتقدمة ضد الروبوتات، فإن البروكسي المحمولة هي الأنسب — لأنها تستخدم عناوين IP حقيقية من مزودي الخدمة ولا تتعرض تقريبًا للحظر.
زاحف أساسي باستخدام requests مع تدوير البروكسي
للبدء، يمكن استخدام سكربت بسيط متزامن باستخدام requests مع تدوير البروكسي لكل طلب أو بعد عدد محدد من الطلبات. أدناه مثال على تنزيل الصور من قائمة URL مع التحقق من نوع المحتوى وتحديد حجم الملف، لتجنب تحميل ملف ثقيل من نوع غير مناسب.
import requests
import itertools
import hashlib
import os
PROXIES = [
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
]
proxy_cycle = itertools.cycle(PROXIES)
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "image/avif,image/webp,image/*,*/*;q=0.8",
}
def download_image(url, save_dir="dataset", max_size_mb=10, timeout=15):
proxy = next(proxy_cycle)
proxies = {"http": proxy, "https": proxy}
try:
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=timeout, stream=True)
resp.raise_for_status()
content_type = resp.headers.get("Content-Type", "")
if "image" not in content_type:
return None
content_length = int(resp.headers.get("Content-Length", 0))
if content_length > max_size_mb * 1024 * 1024:
return None
file_hash = hashlib.md5(url.encode()).hexdigest()
ext = content_type.split("/")[-1].split(";")[0]
filepath = os.path.join(save_dir, f"{file_hash}.{ext}")
os.makedirs(save_dir, exist_ok=True)
with open(filepath, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
return filepath
except requests.exceptions.RequestException as e:
print(f"خطأ عند {url} عبر {proxy}: {e}")
return None
النقطة الرئيسية هي التحقق من Content-Length قبل تنزيل جسم الاستجابة. هذا يوفر البيانات عن طريق تصفية الملفات الثقيلة جدًا قبل التحميل الكامل. تدوير البروكسي عبر itertools.cycle يوزع الحمل بالتساوي بين عناوين IP، مما يقلل من خطر حظر عنوان معين.
جمع غير متزامن عبر aiohttp
السكربت المتزامن باستخدام requests مناسب لعدة آلاف من الصور، لكن لمجموعات البيانات التي تحتوي على 50,000 ملف أو أكثر، تحتاج إلى اللامتزامن — وإلا فإن الجمع سيستغرق أيامًا. aiohttp مع إشارة للحد من التوازي هو خيار عملي لعشرات الآلاف من المهام المتزامنة دون تحميل بروكسي.
import asyncio
import aiohttp
import itertools
PROXIES = [
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
]
proxy_cycle = itertools.cycle(PROXIES)
sem = asyncio.Semaphore(50) # تحديد عدد الطلبات المتزامنة
async def fetch_image(session, url, idx):
proxy = next(proxy_cycle)
async with sem:
try:
async with session.get(url, proxy=proxy, timeout=15) as resp:
if resp.status != 200:
return
content_type = resp.headers.get("Content-Type", "")
if "image" not in content_type:
return
data = await resp.read()
with open(f"dataset/{idx}.jpg", "wb") as f:
f.write(data)
except Exception as e:
print(f"خطأ {url}: {e}")
async def main(urls):
async with aiohttp.ClientSession() as session:
tasks = [fetch_image(session, url, i) for i, url in enumerate(urls)]
await asyncio.gather(*tasks)
# asyncio.run(main(url_list))
إشارة لـ 50 اتصالًا متزامنًا هي نقطة انطلاق. إذا كانت البروكسي السكنية تتحمل الحمل دون زيادة في الأخطاء 429 ووقت الانتظار، يمكن زيادة العدد تدريجيًا إلى 100-150. الأهم هو مراقبة نسبة الطلبات غير الناجحة: إذا زادت عن 5-7%، يجب تقليل التوازي بدلاً من زيادة مجموعة البروكسي بلا حدود.
Scrapy + بروكسي-وسيط لجمع البيانات على نطاق واسع
لجمع البيانات في الإنتاج مع قائمة انتظار مدمجة، وإعادة المحاولة وإزالة التكرار للـ URL، من الأسهل استخدام Scrapy مع ImagesPipeline. يقوم بتنزيل الصور بنفسه، يتحقق من صلاحيتها عبر PIL ويمكنه إنشاء معاينات بأحجام مختلفة.
# settings.py
ITEM_PIPELINES = {
'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_STORE = 'dataset_images'
IMAGES_MIN_HEIGHT = 200
IMAGES_MIN_WIDTH = 200
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.ProxyRotationMiddleware': 350,
}
CONCURRENT_REQUESTS = 32
DOWNLOAD_DELAY = 0.5
RETRY_TIMES = 3
# middlewares.py
import random
class ProxyRotationMiddleware:
PROXIES = [
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
"http://user:[email protected]:10000",
]
def process_request(self, request, spider):
request.meta['proxy'] = random.choice(self.PROXIES)
المعايير IMAGES_MIN_HEIGHT و IMAGES_MIN_WIDTH تتخلص تلقائيًا من الرموز الصغيرة والرسوم المتحركة التي تلوث مجموعة البيانات وتستهلك البيانات بلا فائدة. DOWNLOAD_DELAY بمقدار 0.5 ثانية يقلل من تكرار الطلبات من بروكسي واحد، مما يقلل من نسبة الكابتشا في المصادر ذات المراقبة الصارمة ضد الاحتيال مثل بينتيريست.
كيفية تقليل استهلاك البيانات
عادةً ما يتم احتساب البيانات عبر البروكسي بناءً على الحجم، لذا فإن أي تحسين يوفر الميزانية مباشرة. إليك بعض الحيل الفعالة:
- اطلب المعاينات، وليس النسخ الأصلية، إذا كان الدقة 512–1024 بكسل كافية للتدريب — معظم المصادر تقدم الصورة بالحجم المطلوب عبر URL منفصل أو معلمة استعلام.
- قم بتصفية البيانات حسب Content-Length قبل تنزيل الجسم — طلب HEAD أو قراءة رؤوس GET المتدفقة يسمح بالتخلص من الملفات الثقيلة جدًا دون استهلاك البيانات لتحميلها.
- قم بإيقاف تحميل الموارد المساعدة، إذا كان الزاحف يعمل عبر متصفح بدون رأس: قم بحظر CSS، الخطوط، ونصوص التتبع، مع ترك HTML والصور المطلوبة فقط.
- قم بإزالة تكرار URL قبل الطلب، وليس بعد التنزيل — الصور المتطابقة على صفحات بطاقات المنتجات المختلفة (مثل Wildberries) لا تحتاج إلى التنزيل مرة أخرى.
- استخدم ذاكرة التخزين المؤقت المحلية للاستجابات عند إعادة تشغيل الزاحف أثناء التصحيح، لتجنب استهلاك البيانات عبر البروكسي في كل تشغيل تجريبي للكود.
الأخطاء الشائعة، 403 وحدود المعدل
عند جمع الصور بكميات كبيرة، سيواجه الزاحف حتمًا استجابات 403، 429 وإعادة التوجيه المؤقت إلى صفحات التحقق. المعالجة الصحيحة لهذه الرموز توفر البيانات ومجموعة البروكسي.
| الرمز/العرض | السبب | ماذا تفعل |
|---|---|---|
| 403 محظور | IP في القائمة السوداء للمصدر | تدوير البروكسي، تغيير User-Agent |
| 429 عدد الطلبات كثير جدًا | تم تجاوز حد الطلبات في الدقيقة | زيادة DOWNLOAD_DELAY، تقليل التوازي |
| إعادة توجيه إلى كابتشا | تحليل سلوكي يشتبه في وجود روبوت | الانتقال إلى IP سكنية/محمولة |
| Content-Length فارغ | استجابة مجزأة أو دمية بدلاً من الصورة | التحقق من الحجم الفعلي للبايتات التي تم تنزيلها |
من المهم تسجيل نسبة الطلبات الناجحة لكل بروكسي. إذا كان عنوان IP معين يعطي 403 بشكل مستمر أكثر من الآخرين — قم بإخراجه من التدوير تلقائيًا، دون انتظار أن يؤثر على الإحصائيات العامة للحظر عبر مجموعة البروكسي.
حساب ميزانية بيانات البروكسي
قبل بدء الجمع، من المفيد تقدير حجم البيانات مسبقًا، وليس حسابها بعد ذلك. الصيغة بسيطة: عدد الصور × الوزن المتوسط للملف × معامل النفقات العامة (HTML، الرؤوس، الطلبات المتكررة بسبب الأخطاء — عادةً 1.3–1.6).
مثال على الحساب لمجموعة بيانات تحتوي على 200,000 صورة بدقة متوسطة (~150 كيلوبايت) مع جمع بطاقات المنتجات: 200,000 × 150 كيلوبايت = 30 غيغابايت من الوزن النقي للصور. مع الأخذ في الاعتبار صفحات HTML والطلبات المتكررة بسبب الحظر المؤقت (معامل 1.5) يكون الاستهلاك النهائي حوالي 45 غيغابايت. إذا كانت بعض المصادر تتطلب IP محمولة بسبب حماية ضد الروبوتات، يجب احتساب ذلك في مجموعة البروكسي بشكل منفصل، حيث أن البيانات عبر IP المحمولة عادة ما تكون أغلى من السكنية أو مراكز البيانات.
من الممارسات الجيدة جمع دفعة تجريبية تتكون من 1,000–2,000 صورة، قياس الاستهلاك الفعلي للبيانات ونسبة الأخطاء، ثم استقراء ذلك على الحجم المخطط لمجموعة البيانات. هذا أكثر دقة من أي حسابات نظرية، حيث يأخذ في الاعتبار خصوصيات المصدر المحدد.
الخاتمة
جمع الصور لتدريب نماذج الرؤية الحاسوبية هو مهمة على تقاطع هندسة البيانات وإدارة البنية التحتية الشبكية بشكل صحيح. توفر البنية الصحيحة للزاحف (اللامتزامن، التصفية حسب Content-Length، إزالة تكرار URL) توفير البيانات، بينما يحدد اختيار البروكسي المدروس ما إذا كنت ستجمع الحجم المطلوب من مجموعة البيانات في أيام أو أسابيع من الحظر المستمر.
إذا كانت مصادر البيانات تستخدم حماية متقدمة ضد الروبوتات — محركات البحث للصور، الأسواق، وسائل التواصل الاجتماعي — ابدأ بـ البروكسي السكنية: فهي توفر أفضل توازن بين المرونة ضد الحظر وتكلفة البيانات. لمصادر API المفتوحة ومواقع الصور بدون حدود صارمة، من المنطقي توفير المال باستخدام بروكسي مراكز البيانات، ولأكثر التطبيقات حماية — قم بتوصيل البروكسي المحمولة للجزء النهائي والأكثر تعقيدًا من الجمع.