شرح Scrapy في Python 3 لاستخراج الصور من Google Drive وإنشاء API بصيغة JSON بسهولة
يعد Scrapy واحدًا من أقوى أطر عمل Web Scraping المتوفرة ضمن مكتبات بايثون 3، حيث يوفر بيئة احترافية لبناء برامج قادرة على جمع البيانات من المواقع بسرعة وكفاءة مع استهلاك منخفض للموارد.
ورغم أن أغلب الأمثلة المنتشرة تعتمد على استخراج البيانات من المواقع التقليدية، إلا أن Scrapy يمتلك مرونة كبيرة تسمح بالتعامل مع العديد من الخدمات المختلفة، ومن بينها Google Drive.
في هذا المقال سنتعرف على طريقة استخراج جميع الصور الموجودة داخل مجلد في Google Drive وتحويلها إلى ملف JSON يحتوي على أسماء الصور وروابط المعاينة الخاصة بها باستخدام Scrapy وPython 3.
كما سنشرح فكرة عمل الكود خطوة بخطوة مع توضيح أهم الدوال المستخدمة وأفضل الممارسات عند تنفيذ مشاريع Web Scraping.
لماذا يعتبر Scrapy من أفضل مكتبات بايثون 3؟
إذا كنت تعمل في مجال جمع البيانات أو بناء أدوات الأتمتة فإن Scrapy يعتبر من أول الخيارات التي ينصح بها.
ويرجع ذلك إلى أنه يوفر:
- سرعة عالية في تنفيذ الطلبات.
- إدارة تلقائية للطلبات والاستجابات.
- دعم تصدير البيانات إلى JSON وCSV وXML.
- سهولة التعامل مع CSS Selectors وXPath.
- إدارة متقدمة للـ Concurrency.
- إمكانية إنشاء مشاريع Web Scraping ضخمة.
ولهذا السبب تعتمد عليه العديد من الشركات عند بناء أنظمة استخراج البيانات الضخمة.
فكرة المشروع
الفكرة بسيطة للغاية.
لدينا مجلد داخل Google Drive يحتوي على مجموعة من الصور.
بدلاً من الدخول إلى المجلد ونسخ روابط الصور يدويًا، سنجعل Scrapy يقوم بهذه المهمة بالكامل.
البرنامج سيقوم بالخطوات التالية:
- فتح مجلد Google Drive.
- قراءة جميع الملفات الموجودة بداخله.
- التأكد أن الملف عبارة عن صورة.
- استخراج File ID.
- إنشاء رابط Preview لكل صورة.
- حفظ جميع النتائج داخل ملف JSON.
وبهذه الطريقة يصبح لديك API بسيط يمكن استخدامه داخل أي تطبيق Flutter أو React أو حتى مواقع الويب.
إنشاء Spider جديد داخل Scrapy
بعد إنشاء مشروع Scrapy نبدأ بإنشاء Spider جديد مسؤول عن جلب الصور من Google Drive.
يعتمد هذا الـ Spider على صفحة Google Drive Embedded Folder والتي تعرض محتويات المجلد داخل صفحة HTML يمكن لـ Scrapy قراءتها بسهولة.
ويتم تعريف اسم الـ Spider بالشكل التالي:
name = "images"
وبعد ذلك يمكن تشغيله باستخدام الأمر:
python3 -m scrapy crawl images
سيبدأ Scrapy مباشرة في قراءة جميع الملفات الموجودة داخل المجلد المحدد.
إعدادات Scrapy المستخدمة
داخل المشروع تم استخدام بعض الإعدادات المهمة لتحسين الأداء.
- إيقاف ROBOTSTXT_OBEY.
- تقليل عدد الطلبات المتزامنة.
- إضافة Download Delay.
- تصدير النتائج مباشرة إلى JSON.
وهذه الإعدادات تساعد على جعل عملية الاستخراج أكثر استقرارًا خصوصًا عند التعامل مع مجلدات كبيرة تحتوي على عدد كبير من الملفات.
تحديد امتدادات الصور
ليس كل ملف موجود داخل Google Drive يعتبر صورة.
لذلك يتم إنشاء قائمة تحتوي على جميع الامتدادات المدعومة مثل:
- JPG
- PNG
- WEBP
- GIF
- SVG
- BMP
- AVIF
- HEIC
- TIFF
بعد ذلك يقوم البرنامج بمقارنة اسم كل ملف بهذه الامتدادات للتأكد من أنه صورة قبل إضافته إلى النتائج.
قراءة Folder ID
يعتمد البرنامج على Folder ID الخاص بـ Google Drive.
وهو الجزء الموجود داخل رابط المجلد.
عند تشغيل البرنامج يمكنك تمرير Folder ID جديد دون الحاجة لتعديل الكود، مما يجعل الـ Spider قابلًا لإعادة الاستخدام مع أي مجلد آخر.
بدء عملية Scraping
تبدأ عملية استخراج البيانات من خلال إنشاء طلب HTTP إلى صفحة Embedded Folder الخاصة بـ Google Drive.
بعد استلام الصفحة يقوم Scrapy بتحليل عناصر HTML واستخراج جميع الملفات الموجودة داخل المجلد.
وتتميز هذه الطريقة بأنها لا تحتاج إلى استخدام Google Drive API أو OAuth، مما يجعلها مناسبة للمجلدات العامة.
تحليل عناصر الصفحة
بعد تحميل الصفحة يبدأ Scrapy في البحث عن العناصر التي تمثل الملفات.
ويتم ذلك باستخدام CSS Selectors والتي تعتبر من أسرع الطرق للتعامل مع صفحات HTML داخل Scrapy.
بعد الحصول على العناصر يبدأ البرنامج في استخراج:
- اسم الملف.
- الرابط.
- File ID.
ثم يتم التحقق من أن الملف عبارة عن صورة قبل إضافته إلى النتائج النهائية.
استخراج File ID
كل ملف داخل Google Drive يمتلك معرفًا فريدًا يسمى File ID.
يتم استخراج هذا المعرف باستخدام التعبيرات النمطية (Regular Expressions)، وبعد الحصول عليه يمكن إنشاء أي رابط خاص بالملف بسهولة.
وتعتبر هذه الخطوة من أهم أجزاء المشروع لأنها المسؤولة عن إنشاء روابط المعاينة.
إنشاء رابط Preview
بدلًا من استخدام روابط التحميل المباشر يتم إنشاء روابط Preview الخاصة بـ Google Drive.
ويمتاز هذا النوع من الروابط بأنه يعمل مباشرة داخل التطبيقات أو صفحات الويب دون الحاجة لتحميل الملف كاملًا.
كما يمكن استخدامه داخل Flutter أو Android أو React لعرض الصور بسهولة.
تصدير النتائج إلى JSON
بعد الانتهاء من معالجة جميع الملفات يقوم Scrapy تلقائيًا بحفظ النتائج داخل ملف JSON.
وسيكون شكل البيانات مشابهًا لما يلي:
[
{
"name": "image1.jpg",
"url": "https://drive.google.com/file/d/FILE_ID/preview"
},
{
"name": "image2.png",
"url": "https://drive.google.com/file/d/FILE_ID/preview"
}
]
ويمكن بعد ذلك استهلاك هذا الملف بسهولة داخل أي تطبيق أو API.
أفضل الممارسات
- اجعل المجلد Public قبل تشغيل Scrapy.
- أضف امتدادات الصور التي تحتاجها فقط.
- استخدم Download Delay عند التعامل مع مجلدات كبيرة.
- احفظ النتائج بصيغة JSON لسهولة استخدامها.
- اجعل Folder ID متغيرًا حتى يمكن إعادة استخدام الـ Spider.
- استخدم CSS Selectors بدلاً من XPath عند عدم الحاجة.
الخلاصة
يعتبر Scrapy من أقوى مكتبات بايثون 3 لبناء أدوات Web Scraping احترافية، ويمنح المطورين مرونة كبيرة في استخراج البيانات من مصادر مختلفة دون تعقيد.
وفي هذا المقال تعرفنا على طريقة استخراج الصور من مجلد Google Drive وتحويلها إلى ملف JSON جاهز للاستخدام داخل التطبيقات المختلفة، وذلك دون الحاجة إلى Google Drive API أو عمليات مصادقة معقدة.
كما أن هذا الأسلوب يمكن تطويره بسهولة لإضافة ميزات أخرى مثل استخراج ملفات PDF أو الفيديوهات أو إنشاء REST API متكامل يعرض محتويات Google Drive بشكل ديناميكي.
رابط المكتبة
Scrapy
الكود كامل
import re
import scrapy
# python3 -m scrapy crawl images
class ImagesSpider(scrapy.Spider):
name = "images"
custom_settings = {
"ROBOTSTXT_OBEY": False,
"CONCURRENT_REQUESTS_PER_DOMAIN": 2,
"DOWNLOAD_DELAY": 0.5,
"FEEDS": {
"images.json": {
"format": "json",
"encoding": "utf-8",
"overwrite": True,
"store_empty": True,
}
},
}
IMAGE_EXTENSIONS = {
".jpg",
".jpeg",
".png",
".gif",
".webp",
".bmp",
".svg",
".tif",
".tiff",
".heic",
".heif",
".avif",
}
def __init__(self, folder_id=None, **kwargs):
super().__init__(**kwargs)
self.folder_id = folder_id or "###"
def start_requests(self):
url = f"https://drive.google.com/embeddedfolderview?id={self.folder_id}#list"
yield scrapy.Request(url, callback=self.parse_files)
def parse_files(self, response):
entries = response.css("div.flip-entry")
self.logger.info("عدد العناصر التي تم العثور عليها: %d", len(entries))
for entry in entries:
href = entry.css("a::attr(href)").get("")
file_id = self._extract_file_id(href)
if not file_id:
continue
name = self._extract_name(entry)
if not name or not self._is_image_file(name):
continue
yield {
"name": name,
"url": self._build_preview_url(file_id),
}
def _extract_file_id(self, href):
match = re.search(r"/file/d/([a-zA-Z0-9_-]+)/", href)
return match.group(1) if match else None
def _extract_name(self, entry):
name = entry.css("a::attr(title)").get()
if not name:
name = entry.css("a::text").get()
if not name:
name = entry.css("::text").get()
return name.strip() if name else None
def _is_image_file(self, filename):
lower_name = filename.lower()
return any(lower_name.endswith(ext) for ext in self.IMAGE_EXTENSIONS)
def _build_preview_url(self, file_id):
return f"https://drive.google.com/file/d/{file_id}/preview"لمزيد من المقالات :


