استخراج بيانات متجر إلكتروني باستخدام بايثون عبر Beautiful Soup وPandas

دقائق القراءة: 6

مقدمة: ما هو استخراج البيانات من الويب باستخدام Python؟

يُعد استخراج البيانات من الويب أو Web Scraping من أهم المهارات العملية التي تساعد المطورين والمحللين على جمع المعلومات من المواقع بشكل آلي ومنظم. في هذا الدليل سنبني مشروعاً عملياً لاستخراج بيانات منتجات من متجر إلكتروني باستخدام لغة Python مع مكتبتي Beautiful Soup وPandas.

الفكرة هنا لا تقتصر على قراءة الصفحة الرئيسية فقط، بل تمتد إلى الدخول إلى صفحة كل منتج على حدة لاستخراج تفاصيل أعمق مثل اسم المنتج والسعر والتقييم والوصف. وهذه الطريقة مفيدة جداً عندما لا تكون كل البيانات متاحة في صفحة القوائم الرئيسية.

شرح استخراج بيانات متجر إلكتروني باستخدام بايثون وBeautiful Soup وPandas

قبل البدء: الاعتبارات الأخلاقية واحترام robots.txt

قبل تنفيذ أي عملية Scraping على أي موقع، يجب مراجعة ملف robots.txt الخاص به. هذا الملف يوضح للمطورين وبرامج الزحف ما الصفحات المسموح الوصول إليها وما القيود المفروضة.

  • لا ترسل عدداً كبيراً من الطلبات في وقت قصير.
  • تجنب الضغط على خوادم الموقع دون داعٍ.
  • استخدم المشروع لأغراض تعليمية أو تحليلية مشروعة.
  • تحقق دائماً من شروط الاستخدام الخاصة بالموقع.

في المثال التطبيقي، سنعتمد على متجر إلكتروني متخصص في بيع الويسكي، وسنجمع البيانات بشكل منظم ومسؤول.

واجهة متجر إلكتروني لمنتجات الويسكي المستخدمة في شرح استخراج البيانات

فهم المشكلة: لماذا نحتاج إلى زيارة صفحة كل منتج؟

في كثير من المتاجر الإلكترونية، لا تعرض صفحة التصنيفات جميع التفاصيل المهمة. قد تجد اسم المنتج والسعر فقط، بينما يكون التقييم أو الوصف داخل الصفحة الداخلية الخاصة بالمنتج.

لهذا سنعمل على مرحلتين:

  1. جمع روابط جميع المنتجات من صفحات التصنيف.
  2. زيارة كل رابط على حدة لاستخراج البيانات التفصيلية.

هذه المنهجية تمنحك مرونة أعلى وتساعدك على بناء قاعدة بيانات أدق وأكثر فائدة.

عرض قائمة منتجات متجر إلكتروني تتطلب فتح كل منتج لاستخراج التقييم

إعداد مشروع استخراج البيانات في Python

إنشاء المجلد وتثبيت المكتبات

إعداد المشروع بسيط للغاية. يكفي إنشاء مجلد جديد ثم تثبيت المكتبات المطلوبة: beautifulsoup4 وrequests وpandas. يفترض هذا الشرح أنك تستخدم إصدار Python 3.x.

mkdir scraper
pip install beautifulsoup4
pip install requests
pip install pandas

إنشاء ملف المشروع واستيراد المكتبات

بعد ذلك، أنشئ ملفاً داخل المجلد وليكن مثلاً باسم scraper.py، ثم أضف الاستيرادات التالية:

import requests
from bs4 import BeautifulSoup
import pandas as pd

تهيئة المتغيرات الأساسية وإرسال User-Agent

سنحتاج إلى تعريف الرابط الأساسي للموقع في متغير baseurl، وذلك لأن روابط المنتجات قد تأتي بصيغة نسبية ونحتاج إلى تحويلها إلى روابط كاملة.

كذلك من الأفضل إرسال قيمة User-Agent مخصصة مع كل طلب HTTP، لأن بعض المواقع قد تمنع الطلبات الافتراضية القادمة من مكتبة requests.

baseurl = "https://www.thewhiskyexchange.com"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
}

تحليل بنية الصفحة واكتشاف روابط المنتجات

الخطوة التالية هي فحص الصفحة باستخدام أدوات المطور في المتصفح مثل Inspect داخل Chrome DevTools. الهدف هنا هو معرفة الوسوم والعناصر التي تحتوي على بطاقات المنتجات وروابطها.

فحص عناصر صفحة متجر إلكتروني باستخدام أدوات المطور في المتصفح

بعد الفحص سنجد أن كل منتج موجود داخل عنصر li يحمل فئة product-grid__item. لذا يمكننا استخراج جميع هذه العناصر كما يلي:

k = requests.get('https://www.thewhiskyexchange.com/c/35/japanese-whisky').text
soup = BeautifulSoup(k, 'html.parser')
productlist = soup.find_all("li", {"class": "product-grid__item"})
print(productlist)

طباعة القائمة هنا تساعدنا على التأكد من أننا نستهدف العناصر الصحيحة بالفعل.

نتيجة استخراج عناصر المنتجات من صفحة التصنيف باستخدام Beautiful Soup

استخراج روابط صفحات المنتجات

بعد الحصول على العناصر التي تمثل المنتجات، نحتاج الآن إلى استخراج الرابط الداخلي لكل منتج من داخل الوسم a الذي يحمل الفئة product-card.

productlinks = []
for product in productlist:
    link = product.find("a", {"class": "product-card"}).get('href')
    productlinks.append(baseurl + link)

في هذا الجزء:

  • أنشأنا قائمة فارغة باسم productlinks.
  • استخدمنا حلقة for للمرور على كل منتج.
  • استخرجنا قيمة الخاصية href عبر الدالة get().
  • أضفنا baseurl لتكوين رابط كامل وصحيح.

نتيجة جمع روابط المنتجات من الصفحة الرئيسية للتصنيف

جمع الروابط من جميع صفحات التصنيف

لأن المنتجات موزعة على عدة صفحات، نحتاج إلى تكرار العملية على جميع الصفحات بدلاً من صفحة واحدة فقط. في المثال الحالي هناك خمس صفحات، لذلك سنستخدم حلقة تمر من 1 إلى 5.

productlinks = []
for x in range(1, 6):
    k = requests.get(
        'https://www.thewhiskyexchange.com/c/35/japanese-whisky?pg={}&psize=24&sort=pasc'.format(x)
    ).text
    soup = BeautifulSoup(k, 'html.parser')
    productlist = soup.find_all("li", {"class": "product-grid__item"})

    for product in productlist:
        link = product.find("a", {"class": "product-card"}).get('href')
        productlinks.append(baseurl + link)

بعد تشغيل هذا الجزء، يمكنك التأكد من عدد الروابط عبر طباعة طول القائمة productlinks. في المثال الأصلي من المفترض أن نحصل على 97 رابطاً.

التحقق من عدد روابط المنتجات المستخرجة من جميع صفحات التصنيف

تحليل صفحة المنتج واستخراج البيانات المطلوبة

الآن تبدأ المرحلة الأهم: زيارة كل صفحة منتج واستخراج المعلومات التي نحتاجها. بعد فحص صفحة المنتج، سنجد أن البيانات موزعة تقريباً كما يلي:

  • الاسم داخل الوسم h1.
  • السعر داخل الوسم p.
  • التقييم داخل عنصر مراجعات مخصص.
  • الوصف داخل عنصر div.

تحديد مواضع اسم المنتج والسعر والتقييم والوصف داخل صفحة المنتج

يمكننا تنفيذ ذلك عبر الشيفرة التالية:

data = []
for link in productlinks:
    f = requests.get(link, headers=headers).text
    hun = BeautifulSoup(f, 'html.parser')

    try:
        price = hun.find("p", {"class": "product-action__price"}).text.replace('\n', "")
    except:
        price = None

    try:
        about = hun.find("div", {"class": "product-main__description"}).text.replace('\n', "")
    except:
        about = None

    try:
        rating = hun.find("div", {"class": "review-overview"}).text.replace('\n', "")
    except:
        rating = None

    try:
        name = hun.find("h1", {"class": "product-main__name"}).text.replace('\n', "")
    except:
        name = None

    whisky = {
        "name": name,
        "price": price,
        "rating": rating,
        "about": about
    }

    data.append(whisky)

لماذا استخدمنا try وexcept؟

ليست كل صفحات المنتجات متطابقة تماماً. بعض المنتجات قد لا تحتوي على تقييم، وبعضها قد يفتقد جزءاً من الوصف. لذلك يساعدنا استخدام try وexcept على منع توقف البرنامج عند غياب أي عنصر.

تنظيف النصوص باستخدام replace()

عند استخراج النصوص من HTML، غالباً ما تظهر أسطر جديدة أو فراغات غير مرغوبة. لهذا استُخدمت الدالة replace() لإزالة محارف \n وتحسين شكل البيانات قبل تخزينها.

تنظيم البيانات في Pandas DataFrame

بعد الانتهاء من جمع البيانات، تأتي مرحلة تنظيمها في بنية أكثر وضوحاً. وهنا تبرز فائدة مكتبة Pandas التي تسهّل عرض البيانات وتحليلها أو حفظها لاحقاً في ملف CSV أو Excel.

df = pd.DataFrame(data)
print(df)

عرض البيانات المستخرجة من المنتجات داخل DataFrame باستخدام Pandas

الكود الكامل لمشروع Web Scraping

فيما يلي النسخة الكاملة من السكربت بعد جمع جميع الخطوات السابقة في ملف واحد:

import requests
from bs4 import BeautifulSoup
import pandas as pd

baseurl = "https://www.thewhiskyexchange.com"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36'
}

productlinks = []
t = {}
data = []
c = 0

for x in range(1, 6):
    k = requests.get(
        'https://www.thewhiskyexchange.com/c/35/japanese-whisky?pg={}&psize=24&sort=pasc'.format(x)
    ).text
    soup = BeautifulSoup(k, 'html.parser')
    productlist = soup.find_all("li", {"class": "product-grid__item"})

    for product in productlist:
        link = product.find("a", {"class": "product-card"}).get('href')
        productlinks.append(baseurl + link)

for link in productlinks:
    f = requests.get(link, headers=headers).text
    hun = BeautifulSoup(f, 'html.parser')

    try:
        price = hun.find("p", {"class": "product-action__price"}).text.replace('\n', "")
    except:
        price = None

    try:
        about = hun.find("div", {"class": "product-main__description"}).text.replace('\n', "")
    except:
        about = None

    try:
        rating = hun.find("div", {"class": "review-overview"}).text.replace('\n', "")
    except:
        rating = None

    try:
        name = hun.find("h1", {"class": "product-main__name"}).text.replace('\n', "")
    except:
        name = None

    whisky = {
        "name": name,
        "price": price,
        "rating": rating,
        "about": about
    }

    data.append(whisky)
    c = c + 1
    print("completed", c)

df = pd.DataFrame(data)
print(df)

نصائح مهمة لتحسين جودة مشروع الاستخراج

1) أضف مهلة زمنية بين الطلبات

من الأفضل استخدام تأخير بسيط بين الطلبات عبر مكتبة مثل time باستخدام sleep() لتجنب إرسال عدد كبير من الطلبات بسرعة.

2) تحقق من الاستجابات

بدلاً من الاعتماد على .text مباشرة في كل مرة، يمكنك التحقق من رمز الحالة Status Code للتأكد من أن الطلب نجح.

3) خزّن النتائج في ملف

بعد بناء DataFrame يمكنك حفظ النتائج بسهولة باستخدام df.to_csv() أو df.to_excel().

4) تعامل مع تغيّر بنية الموقع

مواقع الويب تتغير باستمرار، لذلك قد تحتاج إلى تعديل أسماء الفئات class أو محددات العناصر إذا تغيرت بنية HTML.

متى تكون Beautiful Soup وPandas خياراً ممتازاً؟

هذا المزيج مناسب جداً عندما تريد:

  • استخراج بيانات منظمة من صفحات ثابتة نسبياً.
  • تحويل النتائج إلى جداول قابلة للتحليل.
  • إنجاز مهام جمع البيانات بسرعة ووضوح.
  • بناء نماذج أولية لمشاريع تحليل السوق أو متابعة الأسعار.

أما إذا كانت الصفحة تعتمد بشدة على JavaScript لتحميل المحتوى، فقد تحتاج إلى أدوات إضافية مثل Selenium أو حلول تعتمد على المتصفح.

الخلاصة التقنية

يعرض هذا المثال طريقة عملية وفعالة لبناء سكربت استخراج بيانات من متجر إلكتروني باستخدام Python وBeautiful Soup وPandas. القوة الحقيقية في هذا الأسلوب تكمن في تقسيم العمل إلى مراحل واضحة: جمع الروابط أولاً، ثم زيارة الصفحات الداخلية، ثم تنظيف النتائج وتنظيمها في جدول تحليلي. تقنياً، هذا النمط مناسب جداً لمهام تتبع الأسعار وتحليل المنتجات وبناء قواعد بيانات خفيفة، بشرط الالتزام بأخلاقيات الزحف واحترام موارد المواقع المستهدفة.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *