استخراج بيانات Pinterest باستخدام Python: "Pins وBoards والتمرير اللانهائي"

آخر تحديث في April 17, 2026
استخراج بيانات Pinterest باستخدام Python: "Pins وBoards والتمرير اللانهائي"

قبل بضعة أشهر، ورّاني أحد مهندسينا سكربت Python كتبه خلال الويكند. كان هدفه يسحب صور الإلهام الخاصة بالمنتجات من Pinterest لمشروع أبحاث سوق. شغّله، وكانت النتيجة… 16 Pin فقط. من لوحة فيها أكثر من 2,000. ظل يطالع الشاشة ثم يطالعني، وقال: "أعتقد أن Pinterest يسخر مني".

وهو مو الوحيد. بصراحة، هذه أكثر مشكلة أشوفها عند المطورين اللي يحاولون استخراج بيانات Pinterest باستخدام Python. تفتح requests وBeautifulSoup، تزور رابط Pinterest، ثم تطلع لك كم قطعة بسيطة أو صفحة HTML فاضية. السبب؟ Pinterest عبارة عن تطبيق أحادي الصفحة مبني بالكامل على JavaScript — يعني طلب HTTP الثابت ما يشوف المحتوى الحقيقي أبدًا. في هذا الدليل، بشرح لك ليه يصير كذا، وما هي الطرق اللي تشتغل فعلًا (Playwright، واعتراض الـ API الداخلي، وأدوات بدون كود مثل Thunderbit)، وبعطيك أمثلة عملية خطوة بخطوة لاستخراج الـ Pins واللوحات (Boards) وملفات المستخدمين، والتعامل مع التمرير اللانهائي، والحصول على الصور عالية الدقة. سواء كنت تبغى تبني أداة استخراج احترافية أو بس تجمع البيانات بسرعة، فهذا المقال بيفيدك.

ما المقصود باستخراج بيانات Pinterest؟

استخراج بيانات Pinterest يعني جمع البيانات من Pinterest برمجيًا — مثل صور الـ Pin والعناوين والوصف وأسماء اللوحات وعدد المتابعين والروابط. بدل ما تتصفح يدويًا وتحفظ كل Pin لحاله، تقدر تستخدم كود (أو أداة) لجمع بيانات منظمة من نتائج البحث أو اللوحات أو ملفات المستخدمين على نطاق واسع.

ومع وجود أكثر من 240 مليار Pin على المنصة و619 مليون مستخدم نشط شهريًا حتى أواخر 2025، يعتبر Pinterest واحدًا من أغنى مصادر البيانات البصرية على الويب. وللشركات، هذي البيانات كنز حقيقي — سواء كنت تتابع اتجاهات المنتجات، أو تقارن محتوى المنافسين، أو تبني قوائم للتواصل مع المؤثرين.

لماذا نستخدم Python لاستخراج بيانات Pinterest؟

Pinterest ما عاد مجرد لوحة إلهام لمخططي حفلات الزفاف. صار منصة قوية لذكاء الأعمال — إذ إن 85% من مستخدمي Pinterest الأسبوعيين اشتروا شيئًا بناءً على Pins من العلامات التجارية، كما أن 96–97% من أهم عمليات البحث غير مرتبطة بعلامات تجارية، وهذا يعني أن المستخدمين يدخلون بنية شراء لكن بدون ولاء مسبق لعلامة معينة. وهذي فرصة كبيرة للاكتشاف — وتوضح ليه فرق كثيرة تبغى بيانات Pinterest بشكل منظم.

وهذا ينعكس عمليًا كالتالي بحسب الفريق:

الفريقالبيانات المطلوبةالقيمة التجارية
عمليات التجارة الإلكترونيةصور المنتجات، الأسعار، الجماليات الرائجةتسعير تنافسي، ومخزون مرتبط بالاتجاهات
التسويقأداء اللوحات، تفاعل الـ Pin، محتوى المنافسيناستراتيجية المحتوى، وقياس أداء الحملات
المبيعات / توليد العملاءملفات المبدعين، عدد المتابعين، معلومات التواصلالتواصل مع المؤثرين، واستهداف الشراكات
العقاراتPins تنسيق المنازل، اتجاهات الديكور، تخطيطات الغرفتصوير القوائم، وإرشادات التنسيق الداخلي
صناع المحتوىالمواضيع الرائجة، التنسيقات الشائعة، المواسمتقويم المحتوى، ودراسة الأسلوب البصري

والنقطة الأهم: الـ API الرسمي لـ Pinterest محدود. فهو يحتاج حساب أعمال، وموافقة مسبقة (بما فيها عرض فيديو لتطبيقك)، وكمان يعطيك فقط وصولًا لبيانات حسابك أنت. إذا كنت تبغى تتصفح اللوحات العامة أو نتائج البحث أو ملفات المنافسين، فالاستخراج هو البديل العملي. ولهذا تلجأ فرق كثيرة إلى Python — أو إلى أدوات بدون كود مثل Thunderbit عندما تبغى النتائج بدون إعدادات معقدة.

لماذا يفشل BeautifulSoup وحده مع Pinterest، وما الذي يعمل فعلًا؟

إذا حاولت استخراج بيانات Pinterest باستخدام requests + BeautifulSoup وحصلت على 16 عنصرًا فقط أو صفحة فاضية، فأنت مو متخيل. Pinterest مبني باستخدام React ويعرض 100% من المحتوى عبر JavaScript. ولما تطلب رابط Pinterest عبر HTTP عادي، السيرفر يرسل لك HTML بسيط جدًا — بعض وسوم <link> و<script>، و<div> فاضي يركّب فيه React التطبيق. كل بطاقات الـ Pin والصور والعناوين والشبكات تُضاف بعد تنفيذ JavaScript داخل المتصفح.

ما فيه تنفيذ JavaScript = ما فيه Pins.

طيب وش اللي ينجح؟ هذه مقارنة سريعة بين الطرق الرئيسية:

الطريقةتدعم JavaScript؟تحصل على كل البيانات؟مستوى التعقيدالأنسب لـ
requests + BeautifulSoupلاتقريبًا 0–16 عنصرًامنخفضغير مناسبة لـ Pinterest
Selenium / Playwrightنعمنعم، مع منطق للتمريرمتوسطتحكم كامل، وسلاسل عمل Python
اعتراض الـ API الداخلي لـ Pinterestنعمنعم، بيانات JSON مقسمة على صفحاتمرتفعأقصى قدر من البيانات، من دون متصفح
Scraper API من طرف ثالثنعميختلفمنخفضالتوسع من دون بنية تحتية
أداة بدون كود (Thunderbit)نعمبيانات منظمة بالذكاء الاصطناعيمنخفض جدًالغير التقنيين، ونتائج سريعة

في هذا الدليل، أنصح باستخدام Playwright كخيار Python. هو يعرض JavaScript، ويدعم محاكاة التمرير، وصيانته ممتازة (أكثر من 78,600 نجمة على GitHub، ونمو 180% سنويًا في الوظائف المطلوبة)، وكمان أسرع من Selenium بنسبة 35–45% في الاختبارات. وإذا كنت تفضل الشغل بدون كود، فبغطي هذا الخيار أيضًا.

Pinterest API الرسمي مقابل Python Scraping مقابل الأدوات بدون كود: أي مسار تختار؟

قبل ما تبدأ تكتب الكود، من المفيد تسأل نفسك: هل فعلًا تحتاج هذا المسار؟ هذا إطار قرار سريع:

المعيارPinterest APIاستخراج البيانات بـ PythonThunderbit (بدون كود)
يتطلب موافقةحساب أعمال + عرض فيديولالا
الوصول إلى Pins/Boards العامةمحدود (بياناتك فقط)كاملكامل
تنزيل الصور بدقة كاملةيختلفنعم، عبر تحليل الرابطنعم، عبر استخراج الصور
التعامل مع التمرير اللانهائيغير قابل للتطبيقنعم، عبر الكودتلقائي
الحاجة للصيانةمنخفضةمرتفعة (قد تتغير المحددات)لا توجد (الذكاء الاصطناعي يتكيف)
التصدير إلى Sheets/Airtableيدويعبر كود مخصصمدمج
وقت الإعدادساعات–أيام30–60 دقيقةدقيقتان

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

أما إذا كنت تبغى تحكم كامل، أو ناوي تدمج الاستخراج داخل pipeline بـ Python، أو ببساطة تحب تبني الأدوات بنفسك — فكمّل القراءة.

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

  • مستوى الصعوبة: متوسط
  • الوقت المطلوب: حوالي 30–60 دقيقة (بما في ذلك البرمجة والاختبار)
  • ما تحتاجه: Python 3.9+، ومتصفح Chrome (للاختبار)، والوصول إلى الطرفية/سطر الأوامر

تثبيت Playwright والاعتماديات

ابدأ بإنشاء مجلد للمشروع وإعداد بيئة افتراضية:

mkdir pinterest-scraper
cd pinterest-scraper
python -m venv venv
source venv/bin/activate  # على Windows: venv\Scripts\activate

بعدها ثبّت Playwright وحمّل نسخة Chromium:

pip install playwright
playwright install chromium

كمان راح تستخدم وحدات Python المدمجة json وos وcsv لتصدير البيانات. ما تحتاج تثبيت إضافي لها.

هيكل مجلد المشروع

أنصح ترتب الملفات من البداية:

pinterest-scraper/
├── scraper.py
├── config.py
├── output/
│   ├── pins.json
│   └── pins.csv
└── images/
    ├── board-name-1/
    └── board-name-2/

في ملف config.py، عيّن سلسلة user agent الخاصة بك. Pinterest يحظر بصمات المتصفحات headless الافتراضية، لذلك استخدم سلسلة واقعية:

USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"

الخطوة 1: إنشاء رابط البحث في Pinterest

أنشئ رابط البحث بإدراج عبارة البحث داخل القالب:

query = "mid century modern furniture"
url = f"https://www.pinterest.com/search/pins/?q={query.replace(' ', '%20')}&rs=typed"

تقدر تخليها ديناميكية لأي عبارة بحث. المعامل rs=typed يخبر Pinterest أن الاستعلام كُتب يدويًا (وليس اقتراحًا)، وهذا أحيانًا يؤثر في صلة النتائج.

الخطوة 2: تشغيل متصفح Headless وتحميل الصفحة

هذا هو الإعداد الأساسي لـ Playwright. لاحظ user agent المخصص — بدونه، غالبًا Pinterest يحظر الطلب أو يوديك لصفحة تسجيل دخول.

import asyncio
from playwright.async_api import async_playwright
from config import USER_AGENT

async def scrape_search(query, max_pins=100):
    url = f"https://www.pinterest.com/search/pins/?q={query.replace(' ', '%20')}&rs=typed"
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page(
            user_agent=USER_AGENT,
            viewport={"width": 1920, "height": 1080}
        )
        await page.goto(url)
        await asyncio.sleep(3)  # انتظار تحميل JavaScript للـ Pins الأولية

بعد تنفيذ هذا الجزء، يفترض أن الصفحة حمّلت أول دفعة من الـ Pins — غالبًا بين 25 و50.

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

Pinterest يحط كل Pin داخل div يحمل data-test-id='pinWrapper'. داخلها بتلقى رابطًا (<a>) فيه عنوان الـ Pin ورابطه (عبر aria-label)، وعنصر <img> يحمل رابط الصورة المصغرة.

        results = []
        pins = await page.query_selector_all("div[data-test-id='pinWrapper']")
        for pin in pins:
            link = await pin.query_selector("a")
            if not link:
                continue
            title = await link.get_attribute("aria-label") or ""
            href = await link.get_attribute("href") or ""
            img = await pin.query_selector("img")
            src = await img.get_attribute("src") if img else ""
            results.append({
                "title": title,
                "url": f"https://www.pinterest.com{href}" if href.startswith("/") else href,
                "image_url": src
            })

بهذه المرحلة، results يحتوي على الـ Pins الظاهرة في الجزء الأول من الشاشة. وللحصول على المزيد، تحتاج تمرير — وهذا يودينا لأهم جزء.

الخطوة 4: حفظ النتائج بصيغة JSON أو CSV

بعد الاستخراج، احفظ البيانات في ملفات يسهل استخدامها لاحقًا:

import json
import csv

def save_json(data, filepath="output/pins.json"):
    with open(filepath, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def save_csv(data, filepath="output/pins.csv"):
    if not data:
        return
    with open(filepath, "w", newline="", encoding="utf-8-sig") as f:
        writer = csv.DictWriter(f, fieldnames=data[0].keys())
        writer.writeheader()
        writer.writerows(data)

استخدم ترميز utf-8-sig لملف CSV إذا كنت بتفتحه في Excel — لأنه يمنع ظهور الأحرف بشكل مشوّه.

استخراج لوحات Pinterest الكاملة وملفات المستخدمين

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

استخراج كل Pins من رابط لوحة

روابط اللوحات عادة تكون بالشكل https://www.pinterest.com/{username}/{board-name}/. وبنية الصفحة تشبه نتائج البحث — حيث تُلفّ الـ Pins داخل div[data-test-id='pinWrapper'] — لكن لازم تمرر لتحميلها كلها.

async def scrape_board(board_url, max_pins=500):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page(user_agent=USER_AGENT, viewport={"width": 1920, "height": 1080})
        await page.goto(board_url)
        await asyncio.sleep(3)

        seen_ids = set()
        all_pins = []

        for scroll_round in range(100):  # حد أمان
            pins = await page.query_selector_all("div[data-test-id='pinWrapper']")
            new_count = 0
            for pin in pins:
                link = await pin.query_selector("a")
                if not link:
                    continue
                href = await link.get_attribute("href") or ""
                if href in seen_ids:
                    continue
                seen_ids.add(href)
                new_count += 1
                title = await link.get_attribute("aria-label") or ""
                img = await link.query_selector("img")
                src = await img.get_attribute("src") if img else ""
                all_pins.append({
                    "title": title,
                    "url": f"https://www.pinterest.com{href}" if href.startswith("/") else href,
                    "image_url": src
                })

            print(f"التمرير {scroll_round + 1}: تم جمع {len(all_pins)} Pin فريد")
            if new_count == 0 or len(all_pins) >= max_pins:
                break

            prev_height = await page.evaluate("document.body.scrollHeight")
            await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
            await asyncio.sleep(2.5)
            curr_height = await page.evaluate("document.body.scrollHeight")
            if curr_height == prev_height:
                break  # لا يوجد محتوى إضافي

        await browser.close()
        return all_pins

انتبه لشيء مهم: أحيانًا تعرض صفحات اللوحات تبويبًا اسمه "More Ideas" يفصل بين الـ Pins المحفوظة والاقتراحات الخوارزمية. إذا كنت تبغى فقط الـ Pins المحفوظة الخاصة بالمستخدم، فتوقف عن التمرير لما يظهر هذا الفاصل.

استخراج ملف مستخدم: اللوحات، وعدد المتابعين، والـ Pins

روابط الملفات الشخصية تكون مثل https://www.pinterest.com/{username}/. ومن صفحة الملف الشخصي تقدر تستخرج:

  • عدد المتابعين/المتابَعين: ابحث عن div[data-test-id='follower-count']
  • قائمة اللوحات: كل لوحة تكون بطاقة ترتبط بـ /{username}/{board-name}/
  • إجمالي عدد الـ Pins: يظهر أحيانًا في رأس الملف الشخصي
async def scrape_profile(username):
    url = f"https://www.pinterest.com/{username}/"
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page(user_agent=USER_AGENT, viewport={"width": 1920, "height": 1080})
        await page.goto(url)
        await asyncio.sleep(3)

        # استخراج عدد المتابعين
        follower_el = await page.query_selector("div[data-test-id='follower-count']")
        followers = await follower_el.inner_text() if follower_el else "غير متاح"

        # استخراج روابط اللوحات
        board_links = await page.query_selector_all("a[href*='/" + username + "/']")
        boards = []
        for bl in board_links:
            href = await bl.get_attribute("href") or ""
            name = await bl.get_attribute("aria-label") or href.split("/")[-2]
            if href.count("/") >= 3 and href != f"/{username}/":
                boards.append({"name": name, "url": f"https://www.pinterest.com{href}"})

        await browser.close()
        return {"username": username, "followers": followers, "boards": boards}

ولجمع كل الـ Pins عبر جميع لوحات الملف الشخصي، كرر على قائمة اللوحات واستدعِ scrape_board() لكل لوحة. وتقدر أيضًا ترتب الصور التي تم تنزيلها داخل مجلدات منفصلة لكل لوحة تلقائيًا.

بناء معالج تمرير لانهائي جاهز للإنتاج

هذه هي النقطة اللي تفرق بين أداة بسيطة ومُستخرِج حقيقي. أكبر مشكلة — وشفتها في أكثر من اثني عشر نقاشًا في المنتديات — هي أن أدوات الاستخراج ما ترجع إلا 16–25 عنصرًا لأنها ما تتمرر بما يكفي، أو لأنها تستخدم عدد تمريرات ثابت مثل for i in range(5): scroll() وتنتظر الأفضل.

هذا الأسلوب غير موثوق. Pinterest يحمّل المحتوى الجديد على دفعات تقارب 25 Pin، ويبدأ هذا عند التمرير. إذا مررت خمس مرات، ممكن تحصل على 125 Pin — أو 75 إذا كان الاتصال بطيئًا، أو 150 إذا كانت الدفعات أصغر. تحتاج نمط أذكى.

نمط التمرير حتى لا يظهر محتوى جديد

هذه دالة تمرير قوية تتتبع معرفات الـ Pin الفريدة، وتستخدم مهلة قابلة للتعديل، وتضم منطق إعادة المحاولة، وتطبع التقدم:

import time
import random

async def scroll_and_collect(page, max_pins=1000, max_scrolls=200, scroll_pause=2.5):
    seen_ids = set()
    all_pins = []
    no_new_count = 0

    for i in range(max_scrolls):
        pins = await page.query_selector_all("div[data-test-id='pinWrapper']")
        new_this_round = 0

        for pin in pins:
            link = await pin.query_selector("a")
            if not link:
                continue
            href = await link.get_attribute("href") or ""
            if href in seen_ids:
                continue
            seen_ids.add(href)
            new_this_round += 1
            title = await link.get_attribute("aria-label") or ""
            img = await pin.query_selector("img")
            src = await img.get_attribute("src") if img else ""
            all_pins.append({
                "title": title,
                "url": f"https://www.pinterest.com{href}" if href.startswith("/") else href,
                "image_url": src
            })

        print(f"  التمرير {i+1}: {new_this_round} Pin جديد | {len(all_pins)} Pin فريد إجمالًا")

        if len(all_pins) >= max_pins:
            print(f"  تم الوصول إلى حد max_pins ({max_pins}). التوقف.")
            break

        if new_this_round == 0:
            no_new_count += 1
            if no_new_count >= 3:
                print("  ما ظهر أي محتوى جديد بعد 3 تمريرات متتالية. انتهى المحتوى.")
                break
        else:
            no_new_count = 0

        prev_height = await page.evaluate("document.body.scrollHeight")
        await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
        await asyncio.sleep(scroll_pause + random.uniform(0.5, 1.5))
        curr_height = await page.evaluate("document.body.scrollHeight")

        if curr_height == prev_height and new_this_round == 0:
            print("  ارتفاع الصفحة ما تغير وما ظهرت Pins جديدة. غالبًا انتهت الخلاصة.")
            break

    return all_pins

ليش هذا التصميم فعّال؟

  • إزالة التكرار عبر href: رابط كل Pin فريد، لذلك نستخدمه كمعرّف. هذا يمنع عدّ الـ Pin نفسه مرتين لما يعاد رسم DOM أثناء التمرير.
  • قاعدة ثلاث مرات: إذا ما ظهر أي محتوى جديد في ثلاث تمريرات متتالية، نتوقف. هذا يعالج حالة أن الصفحة ما زالت تحمل لكن ما فيها محتوى جديد.
  • تذبذب عشوائي في التوقف: إضافة تأخير عشوائي بين 0.5 و1.5 ثانية بين التمريرات يجعل السلوك أقرب للبشري ويقلل احتمال تفعيل أنظمة مكافحة البوت.
  • حد أمان لعدد التمريرات: يمنع الدخول في حلقات لا نهائية إذا صار خطأ ما.

التعامل مع الحالات الخاصة

  • فاصل "More Ideas": في صفحات اللوحات، يضيف Pinterest أحيانًا قسمًا باسم "More Ideas". إذا كنت تبغى فقط الـ Pins الأصلية المحفوظة في اللوحة، تقدر تتحقق من هذا العنصر وتتوقف لما يظهر.
  • تحديد المعدل في الجلسات الطويلة: إذا كنت تتمرر عبر لوحة فيها آلاف الـ Pins، قد يبدأ Pinterest يخفف الاستجابات. إذا لاحظت أن بعض التمريرات ما تُظهر محتوى جديد بشكل متقطع (وليس ثلاث مرات متتالية)، فزد مدة التوقف إلى 5 ثوانٍ أو أكثر.

الحصول على صور Pinterest عالية الدقة، وليس الصور المصغرة

هذه النقطة تزعج كثيرين. تطلع بمجموعة Pins، وتنزّل الصور، فتجدها كلها صورًا مصغرة صغيرة بعرض 236 بكسل. والناس في المنتديات يصفونها بأنها "جودة سيئة جدًا، وكأن الحجم صغير للغاية". الحل هو فهم بنية روابط صور Pinterest.

فهم مسارات روابط صور Pinterest

كل صور Pinterest تُقدَّم من https://i.pinimg.com/{size}/{hash}.jpg. الجزء {size} هو اللي يحدد الدقة:

مسار الحجمالأبعادالاستخدام
/236x/بعرض 236 بكسلعرض الشبكة الافتراضي (ما تحصل عليه عادةً)
/474x/بعرض 474 بكسلدقة متوسطة
/736x/بعرض 736 بكسلعرض تفاصيل الـ Pin / العرض الموسع
/originals/أبعاد الرفع الأصليةالدقة الكاملة

دالة مساعدة: ترقية أي رابط صورة من Pinterest إلى أعلى دقة

هذه دالة تعيد كتابة أي رابط صورة من Pinterest إلى أعلى جودة متاحة، مع منطق بديل تلقائي:

import requests as req

def upgrade_image_url(url, preferred_size="originals"):
    """إعادة كتابة رابط صورة Pinterest إلى أعلى دقة متاحة."""
    sizes = ["originals", "736x", "474x", "236x"]
    if preferred_size not in sizes:
        preferred_size = "originals"

    for size in sizes[sizes.index(preferred_size):]:
        upgraded = url
        for s in sizes:
            upgraded = upgraded.replace(f"/{s}/", f"/{size}/")
        try:
            resp = req.head(upgraded, timeout=5, allow_redirects=True)
            if resp.status_code == 200:
                return upgraded
        except Exception:
            continue
    return url  # إرجاع الرابط الأصلي إذا فشلت كل المحاولات

ملاحظة مهمة (حتى 2025): مسار /originals/ صار يرجع كثيرًا أخطاء HTTP 403 Forbidden. وهذا مؤكد في مشكلة موثقة في gallery-dl حتى منتصف 2025. الحد الأعلى الموثوق هو /736x/. دالتي تحاول /originals/ أولًا، ثم تنتقل تلقائيًا إلى /736x/.

تنزيل الصور في مجلدات منظمة

import os
import time

def download_images(pins, folder="images/default", delay=1.5):
    os.makedirs(folder, exist_ok=True)
    for i, pin in enumerate(pins):
        img_url = upgrade_image_url(pin.get("image_url", ""), preferred_size="736x")
        if not img_url:
            continue
        filename = f"pin_{i+1}.jpg"
        filepath = os.path.join(folder, filename)
        try:
            resp = req.get(img_url, timeout=15)
            if resp.status_code == 200:
                with open(filepath, "wb") as f:
                    f.write(resp.content)
                print(f"  تم تنزيل {filename} ({len(resp.content) // 1024} KB)")
            else:
                print(f"  فشل {filename}: HTTP {resp.status_code}")
        except Exception as e:
            print(f"  خطأ أثناء تنزيل {filename}: {e}")
        time.sleep(delay + random.uniform(0.3, 0.8))

حط تأخير بين عمليات التنزيل. أنا عادة أستخدم 1.5–2.3 ثانية مع تذبذب بسيط. بدون هذا، ممكن Pinterest يحظر عنوان IP الخاص بك بعد بضع مئات من الطلبات.

تصدير بيانات Pinterest التي استخرجتها

التصدير إلى CSV أو JSON

غطينا الأساسيات سابقًا. أما مع مجموعات البيانات الكبيرة جدًا (أكثر من 10,000 Pin)، ففكر في استخدام صيغة JSON Lines — كائن JSON واحد في كل سطر — لأنها أسهل في البث والمعالجة:

def save_jsonl(data, filepath="output/pins.jsonl"):
    with open(filepath, "w", encoding="utf-8") as f:
        for item in data:
            f.write(json.dumps(item, ensure_ascii=False) + "\n")

التصدير إلى Google Sheets أو Airtable أو Notion

إذا بغيت تدفع البيانات مباشرة من Python إلى Google Sheets، فستحتاج إلى مكتبة gspread وحساب خدمة في Google Cloud. أما Airtable فيستخدم pyairtable. وبالنسبة إلى Notion فستستخدم notion-client. كل خيار يحتاج إعداد مفتاح API ويضيف تعقيدًا حقيقيًا إلى مسارك.

أو — وبصراحة، هذا أسرع طريق فعلًا — تقدر تستخدم Thunderbit لاستخراج بيانات Pinterest والتصدير إلى أي من هذه الوجهات بنقرة واحدة. لا مفاتيح API، ولا حسابات خدمة، ولا كود إضافي. يتولى Thunderbit Chrome Extension التصدير بشكل أصلي.

نصائح لتجنب الحظر أثناء استخراج بيانات Pinterest

يُصنف نظام مكافحة البوتات في Pinterest على أنه 6/10 من حيث صعوبة التجاوز بحسب ScrapeOps — مو سهل، لكنه مو الأصعب بعد. فهو يستخدم بصمة المتصفح، وتحليل السلوك، وتحديد المعدل عبر IP. هذا اللي ينفع:

  • تدوير user agents: استخدم مجموعة من سلاسل Chrome الحقيقية واختر واحدة عشوائيًا لكل جلسة.
  • إضافة تأخيرات عشوائية: 2–5 ثوانٍ بين التمريرات والطلبات، مع تذبذب بسيط. وإذا ما تستخدم proxies، زِدها إلى 10–15 ثانية.
  • استخدام أبعاد شاشة واقعية: خلك على viewport={"width": 1920, "height": 1080} — لا تستخدم مقاسات صغيرة أو غريبة.
  • فكر في proxies عند التوسع: إذا كنت تسحب آلاف الـ Pins، استخدم proxies سكنية دوارة. بدونها، توقع حظر IP بعد بضع مئات من الطلبات.
  • احترم robots.txt: ملف robots.txt في Pinterest يمنع معظم برامج الزحف الآلية ويحتوي على نحو 180 قاعدة منع. انتبه لهذا من ناحية الامتثال.
  • تجنب الاستخراج بعد تسجيل الدخول: التزم بالمحتوى العام المرئي وأنت غير مسجل الدخول. الاستخراج خلف تسجيل الدخول يرفع المخاطر القانونية والتقنية.

Thunderbit يتولى تحديات مكافحة البوت وCAPTCHA تلقائيًا عبر محركه الذكي — وهذا شيء أقل عليك صيانته إذا اخترت المسار بدون كود.

الاعتبارات القانونية والأخلاقية لاستخراج بيانات Pinterest

بختصر هنا لأن هذا مو محور المقال، لكنه مهم.

تنص شروط خدمة Pinterest (القسم 2a) على أنك توافق على عدم "scrape, collect, search, copy or otherwise access data or content from Pinterest in unauthorized ways, such as by using automated means (without our express prior permission)." ومع ذلك، تميل المحاكم عمومًا إلى اعتبار استخراج البيانات المتاحة علنًا غير مخالف لقانون Computer Fraud and Abuse Act — راجع hiQ v. LinkedIn وقضية Meta v. Bright Data (يناير 2024)، حيث حكمت المحكمة بأن استخراج البيانات المرئية للعامة أثناء عدم تسجيل الدخول قانوني.

بعض القواعد الأساسية:

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

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

الخلاصة: ما الذي تعلمته وإلى أين تتجه بعد ذلك

أنت الآن تعرف لماذا يفشل الاستخراج الثابت على Pinterest (لأنه تطبيق React SPA — لا JavaScript، لا بيانات)، وكيف تستخدم Playwright لاستخراج نتائج البحث واللوحات وملفات المستخدمين، وكيف تبني معالج تمرير لانهائي احترافي ما يتوقف عند 16 Pin، وكيف تحصل على صور كاملة الدقة بدل الصور المصغرة الصغيرة.

ملخص سريع لأهم النقاط:

  • requests + BeautifulSoup ما راح يشتغلان مع Pinterest. لا تضيع وقتك.
  • Playwright هو أفضل أداة Python لهذي المهمة — سريع، مدعوم جيدًا، ويتعامل مع عرض JavaScript بشكل أصلي.
  • التمرير اللانهائي يحتاج حلقة تمرير مبنية على إزالة التكرار، وليس عددًا ثابتًا من التمريرات.
  • الصور عالية الدقة تحتاج إعادة كتابة مسار الرابط — استهدف /736x/ (لأن /originals/ غالبًا يرجع 403).
  • استخراج اللوحات والملفات الشخصية مو مغطى كثير في الشروحات الحالية، لكنه سهل نسبيًا إذا استخدمت المحددات الصحيحة.
  • لغير المبرمجين أو للفرق اللي تبغى السرعة، يتيح لك Thunderbit استخراج بيانات Pinterest في خطوتين وتصديرها إلى Google Sheets أو Excel أو Airtable أو Notion — بدون الحاجة إلى Python. جرّبه مجانًا عبر Chrome Extension.

إذا كنت تبني pipeline بـ Python، فالكود الموجود في هذا الدليل يعطيك أساسًا قويًا. وإذا كنت تحتاج فقط إلى البيانات، فThunderbit هو الاختصار. في الحالتين، ما عاد أنت عالق مع 16 Pin ونظرة حيرة.

ولمزيد من المعلومات حول الاستخراج وجمع البيانات، اطلع على أدلتنا حول كيفية استخراج البيانات من الويب باستخدام Python، وأفضل أدوات استخراج الويب الآلية، واستخراج البيانات من موقع إلى Excel. وتقدر أيضًا تستكشف أسعار Thunderbit أو تشاهد الشروحات على قناة Thunderbit على YouTube.

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

1. هل يمكن استخراج بيانات Pinterest باستخدام BeautifulSoup؟

ليس بكفاءة إذا استخدمته وحده. Pinterest يعرض كل المحتوى عبر JavaScript، لذلك فإن requests + BeautifulSoup ترى فقط هيكل HTML فاضي. تحتاج إلى متصفح headless مثل Playwright أو Selenium لعرض الصفحة أولًا، أو تقدر تستخدم أداة بدون كود مثل Thunderbit تتولى عرض JavaScript تلقائيًا.

2. كم عدد الـ Pins اللي أقدر أستخرجها من Pinterest في جلسة واحدة؟

يعتمد هذا على منطق التمرير وطريقة التعامل مع مكافحة البوت. باستخدام معالج التمرير اللانهائي الجاهز للإنتاج في هذا الدليل (إزالة التكرار، والمهلة، ومنطق إعادة المحاولة)، تقدر تستخرج مئات إلى آلاف الـ Pins لكل لوحة أو استعلام بحث بشكل موثوق. أما اللوحات الكبيرة جدًا، فتوقع تقضي عدة دقائق في التمرير والجمع.

3. ليه صور Pinterest اللي استخرجتها تطلع صغيرة جدًا؟

افتراضيًا، Pinterest يقدّم صورًا مصغرة /236x/ في عرض الشبكة. للحصول على دقة أعلى، أعد كتابة مسار الرابط إلى /736x/ أو /originals/. لاحظ أن /originals/ صار يرسل أخطاء 403 بشكل متزايد حتى 2025، لذلك /736x/ هو الحد الأعلى الموثوق.

4. هل استخراج بيانات Pinterest قانوني؟

استخراج البيانات العامة المتاحة علنًا مقبول عمومًا وفق أحكام قضائية حديثة (مثل hiQ v. LinkedIn وMeta v. Bright Data)، لكن شروط خدمة Pinterest تمنع الوصول الآلي غير المصرح به. التزم بالمحتوى العام، ولا تستخدم البيانات في الرسائل المزعجة، واحترم حقوق النشر، واستشر مستشارًا قانونيًا في الاستخدامات التجارية.

5. ما هو أفضل بديل بدون كود لاستخراج بيانات Pinterest؟

يمكن لـ Thunderbit AI Web Scraper استخراج بيانات Pins في Pinterest — مثل العناوين والصور والروابط والوصف — في خطوتين فقط، مع تصدير مدمج إلى Google Sheets أو Excel أو Airtable أو Notion. كما أنه يتعامل تلقائيًا مع عرض JavaScript والتمرير اللانهائي وتحديات مكافحة البوت، لذلك ما تحتاج تكتب أو تصين أي كود.

اعرف المزيد

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