سحب البيانات من المواقع ببايثون: دليل المبتدئين لاستخراج البيانات

سحب البيانات من المواقع (Web Scraping) من أقوى المهارات في صندوق أدوات أي مبرمج بايثون. تتيح لك استخراج البيانات من أي موقع تلقائياً — أسعار المنتجات، عروض الوظائف، المقالات الإخبارية، أو أي معلومة متاحة للعموم. بدلاً من نسخ البيانات يدوياً، سكريبت بايثون ينجزها في ثوانٍ.

هذا الدرس يعلمك بناء سكريبت سحب بيانات من الصفر باستخدام بايثون وBeautifulSoup ومكتبة requests. بنهايته ستملك سكريبتات تستخرج بيانات حقيقية وتحفظها في ملفات CSV. هذه مهارة أساسية في رحلة أتمتة بايثون.

ما هو سحب البيانات من المواقع؟

سحب البيانات هو عملية آلية لاستخراج المعلومات من المواقع الإلكترونية. عند زيارتك لموقع، متصفحك يحمّل كود HTML ويعرضه بصرياً. سكريبت سحب البيانات يفعل نفس الشيء برمجياً — يحمّل الـ HTML ثم يحلله لاستخراج معلومات محددة.

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

إعداد بيئة سحب البيانات

تحتاج مكتبتين أساسيتين:

pip install requests beautifulsoup4

مكتبة requests تتعامل مع تحميل صفحات الويب، وBeautifulSoup4 تحلل HTML لاستخراج البيانات. للمواقع التي تحتاج JavaScript:

pip install selenium

أول سكريبت سحب بيانات: خطوة بخطوة

الخطوة 1: تحميل صفحة الويب

import requests
from bs4 import BeautifulSoup

url = "https://news.ycombinator.com/"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    print("تم تحميل الصفحة بنجاح!")
    html_content = response.text
else:
    print(f"فشل التحميل. الحالة: {response.status_code}")

الخطوة 2: تحليل HTML واستخراج البيانات

soup = BeautifulSoup(html_content, "html.parser")

titles = soup.find_all("span", class_="titleline")

for i, title in enumerate(titles[:10], 1):
    link = title.find("a")
    if link:
        print(f"{i}. {link.text}")
        print(f"   الرابط: {link.get('href')}")

الخطوة 3: حفظ البيانات في ملف CSV

import csv

def scrape_and_save(url, output_file):
    headers = {"User-Agent": "Mozilla/5.0"}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.text, "html.parser")
    titles = soup.find_all("span", class_="titleline")
    
    with open(output_file, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["العنوان", "الرابط"])
        for title in titles:
            link = title.find("a")
            if link:
                writer.writerow([link.text, link.get("href", "")])
    
    print(f"تم حفظ {len(titles)} مقالة في {output_file}")

scrape_and_save("https://news.ycombinator.com/", "articles.csv")

فهم محددات BeautifulSoup

# البحث عن أول عنصر
first_h1 = soup.find("h1")

# البحث عن كل العناصر
all_paragraphs = soup.find_all("p")

# البحث بالفئة CSS
items = soup.find_all("div", class_="product-card")

# البحث بالمعرف ID
header = soup.find("div", id="main-header")

# استخدام CSS selector
prices = soup.select("div.product span.price")

# استخراج النص
text = element.get_text(strip=True)

# استخراج قيمة خاصية
href = link.get("href")

التعامل مع الصفحات المتعددة (Pagination)

def scrape_all_pages(base_url, max_pages=10):
    all_data = []
    for page in range(1, max_pages + 1):
        url = f"{base_url}?page={page}"
        print(f"سحب الصفحة {page}...")
        response = requests.get(url, headers=headers)
        soup = BeautifulSoup(response.text, "html.parser")
        items = soup.find_all("div", class_="item")
        if not items:
            print(f"لا عناصر في الصفحة {page}. توقف.")
            break
        for item in items:
            all_data.append(extract_item_data(item))
        import time
        time.sleep(2)  # احترم الموقع وانتظر بين الطلبات
    return all_data

استخدام Selenium للمواقع الديناميكية

بعض المواقع الحديثة تحمّل المحتوى عبر JavaScript. مكتبة requests تحمّل فقط HTML الأولي. Selenium يحل هذه المشكلة بالتحكم بمتصفح حقيقي:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
try:
    driver.get("https://example.com/dynamic-page")
    wait = WebDriverWait(driver, 10)
    elements = wait.until(
        EC.presence_of_all_elements_located(
            (By.CLASS_NAME, "product-card")
        )
    )
    for element in elements:
        name = element.find_element(By.CLASS_NAME, "name").text
        price = element.find_element(By.CLASS_NAME, "price").text
        print(f"{name}: {price}")
finally:
    driver.quit()

أفضل ممارسات سحب البيانات

أضف تأخيراً بين الطلبات. استخدم time.sleep() بين الطلبات لتجنب الضغط على الخادم. تأخير 1-3 ثوانٍ مناسب عادةً.

استخدم Sessions. كائن requests.Session() يعيد استخدام اتصالات TCP ويتعامل مع ملفات تعريف الارتباط تلقائياً.

تعامل مع الأخطاء. المواقع تتغير هيكلتها بشكل متكرر. استخدم دائماً try-except وتحقق من وجود العناصر.

احترم ملف robots.txt. تحقق من ملف robots.txt للموقع لفهم الصفحات المسموح بسحبها.

دمج سحب البيانات مع أتمتة أخرى

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

الخلاصة

سحب البيانات من المواقع ببايثون يفتح لك عالماً من البيانات. ابدأ بمكتبتي requests وBeautifulSoup للمواقع العادية، وانتقل إلى Selenium للمواقع الديناميكية. احترم دائماً شروط استخدام المواقع واسحب البيانات بمسؤولية.

لمواصلة التعلم، ارجع إلى الدليل الشامل لأتمتة بايثون.

تعليقات

المشاركات الشائعة من هذه المدونة

تعلم Git و GitHub للمبتدئين: دليل شامل بالعربي خطوة بخطوة (2026)

تعلم بايثون من الصفر 2026: دليل شامل للمبتدئين

دليل الصحة النفسية 2026: كيف تتعامل مع القلق والاكتئاب وتعيش حياة متوازنة