كيفية استخراج بيانات Zillow باستخدام Python (من دون التعرض للحظر)

آخر تحديث في July 8, 2026
كيفية استخراج بيانات Zillow باستخدام Python (من دون التعرض للحظر)

تضم Zillow أكثر من 160 مليون سجل عقاري في الولايات المتحدة، واستخراج هذه البيانات على نطاق واسع يُعد من أكثر المهام المطلوبة — والأكثر صداعًا — في شغل بيانات العقارات. إذا سبق لك أن حاولت استخراج بيانات Zillow وانتهى بك الأمر على صفحة CAPTCHA بدل بيانات العقار، فأنت لست وحدك.

قضيت وقتًا طويلًا في البحث وتجربة طرق مختلفة لاستخراج بيانات Zillow — سواء باستخدام Python أو عبر أدوات no-code طورناها في Thunderbit. هذا الدليل يجمع المسارين معًا. سواء كنت تريد شرحًا كاملًا باستخدام Python مع استراتيجيات لتجاوز الحظر، أو كنت تحتاج فقط إلى 200 إعلان في جدول بيانات قبل الغداء، فستجد هنا ما يفيدك. سنشرح لماذا تهم بيانات Zillow، وكيف يبدو هيكل الموقع من الداخل، ودروسًا عملية خطوة بخطوة باستخدام Python، والأسباب الدقيقة لتعطل أدوات الاستخراج، وكيفية أتمتة عمليات الاستخراج المتكررة لمتابعة الأسعار.

لماذا أصلاً نحتاج إلى استخراج بيانات Zillow؟

Zillow هو أكبر مستودع لبيانات العقارات السكنية في الولايات المتحدة. يستقبل 210 ملايين زيارة شهرية ويعرض نحو 750,000+ إعلانًا نشطًا للبيع، بالإضافة إلى 1.9 مليون إعلان إيجار. تستحوذ المنصة على أكثر من 50% من إجمالي حركة المرور الخاصة ببوابات العقارات في الولايات المتحدة — أي أكثر من ضعف أقرب منافس.

zillow_stats_998c14e590.png

قبل الدخول في كود Python، من المهم أن تعرف أن الاستخراج عبر Python ليس الخيار الوحيد، واختيار الطريقة غير المناسبة قد يضيع ساعات من وقتك. أدوات Python مثل httpx وBeautifulSoup تناسب من لديهم مستوى متوسط، لكنها تتطلب التعامل اليدوي مع الـ headers والـ proxies، وتعمل بسرعة متوسطة (1–3 ثوانٍ لكل صفحة)، وتحتاج صيانة متكررة، رغم أنها مجانية؛ أما Selenium أو Playwright فهما أفضل في التعامل مع الحماية ضد الروبوتات عبر عرض JavaScript، لكنهما أبطأ (5–15 ثانية لكل صفحة) وما زالا يحتاجان إلى صيانة عالية؛ وخدمات scraping API مثل ScraperAPI أو ScrapFly أسرع وتأتي بدعم مدمج لمقاومة الحظر مع جهد صيانة متوسط، لكنها تكلف 30–599 دولارًا شهريًا؛ بينما الواجهة الرسمية لـ Zillow عبر Bridge Interactive سريعة ومنخفضة الصيانة لكنها محدودة وتكلف نحو 500 دولار شهريًا؛ وأدوات no-code مثل Thunderbit سهلة للمبتدئين وسريعة ولا تحتاج صيانة بفضل التكيّف بالذكاء الاصطناعي، وغالبًا ما تقدم نموذجًا مجانيًا مع مزايا مدفوعة.

أما من ناحية توفير الوقت، فالفارق كبير جدًا. البحث اليدوي عبر أكثر من 50 رمزًا بريديًا قد يستهلك 15–20 ساعة أسبوعيًا. أما الاستخراج الآلي فينجز المهمة نفسها خلال دقائق — أي تقليل الوقت المستغرق بنسبة 99.7%.

كل طرق استخراج بيانات Zillow: Python مقابل API مقابل no-code (مقارنة)

قبل أن نبدأ بكود Python، اعلم أن "استخراج Zillow باستخدام Python" ليس الخيار الوحيد. اختيار الطريقة الخاطئة يضيّع ساعات. إليك مقارنة مباشرة لتختار الأنسب لك:

الطريقةمستوى المهارةالتعامل مع الحظرالسرعةالصيانةالتكلفة
Python + httpx/BeautifulSoupمتوسطيدوي (headers, proxies)متوسطة (1–3 ث/صفحة)عالية (قد تتعطل المحددات)مجانية
Python + Selenium/Playwrightمتوسطأفضل (يعرض JS)بطيئة (5–15 ث/صفحة)عاليةمجانية
scraping API (ScraperAPI, ScrapFly)متوسطمدمجسريعةمتوسطة30–599 دولار/شهر
Zillow Official API (Bridge Interactive)مبتدئ–متوسطغير منطبقسريعةمنخفضةحوالي 500 دولار/شهر، وصول محدود
أداة no-code (Thunderbit)مبتدئمدمج (الذكاء الاصطناعي يتكيّف)سريعةمعدومة (الذكاء الاصطناعي يقرأ الصفحة من جديد)Freemium

إذا كنت تحتاج البيانات الآن من دون كتابة أي كود، فابدأ بـ Thunderbit. أما إذا كنت تريد فهم البنية التقنية أو تحتاج تخصيصًا كاملًا، فتابع قراءة الشرح العملي باستخدام Python.

الطريقة الأسرع خلال دقيقتين: استخراج Zillow باستخدام Thunderbit (من دون كود)

قبل التعمق في Python، هذه هي الطريقة المناسبة لمن يريد بيانات Zillow بسرعة — من دون إعداد Python، ومن دون ضبط proxies، ومن دون صيانة المحددات. بنينا هذا العمل في Thunderbit خصيصًا للحصول على بيانات عقارية منظمة من دون عبء هندسي.

مستوى الصعوبة: مبتدئ
الوقت المطلوب: حوالي دقيقتين
ما تحتاجه: متصفح Chrome، وThunderbit Chrome Extension (تعمل الخطة المجانية)

الخطوة 1: ثبّت Thunderbit وافتح Zillow

ثبّت إضافة Thunderbit من متجر Chrome Web Store. ثم انتقل إلى صفحة نتائج البحث في Zillow — على سبيل المثال، ابحث عن منازل في Houston, TX.

الخطوة 2: انقر على "AI Suggest Fields"

افتح الشريط الجانبي لـ Thunderbit ثم انقر على "AI Suggest Fields". سيقرأ الذكاء الاصطناعي الصفحة ويقترح الأعمدة تلقائيًا: السعر، العنوان، عدد غرف النوم، عدد الحمامات، المساحة، Zestimate، رابط الإعلان، والمزيد. في اختباري، غالبًا ما يكتشف أكثر من 20 حقلًا من دون أي إعداد يدوي.

الخطوة 3: انقر على "Scrape"

اضغط زر Scrape. ستظهر البيانات في جدول منظم داخل الإضافة. يتعامل Thunderbit تلقائيًا مع تقسيم الصفحات في Zillow — سواء كان ذلك عبر النقر أو التمرير اللانهائي.

الخطوة 4: أغنِ البيانات عبر Scrape Subpages

هل تريد بيانات من صفحة التفاصيل مثل سجل الضرائب، تقييم المدارس، أو سجل الأسعار؟ استخدم "Scrape Subpages" لإثراء الجدول. سيتنقل Thunderbit إلى كل رابط إعلان ويستخرج الحقول الإضافية — من دون أي كود إضافي.

الخطوة 5: التصدير

صدّر البيانات إلى Google Sheets أو Excel أو Airtable أو Notion. التصدير مجاني.

لماذا يعمل Thunderbit جيدًا مع Zillow

الميزة الحقيقية هنا هي المرونة. يقرأ Thunderbit بنية الصفحة من جديد في كل مرة تقوم فيها بالاستخراج. وعندما يغيّر Zillow تصميمه — وهو أمر يحدث كثيرًا — لا تعتمد الأداة على CSS selectors هشة تحتاج إلى إصلاح. الذكاء الاصطناعي يتكيّف تلقائيًا. وهذا يحل فعلًا مشكلة "الهشاشة المتأصلة" في أدوات الاستخراج البرمجية التي تربك الكثير من المستخدمين.

ما البيانات التي يمكنك استخراجها من Zillow؟ (أكثر من 20 حقلًا)

معظم الأدلة تكتفي بالسعر والعنوان ثم تتوقف. لكن إعلانات Zillow تحتوي فعليًا على بيانات أكثر بكثير مما يتوقعه الناس — إليك جدولًا مرجعيًا:

الحقلمكان العثور عليهصعوبة الاستخراج
سعر الإدراجنتائج البحث + صفحة التفاصيلسهل
العنوان / الرمز البريدينتائج البحث + صفحة التفاصيلسهل
Zestimateنتائج البحث + صفحة التفاصيلسهل
سجل الأسعار (كل حدث)صفحة التفاصيلصعب (JSON متداخل)
سجل الضرائبصفحة التفاصيلصعب (JSON متداخل)
عدد غرف النوم / الحمامات / المساحةنتائج البحث + صفحة التفاصيلسهل
سنة البناءصفحة التفاصيلسهل
رسوم HOAصفحة التفاصيلمتوسط
Walk Score / Transit Scoreصفحة التفاصيل (iframe)صعب (يتطلب عرض JavaScript)
تقييم المدارسصفحة التفاصيلمتوسط
مساحة الأرضصفحة التفاصيلسهل
عدد الأيام على Zillowنتائج البحثسهل
وكيل الإعلان / شركة الوساطةنتائج البحث + صفحة التفاصيلمتوسط
رقم MLSصفحة التفاصيلسهل
نوع العقارنتائج البحث + صفحة التفاصيلسهل
خط العرض / خط الطولJSON في __NEXT_DATA__متوسط
نص الوصفصفحة التفاصيلسهل
روابط الصورنتائج البحث + صفحة التفاصيلمتوسط
Rent Zestimateصفحة التفاصيلمتوسط
المبيعات المماثلة القريبةصفحة التفاصيلصعب

الحقول "الصعبة" — مثل سجل الأسعار، وسجل الضرائب، والمبيعات المماثلة — توجد داخل JSON متداخل في صفحات التفاصيل. يوضح القسم التالي من Python كيفية استخراجها بدقة. وإذا كنت تفضل تجنب الكود، فإن AI Suggest Fields في Thunderbit يكتشف معظم هذه الأعمدة تلقائيًا، بينما يقوم Scrape Subpages بسحب حقول صفحات التفاصيل بشكل آلي.

إعداد بيئة Python لاستخراج Zillow

مستوى الصعوبة: متوسط
الوقت المطلوب: حوالي 5 دقائق للإعداد، و30 دقيقة للشرح الكامل
ما تحتاجه: Python 3.8+، متصفح Chrome (لفحص الصفحات)، ومحرر نصوص أو IDE

ثبّت المكتبات المطلوبة:

pip install httpx beautifulsoup4 pandas lxml

وهذه وظيفة كل مكتبة:

  • httpx — عميل HTTP أسرع من requests ويدعم async
  • beautifulsoup4 + lxml — لتحليل HTML
  • pandas — لتصدير البيانات إلى CSV/Excel
  • اختياريًا: selenium أو playwright إذا كنت تحتاج إلى عرض صفحات تعتمد كثيرًا على JavaScript

فهم بنية صفحة Zillow قبل البدء بالاستخراج

zillow_structure_046e848770.png

هذه أهم نقطة يجب فهمها قبل كتابة أي كود. Zillow هو تطبيق Next.js — وهذا مؤكد من خلال منشورات هندسية لموظفين في Zillow. هذا يعني أن معظم البيانات التي تريدها ليست داخل عناصر HTML الظاهرة، بل مضمنة داخل كتلة JSON في <script id="__NEXT_DATA__">.

افتح أي صفحة عقار في Zillow، ثم اضغط F12، واذهب إلى Elements، وابحث عن __NEXT_DATA__. ستجد كائن JSON ضخمًا يحتوي على كل بيانات الإعلان — الأسعار، الإحداثيات، تفاصيل العقار، سجل الأسعار، السجلات الضريبية، تقييم المدارس، والمزيد.

لماذا هذا مهم؟ لأن أسماء CSS classes في Zillow مُولّدة بشكل تجزئي (hashed) عبر styled-components وتتغير مع كل عملية نشر. فمثلًا class مثل StyledPropertyCardHomeDetailsList-c11n-8-109-3__sc-1j0som5-0 قد يحمل hash مختلفًا تمامًا الأسبوع القادم. أي scraper يعتمد على CSS selectors سيتعطل باستمرار.

أما أسلوب استخراج JSON من __NEXT_DATA__ فهو أكثر ثباتًا لأنه لا يعتمد أصلًا على بنية HTML.

مسارات JSON الأساسية لنتائج البحث:

المسارالمحتوى
props.pageProps.searchPageState.cat1.searchResults.listResultsمصفوفة نتائج البحث
props.pageProps.searchPageState.cat1.searchResults.mapResultsنتائج عرض الخريطة
props.pageProps.searchPageState.cat1.searchList.totalPagesإجمالي الصفحات المتاحة

أما في صفحات التفاصيل، فبعضها يستخدم __NEXT_DATA__ وبعضها يعتمد على وسم script بديل اسمه hdpApolloPreloadedData. الكود التالي يتعامل مع الحالتين.

خطوة بخطوة: كيفية استخراج Zillow باستخدام Python

الخطوة 1: إعداد HTTP Headers لتجنب الحظر الفوري

إرسال httpx.get() عادي إلى Zillow سيعيد صفحة CAPTCHA بدل بيانات الإعلانات. تستخدم Zillow نظام PerimeterX (HUMAN Security) إلى جانب Cloudflare — وكلاهما مُصنَّف 8/10 من حيث الصعوبة في اختبارات scraping. يفحص النظام بصمة TLS، والـ headers، وسمعة الـ IP.

إليك الحد الأدنى من الـ headers التي تعمل حتى عام 2025:

import httpx

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
                   "(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
              "image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Sec-Ch-Ua": '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
    "Sec-Ch-Ua-Platform": '"Windows"',
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
}

تُعد ترويسات Sec-Ch-Ua بالغة الأهمية. كثير من الشروحات تتجاهلها — وهذا بالضبط سبب فشل الأكواد في مواجهة PerimeterX.

الخطوة 2: استخراج نتائج البحث من Zillow

روابط بحث Zillow تتبع نمطًا متوقعًا. بالنسبة إلى Houston, TX:

  • الصفحة 1: https://www.zillow.com/houston-tx/
  • الصفحة 2: https://www.zillow.com/houston-tx/2_p/
  • الصفحة 3: https://www.zillow.com/houston-tx/3_p/

كل صفحة تحتوي تقريبًا على 41 إعلانًا. Zillow يحدد النتائج بحد أقصى 20 صفحة (~820 إعلانًا). وللحصول على مجموعات بيانات أكبر، ستحتاج إلى تقسيم البحث جغرافيًا (سنشرح ذلك لاحقًا).

إليك الكود لاستخراج نتائج البحث عبر سحب البيانات من JSON الخاص بـ __NEXT_DATA__:

from bs4 import BeautifulSoup
import json
import time
import random

def scrape_zillow_search(url):
    """استخراج بيانات الإعلانات من صفحة نتائج بحث Zillow."""
    response = httpx.get(url, headers=headers, timeout=15)

    if response.status_code != 200:
        print(f"Got status {response.status_code} for {url}")
        return []

    soup = BeautifulSoup(response.text, "lxml")
    script_tag = soup.find("script", {"id": "__NEXT_DATA__"})

    if not script_tag:
        print("No __NEXT_DATA__ found — likely blocked by CAPTCHA")
        return []

    next_data = json.loads(script_tag.string)

    try:
        results = (
            next_data["props"]["pageProps"]["searchPageState"]
            ["cat1"]["searchResults"]["listResults"]
        )
    except KeyError:
        print("Unexpected JSON structure — Zillow may have changed its format")
        return []

    listings = []
    for item in results:
        listing = {
            "zpid": item.get("zpid"),
            "address": item.get("addressStreet"),
            "city": item.get("addressCity"),
            "state": item.get("addressState"),
            "zipcode": item.get("addressZipcode"),
            "price": item.get("unformattedPrice") or item.get("price"),
            "beds": item.get("beds"),
            "baths": item.get("baths"),
            "sqft": item.get("area"),
            "zestimate": item.get("zestimate"),
            "days_on_zillow": item.get("daysOnZillow"),
            "listing_url": item.get("detailUrl"),
            "img_src": item.get("imgSrc"),
            "property_type": item.get("hdpData", {}).get("homeInfo", {}).get("homeType"),
            "latitude": item.get("latLong", {}).get("latitude"),
            "longitude": item.get("latLong", {}).get("longitude"),
        }
        listings.append(listing)

    return listings

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

all_listings = []
base_url = "https://www.zillow.com/houston-tx/"

for page in range(1, 6):  # أول 5 صفحات
    url = base_url if page == 1 else f"{base_url}{page}_p/"
    print(f"Scraping page {page}...")

    page_listings = scrape_zillow_search(url)
    all_listings.extend(page_listings)

    # تأخير عشوائي بين 3 و7 ثوانٍ
    delay = random.uniform(3, 7)
    time.sleep(delay)

print(f"Total listings scraped: {len(all_listings)}")

يُفترض أن ترى بيانات منظّمة تتراكم داخل all_listings. إذا حصلت على نتائج فارغة، فراجع قسم "لماذا تتعطل أدوات الاستخراج" أدناه.

الخطوة 3: استخراج صفحات تفاصيل عقارات Zillow

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

تستخدم صفحات التفاصيل في Zillow تنسيقين محتملين للبيانات. إليك كودًا يتعامل مع الاثنين:

def scrape_zillow_detail(url):
    """استخراج بيانات تفصيلية لعقار من صفحة Zillow."""
    response = httpx.get(url, headers=headers, timeout=15)

    if response.status_code != 200:
        return None

    soup = BeautifulSoup(response.text, "lxml")

    # جرّب __NEXT_DATA__ أولًا (الأكثر شيوعًا)
    script_tag = soup.find("script", {"id": "__NEXT_DATA__"})
    if script_tag:
        next_data = json.loads(script_tag.string)
        try:
            cache_str = next_data["props"]["pageProps"]["componentProps"]["gdpClientCache"]
            cache = json.loads(cache_str)
            first_key = next(iter(cache))
            prop = cache[first_key]["property"]
            return extract_property_fields(prop)
        except (KeyError, StopIteration):
            pass

    # بديل: hdpApolloPreloadedData
    apollo_tag = soup.find("script", {"id": "hdpApolloPreloadedData"})
    if apollo_tag:
        raw = json.loads(apollo_tag.string)
        api_cache = json.loads(raw["apiCache"])
        for key, value in api_cache.items():
            if "ForSale" in key or "property" in str(value)[:100]:
                prop = value.get("property", value)
                return extract_property_fields(prop)

    return None


def extract_property_fields(prop):
    """استخراج الحقول المنظمة من كائن JSON خاص بعقار Zillow."""
    return {
        "zpid": prop.get("zpid"),
        "zestimate": prop.get("zestimate"),
        "rent_zestimate": prop.get("rentZestimate"),
        "description": prop.get("description"),
        "year_built": prop.get("yearBuilt"),
        "lot_size": prop.get("lotSize"),
        "hoa_fee": prop.get("monthlyHoaFee"),
        "mls_id": prop.get("mlsid"),
        "broker_name": prop.get("brokerName") or prop.get("attributionInfo", {}).get("brokerName"),
        "price_history": [
            {
                "date": event.get("date"),
                "event": event.get("event"),
                "price": event.get("price"),
            }
            for event in prop.get("priceHistory", [])
        ],
        "tax_history": [
            {
                "year": record.get("time"),
                "tax_paid": record.get("taxPaid"),
                "value": record.get("value"),
            }
            for record in prop.get("taxHistory", [])
        ],
        "schools": [
            {
                "name": school.get("name"),
                "rating": school.get("rating"),
                "distance": school.get("distance"),
            }
            for school in prop.get("schools", [])
        ],
    }

مرّر على روابط الإعلانات مع فواصل زمنية:

detail_data = []
for listing in all_listings[:10]:  # ابدأ بـ 10 للاختبار
    detail_url = listing.get("listing_url")
    if not detail_url:
        continue

    if not detail_url.startswith("http"):
        detail_url = f"https://www.zillow.com{detail_url}"

    print(f"Scraping detail: {detail_url}")
    detail = scrape_zillow_detail(detail_url)

    if detail:
        detail_data.append({**listing, **detail})

    time.sleep(random.uniform(3, 8))

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

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

في المناطق التي تحتوي على أكثر من 820 إعلانًا (حد الـ 20 صفحة)، ستحتاج إلى تقسيم المنطقة جغرافيًا. تقبل واجهة Zillow الداخلية المعامل mapBounds. الاستراتيجية هنا: قسم الخريطة إلى أرباع واستخراج كل جزء بشكل منفصل.

def split_bounds(bounds):
    """تقسيم حدود الخريطة إلى 4 أرباع."""
    mid_lat = (bounds["north"] + bounds["south"]) / 2
    mid_lng = (bounds["east"] + bounds["west"]) / 2

    return [
        {"north": bounds["north"], "south": mid_lat, "east": bounds["east"], "west": mid_lng},
        {"north": bounds["north"], "south": mid_lat, "east": mid_lng, "west": bounds["west"]},
        {"north": mid_lat, "south": bounds["south"], "east": bounds["east"], "west": mid_lng},
        {"north": mid_lat, "south": bounds["south"], "east": mid_lng, "west": bounds["west"]},
    ]

في معظم الاستخدامات — مثل متابعة 50–200 إعلان في منطقة محددة — يكون ترقيم الصفحات القياسي في الرابط كافيًا. أما أسلوب تقسيم الأرباع فهو مناسب للاستخراج على مستوى المدينة أو الولاية.

الخطوة 5: تصدير بيانات Zillow التي استخرجتها

احفظ كل شيء إلى CSV باستخدام pandas:

import pandas as pd

df = pd.DataFrame(detail_data)
df.to_csv("zillow_houston_listings.csv", index=False)
print(f"Exported {len(df)} listings to zillow_houston_listings.csv")

وللتصدير إلى JSON:

with open("zillow_houston_listings.json", "w") as f:
    json.dump(detail_data, f, indent=2)

إذا أردت تجاوز خطوة التصدير بالكامل، فإن Thunderbit يصدّر إلى Google Sheets وAirtable وNotion مجانًا — وهذا مفيد إذا كنت تريد البيانات بصيغة تعاونية فورًا.

لماذا تتعطل أدوات استخراج Zillow (وكيف تبني أدوات أكثر صمودًا)

هذا هو دليل النجاة.

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

PerimeterX وCAPTCHA: لماذا تعود طلباتك ببيانات فارغة

يفحص تكامل PerimeterX في Zillow عدة إشارات في الوقت نفسه: بصمة TLS، وHTTP headers، وسمعة IP، وأنماط الطلبات. وعندما يكتشف الأتمتة، يعرض صفحة CAPTCHA من نوع "Press & Hold" بدلًا من بيانات العقار.

سيناريو الفشل بالضبط: ترسل طلبًا باستخدام headers الافتراضية في Python. يحتوي HTML الناتج على سكربتات تحدي PerimeterX بدلًا من بيانات العقار — وعندها لا يجد BeautifulSoup أي وسم __NEXT_DATA__.

الحل: استخدم الـ headers الكاملة المشابهة للمتصفح من الخطوة 1. وإذا كنت ترسل أكثر من بضع عشرات من الطلبات، فستحتاج أيضًا إلى تدوير proxies (سنغطي ذلك لاحقًا). وللاستخراج الثقيل، فكّر في مكتبة مثل curl_cffi مع impersonate="chrome" — فهي عميل HTTP الوحيد في Python تقريبًا القادر على محاكاة بصمة TLS حقيقية شبيهة بـ Chrome.

محددات CSS الديناميكية: لماذا تعيد BeautifulSoup قيمة None

إذا كنت تستخدم CSS selectors مثل .list-card-price أو أسماء classes تحتوي على hashes، فسيتعطل scraper كلما نشرت Zillow تحديثًا جديدًا.

تستخدم Zillow styled-components، التي تولّد أسماء class مثل StyledPropertyCardHomeDetailsList-c11n-8-109-3__sc-1j0som5-0. والجزء الخاص بالـ hash يتغير مع كل build.

الحل: لا تستخدم CSS selectors أصلًا. استخرج البيانات من كتلة JSON الخاصة بـ __NEXT_DATA__ كما في الكود أعلاه. هذا الأسلوب مستقر منذ سنوات لأنه لا يعتمد على HTML markup، الذي يتغير بسرعة أكبر بكثير.

إذا اضطررت إلى تحليل HTML، فابحث عن سمات data-test مثل data-test="property-card" أو استخدم مطابقة جزئية لأسماء الكلاسات مثل [class*="PropertyCard"]. لكن استخراج JSON يظل الطريق الأكثر موثوقية.

تدوير proxies وExponential Backoff: كود يصمد أمام حظر الـ IP

يتم إدراج عناوين IP الخاصة بمراكز البيانات في قائمة الحظر فورًا من قبل Zillow. لذلك تحتاج إلى residential proxies للوصول الموثوق. المعدل الآمن: طلب واحد كل 3–8 ثوانٍ لكل IP، مع البقاء تحت حوالي 500 طلب في الساعة.

إليك دالة إعادة المحاولة مع exponential backoff وjitter:

import random
import time

def backoff_with_jitter(attempt, base_delay=2, max_delay=60):
    """Exponential backoff بأسلوب AWS مع jitter كامل."""
    delay = min(max_delay, base_delay * (2 ** attempt))
    return random.uniform(0, delay)

def fetch_with_retry(url, max_retries=5):
    for attempt in range(max_retries):
        try:
            response = httpx.get(url, headers=headers, timeout=15)
            if response.status_code == 200:
                return response
            if response.status_code in (403, 429):
                delay = backoff_with_jitter(attempt, base_delay=5)
                print(f"Blocked ({response.status_code}). Retrying in {delay:.1f}s...")
                time.sleep(delay)
                continue
        except Exception as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(backoff_with_jitter(attempt))
    return None

وهنا pool بسيط لتدوير proxies:

class ProxyPool:
    def __init__(self, proxies):
        self.proxies = proxies
        self.index = 0
        self.failures = {}

    def get_next(self):
        proxy = self.proxies[self.index % len(self.proxies)]
        self.index += 1
        return {"http://": proxy, "https://": proxy}

    def report_failure(self, proxy):
        self.failures[proxy] = self.failures.get(proxy, 0) + 1
        if self.failures[proxy] > 3:
            self.proxies.remove(proxy)

# الاستخدام:
pool = ProxyPool(proxies=[
    "http://user:pass@residential1.example.com:8080",
    "http://user:pass@residential2.example.com:8080",
])

بالنسبة إلى مزوّدي الـ proxy، فإن DataImpulse يقدم residential proxies بسعر يقارب 1 دولار/GB (وهو الخيار الأرخص)، بينما IPRoyal وSmartproxy يُعدّان خيارين جيدين في الفئة المتوسطة بسعر 4–7 دولارات/GB.

البديل منخفض الصيانة تمامًا

إذا كنت تستخراج بيانات Zillow بشكل متكرر وتعبت من إصلاح المحددات المعطلة أو إدارة مجموعات الـ proxies، فإن Thunderbit يقرأ بنية الصفحة من جديد في كل عملية استخراج. لا توجد selectors تحتاج إلى صيانة، ولا إعدادات proxy. إنه يحل فعلًا مشكلة الهشاشة التي تجعل الأدوات البرمجية مصدر صداع متكرر.

أتمتة استخراج Zillow: الجدولة ومتابعة تغيّر الأسعار

كل مستثمر عقاري تحدثت معه يريد هذا، ولا يغطيه أي دليل آخر عن استخراج Zillow: عمليات استخراج متكررة وآلية لمتابعة الأسعار.

لمستخدمي Python: مهام Cron واكتشاف تغيّر الأسعار

أعدّ مهمة cron تشغّل scraper أسبوعيًا وتعلّم تغيّرات الأسعار:

import pandas as pd
from datetime import datetime

def detect_price_changes(new_data, historical_file, threshold=0.05):
    """مقارنة الاستخراج الجديد بالبيانات التاريخية، ووضع علامة على التغييرات الأكبر من threshold."""
    try:
        old = pd.read_csv(historical_file)
    except FileNotFoundError:
        new_data.to_csv(historical_file, index=False)
        print("First run — saved baseline data.")
        return pd.DataFrame()

    merged = new_data.merge(old, on="zpid", suffixes=("_new", "_old"))
    merged["price_change_pct"] = (
        (merged["price_new"] - merged["price_old"]) / merged["price_old"]
    )
    alerts = merged[merged["price_change_pct"].abs() > threshold]

    # إلحاق البيانات الجديدة مع طابع زمني
    new_data["scraped_at"] = datetime.now().isoformat()
    new_data.to_csv(historical_file, mode="a", header=False, index=False)

    return alerts

أضف هذا إلى crontab ليعمل أسبوعيًا صباح الاثنين الساعة 6:00:

0 6 * * 1 cd /path/to/scraper && python zillow_monitor.py

مثال عملي: راقب 50 إعلانًا في Austin, TX أسبوعيًا. كل يوم اثنين، يقوم السكربت باستخراج الأسعار الحالية، ومقارنتها بالأسبوع السابق، ثم إخراج ملف CSV يوضح أي انخفاض في السعر يتجاوز 5%.

لغير المبرمجين: Scheduled Scraper من Thunderbit

تتيح لك ميزة Scheduled Scraper في Thunderbit وصف الفاصل الزمني بلغة بسيطة ("كل يوم اثنين الساعة 9 صباحًا")، ثم إدخال روابط بحث Zillow، والنقر على Schedule. يتم تصدير البيانات تلقائيًا إلى Google Sheets في كل تشغيل. لا Python، ولا cron، ولا خادم تحتاج إلى إدارته. هذه ميزة مفيدة جدًا لوكلاء العقارات أو فرق العمليات التي تحتاج متابعة منتظمة للأسعار من دون دعم هندسي.

نصائح لاستخراج بيانات Zillow بشكل مسؤول

بعض الملاحظات المهمة للبقاء ضمن الحدود الصحيحة:

  • استخرج البيانات المتاحة للعامة فقط. لا تحاول الوصول إلى صفحات خلف تسجيل الدخول أو التحقق.
  • استخدم معدلات طلب معقولة. اترك 3–8 ثوانٍ بين الطلبات. لا تُرهق الخادم.
  • لا تستخرج بيانات شخصية أو خاصة بالمستخدمين. أسماء الوكلاء ومعلومات شركات الوساطة في الإعلانات عامة؛ أما بيانات الحسابات الشخصية فليست كذلك.
  • خزّن البيانات واستخدمها بطريقة أخلاقية. أبحاث السوق، وتحليل الاستثمار، وتوليد العملاء المحتملين كلها استخدامات مشروعة. أما الرسائل المزعجة فليست كذلك.
  • السياق القانوني: حكم hiQ v. LinkedIn رسّخ أن استخراج البيانات المتاحة للعامة لا يخالف CFAA. كما أكّد حكم Meta v. Bright Data (2024) مبادئ مشابهة. ومع ذلك، فإن شروط استخدام Zillow تقيد الوصول الآلي، وتُطبَّق عبر حظر الـ IP وصفحات CAPTCHA بدلًا من الإجراءات القانونية. تحقّق دائمًا من الإرشادات الحالية واحترم robots.txt.

اختر النهج المناسب لاستخراج Zillow باستخدام Python

أفضل مسار لك يعتمد على حالتك:

تحتاج البيانات بسرعة ومن دون كود؟ Thunderbit ينقلك من صفحة بحث Zillow إلى جدول بيانات منظم في حوالي دقيقتين. يتكيّف الذكاء الاصطناعي مع تغييرات التصميم، ويتعامل مع تقسيم الصفحات، ويتيح التصدير مجانًا. ثبّت Chrome Extension وجربه على صفحة بحث في Zillow.

تريد تحكمًا كاملًا؟ استخدم كود Python الموجود في هذا الدليل. استخرج من JSON في __NEXT_DATA__ وليس من CSS selectors لضمان الثبات. أضف headers تشبه المتصفح الحقيقي. ودوّر residential proxies واستخدم exponential backoff لرفع الاعتمادية.

توسّع في الحجم؟ خدمات scraping API مثل ScrapFly (نسبة نجاح 99% على Zillow) أو ScraperAPI تتولى لك بنية الـ proxy والحماية من CAPTCHA، مقابل 30–599 دولارًا شهريًا بحسب الحجم.

تتابع الأسعار بمرور الوقت؟ أنشئ cron job باستخدام سكربت اكتشاف تغيّر الأسعار، أو استخدم Scheduled Scraper من Thunderbit كخيار بلا صيانة.

البيانات موجودة. السؤال الوحيد هو: كم من وقت الهندسة تريد أن تنفقه لاستخراجها؟ ولمزيد من المعلومات حول نقل بيانات الويب إلى جداول البيانات، اطلع على دليلنا حول استخراج البيانات من المواقع إلى Excel أو على ملخص إحصاءات Zillow للحصول على أحدث بيانات المنصة. كما يمكنك مشاهدة الدروس على قناة Thunderbit على YouTube.

جرّب Thunderbit لاستخراج بيانات Zillow Get Started Free

الأسئلة الشائعة

هل يمكن استخراج Zillow باستخدام Python مجانًا؟

نعم — httpx وBeautifulSoup وpandas كلها مجانية ومفتوحة المصدر. المقابل هو الوقت: ستحتاج إلى إدارة الـ headers، وتدوير الـ proxies، وصيانة المحددات بنفسك. توقّع أن تستثمر 4–8 ساعات في الإعداد الأولي و4–10 ساعات شهريًا في الصيانة عندما يغيّر Zillow موقعه. كما يوفّر Thunderbit أيضًا خطة مجانية إذا أردت تجاوز عبء البرمجة بالكامل.

هل لدى Zillow واجهة API رسمية؟

أوقفت Zillow واجهتها العامة المجانية في سبتمبر 2021. أصبح الوصول الآن عبر Bridge Interactive، ويتطلب موافقة، ويكلف تقريبًا 500 دولار شهريًا، وهو موجّه لمتخصصي العقارات المرخّصين. بالنسبة لمعظم المستخدمين — المستثمرين، والباحثين، والوكلاء الذين يجرون تحليلًا للسوق — يكون الاستخراج هو البديل العملي. كما تنشر Zillow أيضًا بيانات بحثية مجانية بصيغة CSV قابلة للتنزيل على zillow.com/research/data/، بما في ذلك Zillow Home Value Index وZillow Observed Rent Index.

كيف أتجنب الحظر أثناء استخراج Zillow؟

ثلاثة أمور: (1) استخدم headers واقعية تشبه المتصفح، بما في ذلك Sec-Ch-Ua — فهذا هو الرأس الذي تغفله معظم الشروحات، وهو أول ما يفحصه PerimeterX؛ (2) دوّر residential proxies — لأن عناوين IP الخاصة بمراكز البيانات تُدرج في قائمة الحظر فورًا؛ (3) استخرج البيانات من JSON الخاص بـ __NEXT_DATA__ بدلًا من HTML selectors لتجنب التعطل بسبب تغيّر التصميم. اجعل المعدل 1 طلب كل 3–8 ثوانٍ لكل IP. أو استخدم أداة مثل Thunderbit التي تتولى الحماية من الروبوتات تلقائيًا.

ما أفضل طريقة لاستخراج Zillow من دون كتابة كود؟

AI Web Scraper من Thunderbit هو أسرع طريق. ثبّت Chrome Extension، ثم انتقل إلى صفحة بحث Zillow، واضغط "AI Suggest Fields" لاكتشاف الأعمدة تلقائيًا، ثم اضغط "Scrape." صدّر النتائج إلى Google Sheets أو Excel أو Airtable أو Notion من دون أي كود. يقرأ الذكاء الاصطناعي الصفحة من جديد في كل مرة، لذلك لا يتعطل عندما يحدّث Zillow تصميمه.

كم مرة يغيّر Zillow بنية موقعه، وكيف يؤثر ذلك على أدوات الاستخراج؟

ينشر Zillow تحديثات بشكل متكرر — أحيانًا أسبوعيًا. وبما أنهم يستخدمون styled-components، تتغير أسماء CSS class مع كل تحديث، وبالتالي تتعطل الأدوات المبنية على CSS selectors بشكل متكرر. أكثر نهج صامد في Python هو استخراج البيانات من JSON داخل __NEXT_DATA__، لأنه يتغير بوتيرة أقل بكثير. أما النهج الخالي من الصيانة، فإن Thunderbit يقرأ بنية الصفحة من جديد في كل عملية استخراج ويتكيف تلقائيًا مع تغييرات التصميم.

تعرف أكثر

Shuai Guan
Shuai Guan
الرئيس التنفيذي في Thunderbit | خبير في أتمتة البيانات بالذكاء الاصطناعي Shuai Guan هو الرئيس التنفيذي لشركة Thunderbit وخريج كلية الهندسة بجامعة ميشيغان. وبالاستناد إلى ما يقرب من عشر سنوات من الخبرة في مجالي التقنية وبنية SaaS، يتخصص في تحويل نماذج الذكاء الاصطناعي المعقدة إلى أدوات عملية لاستخراج البيانات بدون الحاجة إلى البرمجة. في هذه المدونة، يشارك رؤى صريحة ومجرّبة ميدانيًا حول استخراج البيانات من الويب واستراتيجيات الأتمتة، لمساعدتك على بناء سير عمل أذكى يعتمد على البيانات. وعندما لا يكون منشغلاً بتحسين تدفقات العمل الخاصة بالبيانات، يوجّه نفس دقته واهتمامه بالتفاصيل إلى شغفه بالتصوير الفوتوغرافي.
جدول المحتويات
Thunderbit · وكيل بيانات الويب بالذكاء الاصطناعي

Extract data from any page in 1 click

موثوق به من قبل أكثر من 250,000 مستخدم
الخطة المجانية متاحة
استخرج البيانات باستخدام الذكاء الاصطناعي
انقل البيانات بسهولة إلى Google Sheets أو Airtable أو Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week