How to scrape ebay with python cover 1 2

يوضح لك هذا الدليل كيفية تجريف eBay باستخدام Python من البداية إلى النهاية: أداة استخراج نتائج البحث، والقوائم الفردية، ومتغيرات المنتجات، والمراجعات – بالإضافة إلى إعداد مكافحة الروبوتات والوكيل الذي يبقيه قيد التشغيل. ستحتاج إلى Python 3 وعدد قليل من المكتبات وحوالي 30 دقيقة للإصدار الأساسي. في النهاية، سيكون لديك وظائف تجريف الويب eBay القابلة لإعادة الاستخدام والتي تصدر JSON وCSV النظيفة.

أنا أندريه بيزوف، مدير تسويق جزئي محلي يعمل بالذكاء الاصطناعي وأدير خطوط أنابيب بيانات التجارة الإلكترونية. يعد eBay هدفًا عالي القيمة ولكن يتم الدفاع عنه جيدًا، لذا فإن هذه الإرشادات التفصيلية حول كيفية تجريف eBay تجمع بين الكود والأجزاء التي تتخطاها معظم الأدلة – ترقيم الصفحات، وبيانات المتغيرات المخفية، وتجنب الكتل. النسخة القصيرة من تجريف eBay بأمان: إرسال رؤوس المتصفح الحقيقية، وتدوير البروكسيات السكنية، واحترام حدود المعدل. لمعرفة عناوين IP التي يجب استخدامها، راجع موقعنا أفضل البروكسيات لتجريف eBay مرشد.


حقائق أساسية

  • يحتوي eBay على نوعين من الصفحات – نتائج البحث وقوائم المنتجات – مع هياكل HTML مختلفة، بحيث تكتب أداتي تجريف.
  • المتغيرات (الحجم واللون والتخزين) مخفية في JSON المضمنة، وليس في HTML المرئي ، يمكنك استخراجها باستخدام التعبير العادي و json.loads().
  • رؤوس المتصفح الحقيقية تأتي أولاً – دون السليم User-Agent غالبًا ما يُرجع eBay 403 أو الصفحات الفارغة حتى بالنسبة إلى requests البسيط.
  • يتم وضع علامة على عناوين IP لمركز البيانات بسرعة على eBay؛ يحافظ البروكسيات السكنية المتناوبة على الحجم ويعيدون الأسعار الصحيحة للمنطقة.
  • تختلف القوائم حسب البلد ، تعرض eBay.com وeBay.co.uk وeBay.de أسعارًا وشحنًا مختلفًا، لذا فإن الاستهداف الجغرافي مهم للحصول على بيانات eBay الدقيقة.

الخطوة 1 – قم بإعداد بيئتك

أنشئ بيئة معزولة وقم بتثبيت المكتبات التي يحتاجها إعداد تجريف الويب eBay. كل واحد لديه وظيفة – requests جلب الصفحات، beautifulsoup4 + lxml تحليل HTML و httpx يتعامل مع requests غير المتزامن بمجرد القياس.



# Create an isolated project folder and virtual environment
mkdir ebay-scraper && cd ebay-scraper
python3 -m venv env
source env/bin/activate        # Windows: env\Scripts\activate

# requests  -> send HTTP requests
# beautifulsoup4 -> parse the returned HTML
# lxml -> fast HTML parser backend for BeautifulSoup
# httpx -> async requests for scaling later
pip install requests beautifulsoup4 lxml httpx










الخطوة 2 – فهم بنية صفحة eBay

قبل كتابة التعليمات البرمجية، افهم أن eBay يحتوي على نوعين مختلفين تمامًا من الصفحات – وكيفية تجريف eBay بشكل موثوق تبدأ بمعرفة المحددات التي ينتمي إليها كل منهما. يحتاج تجريف كل نوع صفحة إلى محددات مختلفة. افتح أي صفحة، اضغط F12 (أو انقر بزر الماوس الأيمن → فحص)، وقم بالتمرير فوق العنصر للعثور على فئته. الخريطة أدناه هي ما ستشير إليه في الخطوتين 3 و4.

صفحة نتائج البحث

كل نتيجة تقع في أ li.s-item حاوية تحتوي على العنوان والسعر والرابط المتداخل بداخلها. ال _pgn تتحكم معلمة URL في ترقيم الصفحات ، ستحتاج إليها في الخطوة 3.

صفحة قائمة المنتجات

قائمة واحدة تكشف السعر في .x-price-primary، العنوان في h1 span، وتفاصيل العنصر في .ux-labels-values صفوف. لاحظ أن الوصف الطويل موجود في مكان منفصل iframe#desc_ifr – صفحة فرعية يمكنك استخلاصها بطلبها الخاص.

بيانات محدد نتائج البحث محدد صفحة القائمة
حاوية li.s-item ،
عنوان .s-item__title h1 span
سعر .s-item__price .x-price-primary
الرابط / الصورة a.s-item__link / .s-item__image img ،
تفاصيل السلعة ، .ux-labels-values
وصف ، iframe#desc_ifr

الخطوة 3 – جرّف نتائج البحث عن eBay

تأخذ أداة الكشط الأولى استعلام بحث وترجع قائمة بالعناصر التي تحتوي على العنوان والسعر وURL والصورة – وهي نقطة الدخول لمعظم مشاريع تجريف الويب eBay. من دون User-Agent يُرجع الرأس eBay 403 أو صفحة فارغة حتى بالنسبة لهذا الطلب البسيط، لذلك يتم إدخال الرؤوس من البداية. يمكنك تكييف نفس النمط لتجريف قوائم eBay من أي مصطلح بحث.



import requests
from bs4 import BeautifulSoup
from urllib.parse import quote_plus

HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                         "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
           "Accept-Language": "en-US,en;q=0.9"}

def scrape_search(query, proxies=None):
    """Return a list of eBay search results for a query."""
    url = f"https://www.ebay.com/sch/i.html?_nkw={quote_plus(query)}"
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(html.text, "lxml")
    items = []
    for card in soup.select("li.s-item"):
        title = card.select_one(".s-item__title")
        price = card.select_one(".s-item__price")
        link  = card.select_one("a.s-item__link")
        image = card.select_one(".s-item__image-wrapper img")
        if not (title and link):
            continue
        items.append({
            "title": title.get_text(strip=True),
            "price": price.get_text(strip=True) if price else None,
            "url":   link["href"],
            "image": image.get("src") if image else None,
        })
    return items

print(scrape_search("smartphone")[:3])






























التعامل مع ترقيم الصفحات

صفحة نتائج واحدة لا تكفي. هذه الحلقة تمشي _pgn المعلمة (صفحة 2، 3 … N) وتتوقف عندما تكون قائمة النتائج فارغة أو تصل إلى حد الصفحة – الجزء الذي تتركه معظم البرامج التعليمية الخاصة بأداة تجريف Python.



from urllib.parse import quote_plus

def scrape_all_pages(query, max_pages=10, proxies=None):
    """Page through results via the _pgn parameter until empty or max_pages."""
    all_items = []
    for page in range(1, max_pages + 1):
        url = (f"https://www.ebay.com/sch/i.html?_nkw={quote_plus(query)}"
               f"&_pgn={page}")
        html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
        soup = BeautifulSoup(html.text, "lxml")
        cards = soup.select("li.s-item")
        if not cards:                 # no more results -> stop
            break
        for card in cards:
            title = card.select_one(".s-item__title")
            link  = card.select_one("a.s-item__link")
            if title and link:
                all_items.append({"title": title.get_text(strip=True),
                                  "url": link["href"]})
    return all_items




















الخطوة 4 – اكشط صفحات قائمة المنتجات

عندما تقوم بحذف قوائم eBay واحدة تلو الأخرى، parse_product(url) يأخذ قائمة واحدة URL ويعيد الحقول المنظمة: العنوان والسعر والحالة والبائع والشحن وجدول تفاصيل العنصر حيث يكون كل صف عبارة عن زوج مفتاح/قيمة. هذا هو جوهر استخراج بيانات eBay على مستوى المنتج.



def parse_product(url, proxies=None):
    """Scrape a single eBay listing page."""
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(html.text, "lxml")

    def text(sel):
        el = soup.select_one(sel)
        return el.get_text(strip=True) if el else None

    # item specifics live in a label/value table
    specifics = {}
    for row in soup.select(".ux-labels-values"):
        label = row.select_one(".ux-labels-values__labels")
        value = row.select_one(".ux-labels-values__values")
        if label and value:
            specifics[label.get_text(strip=True)] = value.get_text(strip=True)

    return {
        "title":     text("h1 span"),
        "price":     text(".x-price-primary"),
        "condition": text(".x-item-condition-text .ux-textspans"),
        "seller":    text(".x-sellercard-atf__info__about-seller"),
        "shipping":  text(".ux-labels-values--shipping .ux-textspans"),
        "item_specifics": specifics,
    }

























استخراج متغيرات المنتج (بيانات MSKU)

يحتفظ eBay بخيارات متغير المنتج – اللون والحجم والتخزين – وليس في HTML المرئية ولكن داخل كائن JSON المضمن (MSKU) داخل <script> علامة. يمكنك تحديد موقع JSON وتحليله باستخدامه json.loads(). يتغير شكله ومفتاحه الدقيق بمرور الوقت، لذا تعامل مع الكود أدناه كنقطة بداية واضبطه على ما تراه في DevTools – فهو يُرجع خيارات المتغيرات (الاسم/القيمة)، وهو الجزء الذي يتخطاه معظم المنافسين.



import re, json

def parse_variants(url, proxies=None):
    """eBay keeps multi-SKU variant options (size, colour, storage) in an inline
    JSON blob rather than visible HTML. The exact key and shape change over time,
    so treat the pattern below as a starting point and adjust it to the page you
    inspect in DevTools. This returns the option name/value pairs, not full
    price-per-combination data."""
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30).text
    # find the inline state object, then load it with a balanced-brace slice
    start = html.find('"MSKU"')
    if start == -1:
        return []
    brace = html.find("{", start)
    depth, end = 0, brace
    for i in range(brace, len(html)):
        depth += (html[i] == "{") - (html[i] == "}")
        if depth == 0:
            end = i + 1
            break
    try:
        data = json.loads(html[brace:end])
    except json.JSONDecodeError:
        return []
    return [{"name": v.get("displayName"), "value": v.get("valueName")}
            for v in data.get("menuItemMap", {}).values()]


























الخطوة 5 – جرّف مراجعات المنتج eBay

عند جمع مراجعات eBay، لاحظ أنها مراجعات المنتج/الكتالوج على URL منفصلة، ​​وليس في كل صفحة قائمة – وليست كل قائمة تحتوي عليها. يمكنك الحصول على المراجعة URL من معرف المنتج/الكتالوج الموجود في القائمة، ثم سحب التقييم والنص والتاريخ والمؤلف. تعامل مع نقطة النهاية أدناه على أنها توضيحية وقم بتأكيد المسار الحالي في DevTools.



def scrape_reviews(item_id, proxies=None):
    """Reviews live on a separate URL keyed by the item ID."""
    url = f"https://www.ebay.com/urw/{item_id}/product-reviews"
    html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    soup = BeautifulSoup(html.text, "lxml")
    reviews = []
    for r in soup.select(".ebay-review-section"):
        rating = r.select_one(".star-rating")
        body   = r.select_one(".review-item-content")
        date   = r.select_one(".review-item-date")
        author = r.select_one(".review-item-author")
        reviews.append({
            "rating": rating.get("aria-label") if rating else None,
            "text":   body.get_text(strip=True) if body else None,
            "date":   date.get_text(strip=True) if date else None,
            "author": author.get_text(strip=True) if author else None,
        })
    return reviews


















الخطوة 6 – تصدير البيانات إلى JSON وCSV

احفظ نتائجك في كلا التنسيقين جنبًا إلى جنب: يحتفظ JSON بالبنية المتداخلة (مفيدة للمتغيرات والتفاصيل)، CSV مسطح ويفتح مباشرة في Excel أو Google Sheets.



import json, csv

results = scrape_search("smartphone")

# Option A - JSON (keeps nested structure)
with open("ebay.json", "w", encoding="utf-8") as f:
    json.dump(results, f, indent=2, ensure_ascii=False)

# Option B - CSV (flat, opens in Excel/Sheets)
if results:
    with open("ebay.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=results[0].keys())
        writer.writeheader()
        writer.writerows(results)














الخطوة 7 – تجاوز إجراءات مكافحة الروبوتات الخاصة بـ eBay

تدافع eBay عن القوائم من خلال مكدس متعدد الطبقات: تسجيل سمعة IP، وتحديد المعدل (HTTP 429)، والكتل الناعمة (استجابة 200 بنتيجة فارغة)، واختبارات CAPTCHA. لن تتمكن من التغلب على كل ذلك بخدعة واحدة، لكن الرؤوس وعناوين IP الصحيحة تتعامل مع الحالات الشائعة لتجريف الويب eBay على نطاق معقول.

قم بتعيين الرؤوس المناسبة

أرسل مجموعة رؤوس كاملة وواقعية – وليس مجرد User-Agent. كل رأس يقلل من خطر الحظر الخاص بك: مفقود Accept-Language أو Referer من المؤشرات الشائعة على الروبوتات. بالنسبة للمهام الأكبر حجمًا، قم بتدوير User-Agent من القائمة.



HEADERS = {
    # identify as a real desktop browser - eBay returns 403/empty without this
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",      # match the locale you target
    "Accept-Encoding": "gzip, deflate, br",   # accept compressed responses
    "Referer": "https://www.ebay.com/",       # look like in-site navigation
    "Connection": "keep-alive",
}

# rotate the User-Agent across a list for larger jobs
import random
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/17.0 Safari/605.1.15",
]
HEADERS["User-Agent"] = random.choice(USER_AGENTS)

















استخدم البروكسيات السكنية الدوارين

الرؤوس ليست كافية من حيث الحجم ، eBay يسجل سمعة IP، و بروكسيات مركز البيانات يتم وضع علامة عليها بشكل أسرع بكثير من تلك السكنية. يستخدم الدورية عناوين IP السكنية لتجميع عمليات البحث بكميات كبيرة (IP جديد لكل طلب) و لزجة جلسات الإدراج أو تدفقات المزاد حيث تكون الجلسة المستقرة مهمة. DataImpulse بروكسيات سكنية هي $1/GB، والدفع أولاً بأول، وتوصيلها مباشرة بـ requests يتصل.



# Route requests through DataImpulse rotating residential proxies
proxies = {
    "http":  "http://LOGIN:[email protected]:823",
    "https": "http://LOGIN:[email protected]:823",
}
html = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)






الاستهداف الجغرافي – استخراج بيانات eBay الخاصة بالمنطقة

تختلف قوائم eBay حسب البلد: تعرض eBay.com وeBay.co.uk وeBay.de أسعارًا وتوافرًا وشحنًا مختلفًا لنفس المنتج. لرؤية البيانات التي يراها المشتري في بلد معين، قم بالتوجيه عبر بروكسي موجود هناك. يحتوي DataImpulse على عناوين IP سكنية عبر 195 دولة، بما في ذلك الاستهداف على مستوى الولاية الأمريكية، لذا فإن استخراج بيانات eBay الخاص بك يعكس السوق المناسب. ويُستخدم النهج نفسه في مقارنة الأسعار عبر المناطق.


الخطوة 8 – قم بتوسيع أداة تجريف eBay الخاصة بك

ثلاثة مستويات تحول البرنامج النصي الأساسي إلى طريقة جاهزة للإنتاج لتجريف eBay باستخدام Python على نطاق واسع، من أجل زيادة التعقيد: تأخير عشوائي بين requests للبقاء ضمن حدود المعدل، وإعادة محاولة المنطق مع التراجع الأسي لاستيعاب استجابات 429/403، وجمع غير متزامن مع httpx + asyncio للحجم الموازي.



import time, random, asyncio, httpx

# 1) Basic pacing - a random delay between requests
def polite_get(url, **kw):
    time.sleep(random.uniform(1, 3))
    return requests.get(url, headers=HEADERS, timeout=30, **kw)

# 2) Retry with exponential backoff on 429/403
def get_with_retry(url, retries=4, **kw):
    for attempt in range(retries):
        r = requests.get(url, headers=HEADERS, timeout=30, **kw)
        if r.status_code not in (429, 403):
            return r
        time.sleep(2 ** attempt + random.random())   # 1s, 2s, 4s, 8s ...
    return r

# 3) Async collection for high volume (httpx >=0.28 uses proxy=, not proxies=)
async def scrape_many(urls, proxy=None):
    async with httpx.AsyncClient(headers=HEADERS, proxy=proxy, timeout=30) as client:
        tasks = [client.get(u) for u in urls]
        return await asyncio.gather(*tasks)





















الأسئلة المتداولة

هل تجريف eBay؟

ذلك يعتمد. يمكن أن يكون نسخ البيانات المتاحة للعامة أمرًا قانونيًا في بعض السياقات، لكن اتفاقية المستخدم الخاصة بـ eBay تقيد الوصول الآلي – الروبوتات والأدوات الكاشطة وأدوات التنقيب عن البيانات – دون إذن مسبق، لذا فإن النسخ يمكن أن ينتهك شروطها وينطوي على مخاطر قانونية. استخدام البروكسيات في حد ذاته أمر قانوني. احترم حدود المعدلات، ولا تتهرب من تسجيلات الدخول، وتجنب البيانات الشخصية، واحصل على المشورة القانونية للاستخدام التجاري. هذه معلومات عامة، وليست نصيحة قانونية – راجع موقعنا دليل حول ما إذا كان تجريف الويب قانونيًا أم لا.

هل أحتاج إلى بروكسيات لتجريف eBay؟

بالنسبة لحفنة من requests، لا. بالنسبة لأي حجم حقيقي، نعم – يسجل eBay سمعة IP وحدود المعدل بشدة، لذلك يتم حظر IP واحد بسرعة. يعمل البروكسيات السكنية المتناوبة على نشر requests عبر العديد من عناوين IP ويتيحون لك استهداف بلدان معينة للحصول على الأسعار الصحيحة للمنطقة.

كيف أجرّف متغيرات المنتج eBay؟

لا توجد المتغيرات مثل الحجم واللون في HTML المرئي – يقوم eBay بتخزينها في كائن JSON (MSKU) المضمن داخل علامة البرنامج النصي. حدد موقع هذا الكائن باستخدام re.search() وتحليلها بها json.loads()، كما هو موضح في الخطوة 4.

لماذا تقوم أداة تجريف eBay الخاصة بي بإرجاع نتائج فارغة؟

غالبًا ما تكون رؤوسًا. بدون متصفح حقيقي User-Agent (و بشكل مثالي Accept-Language و Referer)، يقوم eBay بشكل متكرر بإرجاع 403 أو 200 بنص فارغ. أضف مجموعة الرؤوس الكاملة من الخطوة 7؛ إذا استمرت المشكلة، فمن المحتمل أن تكون ذات معدل محدود أو تحمل علامة IP، لذا أبطئ وقم بالتوجيه عبر بروكسي سكني.

كيف يمكنني التعامل مع ترقيم الصفحات eBay في Python؟

زيادة ال _pgn المعلمة URL (&_pgn=2, 3، …) في حلقة وتوقف عند حاوية النتيجة (li.s-item) فارغًا أو وصلت إلى الحد الأقصى للصفحة، كما هو الحال في وظيفة ترقيم الصفحات في الخطوة 3.


خاتمة

هذه هي كيفية تجريف eBay باستخدام Python من النهاية إلى النهاية: نتائج البحث وأدوات تجريف القوائم، والصفحات، واستخراج المتغير المخفي، والمراجعات، وتصدير JSON/CSV، والترويسات بالإضافة إلى البروكسيات السكنية الدوارين الذين يحافظون على تشغيل إعداد eBay Python. ابدأ صغيرًا باستخدام أداة تجريف البحث، ثم قم بوضع طبقات من الصفحات، ورؤوس مكافحة الروبوتات، وقم بالقياس مع نمو حجم عملك. للحصول على عناوين IP الصحيحة، راجع أفضل البروكسيات لتجريف eBay.

آخر تحديث: يونيو 24، 2026.



Share article: