Scraping Pinteresta w Pythonie: „Piny, tablice i nieskończone przewijanie”

Ostatnia aktualizacja: April 17, 2026
Scraping Pinteresta w Pythonie: „Piny, tablice i nieskończone przewijanie”

Kilka miesięcy temu jeden z naszych inżynierów pokazał mi skrypt w Pythonie, który napisał w weekend. Miał pobierać obrazy inspiracji produktowych z Pinteresta na potrzeby projektu badania rynku. Uruchomił go i wynik był… 16 pinów. Z tablicy liczącej ponad 2 000. Wpatrywał się w ekran, potem na mnie, po czym powiedział: „Chyba Pinterest się ze mnie nabija”.

Nie był sam. To bez dwóch zdań najczęstsza frustracja, jaką widzę u programistów próbujących scrapować Pinteresta w Pythonie. Odpalasz requests i BeautifulSoup, wchodzisz na adres Pinteresta i dostajesz garść elementów albo pusty szkielet HTML. Dlaczego? Bo Pinterest to aplikacja typu single-page, renderowana w całości po stronie JavaScript — zwykłe żądanie HTTP nie zobaczy właściwej zawartości. W tym poradniku pokażę Ci, dlaczego tak się dzieje, jakie metody naprawdę działają (Playwright, przechwytywanie wewnętrznego API oraz narzędzia no-code, takie jak Thunderbit), a także dam Ci kod krok po kroku do pobierania pinów, tablic, profili użytkowników, nieskończonego przewijania i obrazów w pełnej rozdzielczości. Niezależnie od tego, czy chcesz zbudować scraper gotowy do użycia w produkcji, czy po prostu szybko pobrać dane, ten artykuł pomoże Ci to zrobić.

Czym jest scraping Pinteresta?

Scraping Pinteresta to programowe wyciąganie danych z tej platformy — takich jak obrazy pinów, tytuły, opisy, nazwy tablic, liczba obserwujących czy adresy URL. Zamiast ręcznie przeglądać i zapisywać piny jeden po drugim, używasz kodu (lub narzędzia), aby masowo zbierać uporządkowane dane z wyników wyszukiwania, tablic albo profili użytkowników.

Przy ponad 240 miliardach Pinów na platformie i 619 milionach aktywnych użytkowników miesięcznie pod koniec 2025 roku Pinterest jest jednym z najbogatszych źródeł danych wizualnych w sieci. Dla firm te dane są na wagę złota — niezależnie od tego, czy śledzisz trendy produktowe, porównujesz treści konkurencji, czy budujesz listy do outreachu influencerów.

Dlaczego warto scrapować Pinteresta w Pythonie?

Pinterest to już nie tylko tablica inspiracji dla organizatorek wesel. To poważna platforma do analizy biznesowej — 85% osób korzystających z Pinteresta co tydzień kupiło coś na podstawie pinów marki, a 96–97% najpopularniejszych wyszukiwań nie zawiera nazwy marki, co oznacza, że użytkownicy przychodzą z intencją zakupu, ale bez lojalności wobec marki. To ogromna szansa na odkrywanie nowych tematów — i właśnie dlatego tyle zespołów chce mieć dostęp do uporządkowanych danych z Pinteresta.

Tak to wygląda w praktyce dla różnych działów:

ZespółPotrzebne daneWartość biznesowa
Operacje e-commerceZdjęcia produktów, ceny, modne estetykiKonkurencyjne ceny, stany magazynowe oparte na trendach
MarketingWyniki tablic, zaangażowanie pinów, treści konkurencjiStrategia contentowa, benchmarki kampanii
Sprzedaż / lead genProfile twórców, liczba obserwujących, dane kontaktoweOutreach do influencerów, targetowanie partnerstw
NieruchomościPiny z home stagingiem, trendy w wystroju, układy pomieszczeńZdjęcia ofert, wskazówki dotyczące aranżacji
Twórcy treściTrendujące tematy, popularne formaty, sezonowe motywyKalendarz treści, analiza stylu wizualnego

A teraz sedno: oficjalne API Pinteresta jest mocno ograniczone. Wymaga konta firmowego, akceptacji (w tym wideoprezentacji aplikacji) i daje dostęp wyłącznie do danych własnego konta. Jeśli chcesz przeglądać publiczne tablice, wyniki wyszukiwania albo profile konkurencji, scraping jest praktyczną alternatywą. Dlatego tak wiele zespołów sięga po Pythona — albo po narzędzia no-code, takie jak Thunderbit, gdy zależy im na wynikach bez konfiguracji.

Dlaczego samo BeautifulSoup zawodzi na Pintereście i co naprawdę działa

Jeśli próbowałeś scrapować Pinteresta przez requests + BeautifulSoup i dostałeś 16 elementów albo pustą stronę, to nie wymyślasz sobie tego. Pinterest jest zbudowany w React i renderuje 100% treści przez JavaScript. Gdy pobierasz URL Pinteresta zwykłym żądaniem HTTP, serwer zwraca minimalny szkielet HTML — kilka tagów <link> i <script> oraz pusty <div>, w którym React dopiero montuje aplikację. Wszystkie karty pinów, obrazy, tytuły i układy siatki są wstrzykiwane dopiero po wykonaniu JavaScriptu w przeglądarce.

Brak wykonania JavaScriptu = brak pinów.

Co więc działa? Oto porównanie głównych podejść:

PodejścieObsługuje JS?Pobiera pełne dane?ZłożonośćNajlepsze do
requests + BeautifulSoupNie~0–16 elementówNiskaNie nadaje się do Pinteresta
Selenium / PlaywrightTakTak, z logiką przewijaniaŚredniaPełna kontrola, pipeline’y w Pythonie
Przechwycenie wewnętrznego API PinterestaTakTak, dane JSON z paginacjąWysokaMaksimum danych, bez przeglądarki
Zewnętrzne Scraper APITakZależnie od usługiNiskaSkalowanie bez własnej infrastruktury
Narzędzie no-code (Thunderbit)TakStrukturyzowane przez AIBardzo niskaOsoby nietechniczne, szybkie wyniki

Do tego poradnika polecam Playwright jako podejście w Pythonie. Renderuje JavaScript, obsługuje symulację przewijania, jest dobrze utrzymywany (78 600+ gwiazdek na GitHubie, wzrost liczby ofert pracy o 180% r/r) i jest 35–45% szybszy od Selenium w benchmarkach. Jeśli wolisz podejście no-code, też je omówię.

Oficjalne API Pinteresta vs. scraping w Pythonie vs. no-code: co wybrać?

Zanim zaczniesz pisać kod, warto zadać sobie pytanie: czy naprawdę musisz? Oto proste ramy decyzyjne:

KryteriumAPI PinterestaScraping w PythonieThunderbit (no-code)
Wymagana akceptacjaKonto firmowe + demo wideoBrakBrak
Dostęp do publicznych pinów/tablicOgraniczony (tylko własne dane)PełnyPełny
Pobieranie obrazów w pełnej rozdzielczościZależnie od danychTak, przez analizę URLTak, przez ekstrakcję obrazów
Obsługa nieskończonego przewijaniaNie dotyczyTak, z kodemAutomatycznie
KonserwacjaNiskaWysoka (selektory się psują)Brak (AI się dostosowuje)
Eksport do Sheets/AirtableRęcznyWłasny kodWbudowany
Czas konfiguracjiGodziny–dni30–60 min2 minuty

Jeśli jesteś marketerem, osobą od operacji e-commerce albo po prostu chcesz mieć dane z Pinteresta w arkuszu bez pisania i utrzymywania skryptów w Pythonie, Thunderbit AI Web Scraper to najszybsza opcja. Otwierasz dowolną stronę Pinteresta, klikasz „AI Suggest Fields”, naciskasz „Scrape” i eksportujesz dane bezpośrednio do Google Sheets, Excela, Airtable albo Notion. Funkcja scrapowania podstron może nawet automatycznie przechodzić do pojedynczych pinów, aby wzbogacić dane. Widziałem, jak osoby, które nigdy nie napisały ani linijki kodu, wyciągały ponad 500 pinów do Google Sheet w mniej niż trzy minuty.

Jeśli natomiast zależy Ci na pełnej kontroli, chcesz wpiąć scraping do pipeline’u w Pythonie albo po prostu lubisz budować rzeczy samodzielnie — czytaj dalej.

Konfiguracja środowiska Python do scrapowania Pinteresta

  • Poziom trudności: średni
  • Czas potrzebny: ok. 30–60 minut (łącznie z kodowaniem i testami)
  • Czego potrzebujesz: Python 3.9+, przeglądarka Chrome (do testów), dostęp do terminala / wiersza poleceń

Instalacja Playwright i zależności

Najpierw utwórz folder projektu i skonfiguruj środowisko wirtualne:

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

Zainstaluj Playwright i pobierz binarkę przeglądarki Chromium:

pip install playwright
playwright install chromium

Do eksportu danych użyjesz też wbudowanych modułów Pythona: json, os i csv. Nie trzeba nic dodatkowo instalować.

Struktura folderów projektu

Od początku warto zachować porządek:

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

W pliku config.py ustaw swój user agent. Pinterest blokuje domyślne sygnatury headless browserów, więc użyj realistycznej wartości:

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"

Krok 1: zbuduj adres URL wyszukiwania na Pintereście

Utwórz URL wyszukiwania, wstawiając zapytanie do szablonu:

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

Możesz to parametryzować dla dowolnej frazy. Parametr rs=typed mówi Pinterestowi, że zapytanie zostało wpisane ręcznie, a nie zasugerowane, co czasem wpływa na trafność wyników.

Krok 2: uruchom przeglądarkę headless i załaduj stronę

Oto podstawowa konfiguracja Playwright. Zwróć uwagę na własny user agent — bez niego Pinterest prawdopodobnie Cię zablokuje albo pokaże ekran logowania.

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)  # Czekamy, aż JavaScript wyrenderuje początkowe piny

Po wykonaniu tego kodu na stronie powinien pojawić się początkowy zestaw pinów — zwykle 25–50.

Krok 3: wyciągnij dane pinów ze strony

Pinterest opakowuje każdy pin w div z atrybutem data-test-id='pinWrapper'. W środku znajdziesz link (<a>) z adresem pinu i tytułem (przez aria-label) oraz element <img> z adresem miniatury.

        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
            })

Na tym etapie results zawiera piny widoczne w początkowym obszarze ekranu. Żeby pobrać więcej, trzeba przewijać — i to prowadzi nas do najważniejszej części.

Krok 4: zapisz wyniki do JSON lub CSV

Po ekstrakcji zapisz dane do plików, żeby łatwo z nich korzystać:

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)

Jeśli planujesz otwierać CSV w Excelu, używaj kodowania utf-8-sig — to zapobiega „krzakom” w znakach.

Scrapowanie całych tablic Pinteresta i profili użytkowników

To duża luka w istniejących poradnikach. Nie udało mi się znaleźć ani jednego konkurencyjnego przewodnika, który dogłębnie omawia scraping tablic albo profili — a to jedne z najczęściej proszonych funkcji na forach. Użytkownicy chcą pobierać wszystkie piny z tablicy, porządkować obrazy w folderach dla każdej tablicy i wyciągać dane na poziomie profilu, takie jak liczba obserwujących czy lista tablic.

Pobieranie wszystkich pinów z adresu URL tablicy

Adresy tablic mają postać https://www.pinterest.com/{username}/{board-name}/. Struktura DOM jest podobna do wyników wyszukiwania — piny są opakowane w div[data-test-id='pinWrapper'] — ale trzeba przewijać stronę, żeby załadować wszystkie elementy.

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):  # Limit bezpieczeństwa
            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"Przewinięcie {scroll_round + 1}: zebrano {len(all_pins)} unikalnych pinów")
            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  # Brak dalszej zawartości

        await browser.close()
        return all_pins

Na co uważać: strony tablic czasem mają zakładkę „More Ideas”, która oddziela zapisane piny od rekomendacji algorytmu. Jeśli chcesz tylko faktycznie zapisane piny użytkownika, przestań przewijać, gdy pojawi się ten separator.

Scrapowanie profilu użytkownika: tablice, liczba obserwujących i piny

Adresy profili mają formę https://www.pinterest.com/{username}/. Z poziomu profilu możesz wyciągnąć:

  • Liczbę obserwujących i obserwowanych: szukaj div[data-test-id='follower-count']
  • Listę tablic: każda tablica to karta z linkiem do /{username}/{board-name}/
  • Łączną liczbę pinów: czasami widoczną w nagłówku profilu
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)

        # Pobranie liczby obserwujących
        follower_el = await page.query_selector("div[data-test-id='follower-count']")
        followers = await follower_el.inner_text() if follower_el else "N/A"

        # Pobranie linków do tablic
        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}

Aby pobrać wszystkie piny ze wszystkich tablic profilu, przejdź po liście tablic i wywołaj scrape_board() dla każdej z nich. Możesz też automatycznie porządkować pobrane obrazy w folderach przypisanych do konkretnych tablic.

Budowa produkcyjnego handlera nieskończonego przewijania

To właśnie ten fragment odróżnia zabawkowy scraper od prawdziwego narzędzia. Główny problem — i widziałem go w co najmniej kilkunastu wątkach na forach — polega na tym, że scraper zwraca tylko 16–25 elementów, bo nie przewija wystarczająco długo albo używa stałej liczby przewinięć typu for i in range(5): scroll() i liczy na szczęście.

To podejście jest zawodne. Pinterest ładuje nowe treści partiami po około 25 pinów, uruchamianymi przez zdarzenia przewijania. Jeśli przewiniesz pięć razy, możesz dostać 125 pinów — albo 75, jeśli sieć działa wolno, albo 150, jeśli partie są mniejsze. Potrzebujesz mądrzejszego wzorca.

Wzorzec „przewijaj, dopóki nie pojawią się nowe treści”

Oto solidna funkcja przewijania, która śledzi unikalne ID pinów, używa konfigurowalnego timeoutu, ma logikę ponowień i pokazuje postęp:

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 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"  Przewinięcie {i+1}: {new_this_round} nowych pinów | {len(all_pins)} łącznie unikalnych pinów")

        if len(all_pins) >= max_pins:
            print(f"  Osiągnięto limit max_pins ({max_pins}). Zatrzymuję.")
            break

        if new_this_round == 0:
            no_new_count += 1
            if no_new_count >= 3:
                print("  Brak nowych pinów przez 3 kolejne przewinięcia. Koniec zawartości.")
                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("  Wysokość strony bez zmian i brak nowych pinów. Prawdopodobnie koniec feedu.")
            break

    return all_pins

Dlaczego to działa:

  • Usuwanie duplikatów po href: URL każdego pinu jest unikalny, więc używamy go jako identyfikatora. Zapobiega to liczeniu tego samego pinu dwa razy, gdy DOM renderuje się ponownie podczas przewijania.
  • Reguła trzech prób: Jeśli trzy kolejne przewinięcia nic nie dają, kończymy. To pomaga w sytuacji, gdy strona jeszcze ładuje dane, ale nie ma już nowej zawartości.
  • Losowe opóźnienie: Dodanie losowego opóźnienia 0,5–1,5 sekundy między przewinięciami sprawia, że zachowanie wygląda bardziej po ludzku i zmniejsza ryzyko wykrycia przez mechanizmy antybotowe.
  • Limit bezpieczeństwa liczby przewinięć: Chroni przed nieskończoną pętlą, jeśli coś pójdzie nie tak.

Obsługa przypadków brzegowych

  • Przerwanie przez „More Ideas”: Na stronach tablic Pinterest czasem wstawia sekcję „More Ideas”. Jeśli chcesz tylko faktyczne piny z tablicy, możesz wykryć ten element i zatrzymać przewijanie, gdy się pojawi.
  • Ograniczanie szybkości przy długich sesjach: Jeśli przewijasz tablicę z tysiącami pinów, Pinterest może zacząć ograniczać odpowiedzi. Jeśli zauważysz, że co jakiś czas przewijanie nie przynosi nowych pinów (ale nie trzy razy z rzędu), zwiększ pauzę przewijania do 5+ sekund.

Jak pobierać obrazy z Pinteresta w pełnej rozdzielczości, a nie miniatury

To właśnie ten problem doprowadza ludzi do szału. Scrapujesz sporo pinów, pobierasz obrazy i wszystkie są maleńkimi miniaturami 236 px. Na forach opisuje się to jako „słaba jakość, za mały rozmiar”. Rozwiązanie polega na zrozumieniu struktury URL-i obrazów Pinteresta.

Jak działa ścieżka do obrazów na Pintereście

Wszystkie obrazy Pinteresta są serwowane z https://i.pinimg.com/{size}/{hash}.jpg. Segment {size} określa rozdzielczość:

Ścieżka rozmiaruWymiaryZastosowanie
/236x/236 px szerokościDomyślny widok siatki (to, co dostajesz na start)
/474x/474 px szerokościŚrednia rozdzielczość
/736x/736 px szerokościWidok szczegółów pinu / powiększony podgląd
/originals/Oryginalne wymiary przesłaniaPełna rozdzielczość

Funkcja pomocnicza: podbij dowolny URL obrazu Pinteresta do pełnej rozdzielczości

Oto funkcja, która przepisuje dowolny URL obrazu Pinteresta do najwyższej dostępnej jakości, z logiką awaryjną:

import requests as req

def upgrade_image_url(url, preferred_size="originals"):
    """Przepisuje URL obrazu Pinteresta na najwyższą dostępną rozdzielczość."""
    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  # Zwracamy oryginał, jeśli wszystko zawiedzie

Ważna uwaga (stan na 2025 rok): ścieżka /originals/ coraz częściej zwraca błąd HTTP 403 Forbidden. Udokumentowany problem w gallery-dl potwierdza to zachowanie od połowy 2025 roku. Niezawodnym maksymalnym wariantem jest /736x/. Moja funkcja próbuje najpierw /originals/, a potem automatycznie przełącza się na /736x/.

Pobieranie obrazów do uporządkowanych folderów

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"  Pobrano {filename} ({len(resp.content) // 1024} KB)")
            else:
                print(f"  Nie udało się pobrać {filename}: HTTP {resp.status_code}")
        except Exception as e:
            print(f"  Błąd pobierania {filename}: {e}")
        time.sleep(delay + random.uniform(0.3, 0.8))

Dodaj opóźnienie między pobraniami. Ja używam 1,5–2,3 sekundy z losowym odchyleniem. Bez tego Pinterest po kilkuset żądaniach zacznie blokować Twój adres IP.

Eksport danych z Pinteresta

Eksport do CSV lub JSON

Podstawy omówiliśmy wcześniej. W przypadku większych zbiorów danych (10 000+ pinów) warto rozważyć format JSON Lines — jeden obiekt JSON w każdej linii — bo łatwiej go strumieniować i przetwarzać:

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")

Eksport do Google Sheets, Airtable lub Notion

Jeśli chcesz wysyłać dane bezpośrednio z Pythona do Google Sheets, potrzebujesz biblioteki gspread i konta serwisowego Google Cloud. Dla Airtable użyj pyairtable. Dla Notion — notion-client. Każde z tych rozwiązań wymaga konfiguracji API i znacząco zwiększa złożoność pipeline’u.

Albo — i tu jestem trochę stronniczy, ale to naprawdę najszybsza droga — możesz użyć Thunderbit, aby scrapować Pinteresta i wyeksportować dane do dowolnego z tych miejsc jednym kliknięciem. Bez kluczy API, bez kont serwisowych, bez dodatkowego kodu. Rozszerzenie Thunderbit do Chrome obsługuje eksport natywnie.

Jak uniknąć blokad podczas scrapowania Pinteresta

System antybotowy Pinteresta ma według ScrapeOps trudność obchodzenia ocenioną na [6/10] — nie jest banalny, ale też nie należy do najtrudniejszych. Wykorzystuje fingerprinting przeglądarki, analizę zachowania i limity oparte na IP. Oto co działa:

  • Rotuj user agenty: używaj puli prawdziwych ciągów user agent Chrome i losuj jeden na sesję.
  • Dodawaj losowe opóźnienia: 2–5 sekund między przewinięciami i żądaniami, z odchyleniem losowym. Bez proxy wydłuż do 10–15 sekund.
  • Używaj realistycznego viewportu: ustaw viewport={"width": 1920, "height": 1080} — nie używaj małych ani nietypowych wymiarów.
  • Rozważ proxy przy większej skali: jeśli scrapujesz tysiące pinów, rotuj proxy typu residential. Bez nich blokady IP są bardzo prawdopodobne po kilkuset żądaniach.
  • Szanuj robots.txt: robots.txt Pinteresta blokuje większość crawlerów i zawiera około 180 reguł disallow. Warto mieć to na uwadze pod kątem zgodności.
  • Unikaj scrapowania po zalogowaniu: trzymaj się publicznie widocznych treści, gdy jesteś wylogowany. Scrapowanie za logowaniem zwiększa zarówno ryzyko prawne, jak i techniczne.

Thunderbit automatycznie radzi sobie z antybotami i CAPTCHA dzięki swojemu silnikowi AI — to jedna rzecz mniej do utrzymywania, jeśli wybierzesz opcję no-code.

Aspekty prawne i etyczne scrapowania Pinteresta

Skrócę ten fragment, bo nie jest głównym tematem artykułu, ale jest ważny.

Warunki korzystania z Pinteresta (sekcja 2a) mówią, że zgadzasz się nie „scrapować, zbierać, przeszukiwać, kopiować ani w inny sposób uzyskiwać dostępu do danych lub treści z Pinteresta w nieautoryzowany sposób, na przykład przy użyciu środków automatycznych (bez naszej uprzedniej wyraźnej zgody)”. Jednocześnie sądy w wielu przypadkach uznawały, że scrapowanie publicznie dostępnych danych nie narusza Computer Fraud and Abuse Act — zobacz hiQ v. LinkedIn oraz Meta v. Bright Data (styczeń 2024), gdzie sąd orzekł, że scrapowanie publicznie widocznych danych przy wylogowaniu jest legalne.

Kilka zasad podstawowych:

  • Scrapuj wyłącznie publicznie widoczne treści i rób to po wylogowaniu
  • Nie wykorzystuj danych ze scrapingu do spamu ani do podszywania się pod użytkowników
  • Szanuj prawa autorskie do obrazów — jeśli to możliwe, pobieraj metadane i nie rozpowszechniaj komercyjnie chronionych obrazów bez zgody
  • Jeśli planujesz używać danych ze scrapingu komercyjnie, skonsultuj się z prawnikiem

Jeśli chcesz głębiej wejść w temat, zobacz nasz przewodnik po skutkach prawnych web scrapingu.

Podsumowanie: czego się nauczyłeś i co dalej

Teraz już wiesz, dlaczego statyczny scraping zawodzi na Pintereście (to aplikacja SPA w React — brak JavaScriptu, brak danych), jak używać Playwright do scrapowania wyników wyszukiwania, tablic i profili użytkowników, jak zbudować produkcyjny handler nieskończonego przewijania, który nie kończy pracy po 16 pinach, oraz jak pobierać obrazy w pełnej rozdzielczości zamiast malutkich miniaturek.

Krótka powtórka najważniejszych rzeczy:

  • requests + BeautifulSoup nie zadziała na Pintereście. Nie trać na to czasu.
  • Playwright to najlepsze narzędzie w Pythonie do tego zadania — szybkie, dobrze wspierane i natywnie obsługujące renderowanie JS.
  • Nieskończone przewijanie wymaga pętli opartej na usuwaniu duplikatów, a nie stałej liczby przewinięć.
  • Obrazy w pełnej rozdzielczości wymagają przepisywania ścieżki URL — celuj w /736x/ (bo /originals/ często zwraca 403).
  • Scraping tablic i profili jest słabo opisany w istniejących poradnikach, ale z odpowiednimi selektorami jest całkiem prosty.
  • Dla osób nietechnicznych i zespołów, którym zależy na szybkości, Thunderbit pozwala scrapować Pinteresta w 2 kliknięcia i eksportować dane do Google Sheets, Excela, Airtable albo Notion — bez Pythona. Wypróbuj za darmo przez rozszerzenie Chrome.

Jeśli budujesz pipeline w Pythonie, kod z tego poradnika daje Ci solidny fundament. Jeśli po prostu potrzebujesz danych, Thunderbit jest skrótem. W obu przypadkach nie utkniesz już z 16 pinami i pustym spojrzeniem.

Więcej o scrapowaniu i ekstrakcji danych znajdziesz w naszych poradnikach: jak scrapować strony internetowe w Pythonie, najlepsze automatyczne narzędzia do web scrapingu oraz jak pobierać dane ze strony do Excela. Możesz też sprawdzić cennik Thunderbit albo obejrzeć materiały na kanale Thunderbit na YouTube.

FAQ

1. Czy da się scrapować Pinteresta przy użyciu BeautifulSoup?

Nie skutecznie samym BeautifulSoup. Pinterest renderuje całą treść przez JavaScript, więc requests + BeautifulSoup widzi tylko pusty szkielet HTML. Najpierw potrzebujesz headless browsera, takiego jak Playwright lub Selenium, który wyrenderuje stronę, albo możesz użyć narzędzia no-code, takiego jak Thunderbit, które automatycznie obsługuje renderowanie JS.

2. Ile pinów można pobrać z Pinteresta w jednej sesji?

To zależy od logiki przewijania i obsługi antybota. Przy produkcyjnym handlerze nieskończonego przewijania z tego poradnika (deduplikacja, timeout, retry) możesz niezawodnie pobierać od setek do tysięcy pinów na tablicę albo na zapytanie wyszukiwania. W przypadku bardzo dużych tablic licz się z kilkoma minutami przewijania i zbierania danych.

3. Dlaczego pobrane obrazy z Pinteresta są takie małe?

Domyślnie Pinterest serwuje miniatury /236x/ w widoku siatki. Aby uzyskać wyższą rozdzielczość, przepisz ścieżkę URL obrazu na /736x/ albo /originals/. Pamiętaj jednak, że /originals/ coraz częściej zwraca błędy 403 w 2025 roku, więc /736x/ to najbardziej niezawodny maksymalny wariant.

4. Czy scrapowanie Pinteresta jest legalne?

Scraping publicznie dostępnych danych jest generalnie akceptowany na podstawie nowszych orzeczeń sądowych (np. hiQ v. LinkedIn, Meta v. Bright Data), ale regulamin Pinteresta zabrania nieautoryzowanego, automatycznego dostępu. Trzymaj się treści publicznych, nie używaj danych do spamu, szanuj prawa autorskie i skonsultuj zastosowania komercyjne z prawnikiem.

5. Jaka jest najlepsza alternatywa no-code do scrapowania Pinteresta?

Thunderbit AI Web Scraper potrafi wyciągać dane pinów z Pinteresta — tytuły, obrazy, URL-e, opisy — w 2 kliknięcia, z wbudowanym eksportem do Google Sheets, Excela, Airtable albo Notion. Obsługuje renderowanie JavaScriptu, nieskończone przewijanie i mechanizmy antybotowe automatycznie, więc nie musisz pisać ani utrzymywać kodu.

Dowiedz się więcej

Shuai Guan
Shuai Guan
CEO w Thunderbit | Ekspert ds. automatyzacji danych AI Shuai Guan jest CEO Thunderbit oraz absolwentem wydziału inżynierii University of Michigan. Czerpiąc z niemal dekady doświadczenia w branży technologicznej i architekturze SaaS, specjalizuje się w przekuwaniu złożonych modeli AI w praktyczne, niewymagające kodowania narzędzia do استخراج danych. Na tym blogu dzieli się szczerymi, sprawdzonymi w boju spostrzeżeniami na temat web scrapingu i strategii automatyzacji, które pomogą Ci tworzyć mądrzejsze, oparte na danych procesy pracy. Gdy nie optymalizuje przepływów danych, z tą samą dbałością o szczegóły oddaje się swojej pasji do fotografii.
Spis treści

Zbierz dane ze strony, po prostu o to prosząc

Powiedz, czego potrzebujesz, prostym angielskim. A najlepiej: nie mów nic.

Wypróbuj Thunderbit darmowe
Wyodrębniaj dane dzięki AI
Łatwo przenoś dane do Google Sheets, Airtable lub Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week