Scrapowanie danych – jak zacząć web scraping w JavaScript

Oskar Gajzler
Przez
Oskar Gajzler
Redaktor IINTE.edu.pl, na co dzień zajmuje się technologiami internetowymi i tłumaczeniem skomplikowanych tematów na prosty język. Pisze poradniki o tym, jak załatwiać sprawy przez internet, jak...
12 min czytania

1. Czym jest web scraping i kiedy ma sens?

Web scraping to proces automatycznego pobierania kodu HTML strony i wyciągania z niego interesujących danych (np. ceny, tytuły artykułów, listy produktów).

Najczęstsze zastosowania:

  • monitorowanie cen i ofert,
  • agregatory ogłoszeń, wydarzeń, newsów,
  • badania rynku i analiza konkurencji,
  • analiza treści (SEO, słowa kluczowe, trendy),
  • zasilanie własnych aplikacji i narzędzi danymi z sieci.

Do prostych stron statycznych wystarczy pobranie HTML i parsowanie Cheerio.

Do stron z dynamicznym JavaScriptem użyj Puppeteera, który uruchamia prawdziwą przeglądarkę Chrome w trybie bezgłowym (headless).

2. Aspekty prawne i etyczne scrapowania

Zanim napiszesz jakikolwiek kod:

  1. Sprawdź regulamin serwisu (terms of service) – niektóre witryny wyraźnie zabraniają scrapingu;
  2. Zajrzyj do robots.txt – to plik wskazujący, które sekcje są przeznaczone do indeksowania przez boty; nie jest to prawo, ale ważna wskazówka;
  3. Szanuj infrastrukturę serwisu – nie rób dziesiątek zapytań na sekundę, wstawiaj opóźnienia między żądaniami;
  4. Dane osobowe – jeśli zbierasz dane, które mogą identyfikować osoby, obowiązują cię przepisy RODO; unikaj gromadzenia i przechowywania danych wrażliwych.

Ten poradnik skupia się na stronie technicznej, ale w praktyce miej podstawową świadomość prawno‑etyczną.

3. Wybór podejścia – fetch + cheerio czy puppeteer?

Dla JavaScript / Node.js masz dwa podstawowe style scrapowania:

PodejścieKiedy używaćZaletyWady
HTTP client + Cheerio (fetch / Axios + Cheerio)Strony statyczne (HTML od razu w odpowiedzi)Szybkie, lekkie, mało zasobożerneNie wykonuje JS, nie widzi treści generowanej w przeglądarce
PuppeteerStrony dynamiczne z JS, SPA, React, Vue itp.Renderuje stronę jak Chrome, obsługuje JS i logowanieWolniejsze, cięższe, zużywa więcej RAM/CPU

Rekomendacja na start:

Zacznij od fetch + Cheerio (lżejsze, prostsze) i przejdź do Puppeteera tylko wtedy, gdy to konieczne.

Sięgnij po Puppeteer, gdy:

  • dane pojawiają się dopiero po kilku sekundach,
  • trzeba kliknąć, przewinąć, zalogować się lub zaakceptować cookies,
  • HTML odpowiedzi nie zawiera interesujących danych, bo ładuje je JS z API.

4. Przygotowanie środowiska (Node.js)

4.1. Instalacja Node.js

  1. Pobierz instalator z oficjalnej strony Node.js (LTS).
  2. Po instalacji w terminalu (PowerShell / CMD / bash) uruchom:

node -v
npm -v

Jeśli obie komendy zwracają wersje – środowisko jest gotowe.

5. Minimalny scraper – fetch + cheerio (statyczna strona)

Pokażę typowy workflow:

  • utworzenie projektu,
  • instalacja potrzebnych paczek,
  • pobranie HTML,
  • parsowanie i wyciągnięcie danych,
  • zapis do pliku.

5.1. Tworzenie projektu i instalacja zależności

W terminalu wykonaj kolejno:

mkdir web-scraping-javascript
cd web-scraping-javascript
npm init -y

Zainstaluj zależności (klient HTTP + parser HTML):

npm install axios cheerio

Możesz też użyć wbudowanego w Node 20+ fetch i tylko Cheerio:

npm install cheerio

W pliku package.json ustaw typ modułów:

{
"type": "module"
}

Dzięki temu możesz używać import zamiast require.

5.2. Najprostszy przykład scrapera z Cheerio

Utwórz plik scrape.js z poniższą zawartością:

import axios from "axios";
import * as cheerio from "cheerio";
import { writeFileSync } from "fs";

const URL = "https://przykladowa-strona.pl/blog";

async function scrape() {
try {
// 1. Pobierz HTML strony
const response = await axios.get(URL);
const html = response.data;

// 2. Załaduj HTML do Cheerio
const $ = cheerio.load(html);

// 3. Wybierz elementy za pomocą selektorów CSS
const articles = [];
$(".article-card").each((_, el) => {
const title = $(el).find(".article-title").text().trim();
const link = $(el).find("a").attr("href");
const date = $(el).find(".article-date").text().trim();
articles.push({ title, link, date });
});

// 4. Zapisz dane do JSON
writeFileSync("articles.json", JSON.stringify(articles, null, 2), "utf-8");
console.log(`Zapisano ${articles.length} artykułów do articles.json`);
} catch (err) {
console.error("Błąd scrapera:", err.message);
}
}

scrape();

Uruchom w terminalu:

node scrape.js

To ta sama logika, co w przewodnikach Cheerio + klient HTTP: pobierasz HTML i wyciągasz elementy przez selektory CSS.

6. Jak znaleźć właściwe selektory CSS (DevTools)

Kluczem do skutecznego scrapowania jest poprawne wskazanie elementów, które chcesz pobrać.

  1. Otwórz stronę w Chrome/Firefox.
  2. Kliknij prawym → „Zbadaj” (Inspect), aby otworzyć DevTools.
  3. W panelu Elements sprawdź strukturę interesujących cię elementów.

Najeżdżaj myszką na fragment, który chcesz zebrać (np. tytuł artykułu), aby zlokalizować go w drzewie DOM.

Sprawdź tag (np. h2, a, span) i klasy (np. class="article-title"), które ułatwią selekcję.

  1. Spróbuj z tymi selektorami CSS:
  • .article-title – wszystkie elementy z tą klasą,
  • .article-card .article-title – .article-title wewnątrz .article-card,
  • a.article-title – linki z klasą article-title.

Cheerio obsługuje znaną z przeglądarki składnię: .find(), .text(), .attr(), .each() itd.

7. Scrapowanie dynamicznej strony – Puppeteer

Jeśli strona ładuje dane dopiero po wykonaniu JS, użycie samego fetch/axios zwróci „goły” HTML bez danych. Wtedy wchodzą do gry przeglądarki headless – np. Puppeteer.

7.1. Instalacja Puppeteer i konfiguracja projektu

W nowym katalogu (lub tym samym, jeśli chcesz) wykonaj:

mkdir web-scraping-puppeteer
cd web-scraping-puppeteer
npm init -y
npm install puppeteer

To standardowa instalacja Puppeteera.

7.2. Podstawowy scraper z Puppeteer

Utwórz plik index.js i wklej kod:

import puppeteer from "puppeteer";
import { writeFileSync } from "fs";

const URL = "https://przykladowa-strona.pl/wydarzenia";

async function scrape() {
// 1. Uruchom przeglądarkę
const browser = await puppeteer.launch({
headless: "new", // nowy tryb headless w nowszych wersjach
});

try {
const page = await browser.newPage();

// 2. Przejdź na stronę
await page.goto(URL, {
waitUntil: "networkidle2", // czekaj aż większość żądań się zakończy
});

// 3. Poczekaj explicite na kluczowy element (bezpieczniej)
await page.waitForSelector(".event-card");

// 4. Wyciągnij dane w kontekście przeglądarki
const events = await page.evaluate(() => {
const cards = document.querySelectorAll(".event-card");
const data = [];

cards.forEach((card) => {
const title = card.querySelector(".event-title")?.textContent?.trim() || "";
const date = card.querySelector(".event-date")?.textContent?.trim() || "";
const link = card.querySelector("a")?.href || "";
data.push({ title, date, link });
});

return data;
});

// 5. Zapis do pliku
writeFileSync("events.json", JSON.stringify(events, null, 2), "utf-8");
console.log(`Zapisano ${events.length} wydarzeń do events.json`);
} catch (e) {
console.error("Błąd scrapera:", e);
} finally {
await browser.close();
}
}

scrape();

Wzorzec pracy z Puppeteer to: launch → newPage → goto → evaluate.

8. Radzenie sobie z typowymi problemami

8.1. Lazy loading / infinite scroll

Gdy strona ładuje kolejne elementy podczas przewijania, użyj automatycznego scrollowania:

async function autoScroll(page) {
await page.evaluate(async () => {
await new Promise((resolve) => {
let totalHeight = 0;
const distance = 400;

const timer = setInterval(() => {
const scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;

if (totalHeight >= scrollHeight - window.innerHeight) {
clearInterval(timer);
resolve();
}
}, 400);
});
});
}

Wywołanie w kodzie:

await autoScroll(page);

Następnie dopiero wykonaj page.evaluate() i zbierz dane.

8.2. Czekanie na JS / API

Zamiast statycznych timeoutów stosuj warunki czekania na elementy lub odpowiedzi sieciowe.

await page.waitForSelector(".product-list-item"); // bardziej niezawodne

Możesz też nasłuchiwać gotowych XHR/fetch w zakładce Network (DevTools), aby zrozumieć, kiedy dane są dostępne.

9. Zapisywanie danych – JSON, CSV

JSON masz w przykładach wyżej. Aby generować CSV, zainstaluj json2csv i skorzystaj z poniższego wzorca:

Instalacja:

npm install json2csv

Przykład użycia CSV (kontynuacja scrapa z Cheerio):

import { writeFileSync } from "fs";
import { Parser } from "json2csv";

function saveAsCSV(data, fileName) {
const parser = new Parser();
const csv = parser.parse(data);
writeFileSync(fileName, csv, "utf-8");
}

// po zebraniu danych:
saveAsCSV(articles, "articles.csv");

10. Dobre praktyki – jak scrapować „po ludzku”

  1. Dodaj User-Agent

    Niektóre strony blokują domyślne UA. W Axios ustaw nagłówek:


    const response = await axios.get(URL, {

    headers: {

    "User-Agent": "Mozilla/5.0 (compatible; MyScraper/1.0; +https://twojadomena.pl)"

    }

    });


    W Puppeteer ustaw UA dla strony:


    await page.setUserAgent("Mozilla/5.0 (compatible; MyScraper/1.0; +https://twojadomena.pl)");


  2. Ogranicz rate (throttling)

    Wstawiaj krótkie przerwy między żądaniami:


    const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

    await sleep(1000); // 1 sek. przerwy


  3. Loguj błędy i statusy

    Obsługuj kody HTTP 4xx/5xx i czytelnie loguj, który URL aktualnie przetwarzasz.


  4. Waliduj i czyść dane

    Stosuj trim(), zamieniaj formaty liczb (np. „1 234,56 zł” → 1234.56) i usuwaj zbędne znaki.


  5. Testuj selektory

    Gdy strona zmieni klasę lub strukturę, scraper przestanie działać – dodaj testy sprawdzające np. czy liczba znalezionych elementów jest większa od zera.


11. Frameworki i narzędzia, gdy projekt rośnie

Jeśli scraper ma spełniać bardziej złożone wymagania, zwróć uwagę na poniższe obszary:

  • przechodzenie przez wiele stron (crawling),
  • zarządzanie kolejkami URL-i,
  • rotacja proxy, retry, harmonogram uruchomień.

W takich przypadkach warto użyć gotowych rozwiązań:

  • Crawlee – framework od Apify do budowy crawlerów w JS;
  • Platformy scrapingowe – np. Apify, SerpApi; rozwiązują kwestie IP, proxy i harmonogramu;
  • Biblioteki do HTTP/HTML – Axios + Cheerio (lekki standard), Got.

12. Prosty mini‑projekt krok po kroku (gotowy przykład)

Załóżmy, że chcesz zbudować mały scraper listy artykułów z polskiego bloga technologicznego (strona statyczna, bez dynamicznego JS).

12.1. Kroki

  1. W DevTools sprawdzasz, że każdy wpis ma strukturę:

<article class="post">
<h2 class="post-title"><a href="/artykul-1">Tytuł 1</a></h2>
<time class="post-date">2026-05-10</time>
</article>

  1. W terminalu przygotuj projekt i zainstaluj paczki:

mkdir blog-scraper
cd blog-scraper
npm init -y
npm install axios cheerio json2csv

  1. Utwórz scrape-blog.js z poniższym kodem:

import axios from "axios";
import * as cheerio from "cheerio";
import { writeFileSync } from "fs";
import { Parser } from "json2csv";

const URL = "https://przykladowy-blog.pl/";

async function scrapeBlog() {
try {
const response = await axios.get(URL, {
headers: {
"User-Agent": "Mozilla/5.0 (compatible; BlogScraper/1.0)"
}
});

const $ = cheerio.load(response.data);
const posts = [];

$("article.post").each((_, el) => {
const title = $(el).find(".post-title").text().trim();
const link = $(el).find(".post-title a").attr("href");
const date = $(el).find(".post-date").text().trim();

posts.push({
title,
link: link?.startsWith("http") ? link : new URL(link, URL).href,
date,
});
});

// zapis JSON
writeFileSync("posts.json", JSON.stringify(posts, null, 2), "utf-8");

// zapis CSV
const parser = new Parser();
const csv = parser.parse(posts);
writeFileSync("posts.csv", csv, "utf-8");

console.log(`Zebrano ${posts.length} postów`);
} catch (err) {
console.error("Błąd scrapera:", err.message);
}
}

scrapeBlog();

  1. Uruchom skrypt:

node scrape-blog.js

Po chwili pojawią się pliki posts.json i posts.csv, gotowe do analizy w Excelu lub do wgrania do bazy danych.

13. Jak się dalej rozwijać?

Jeśli chcesz pójść głębiej, zrób kilka małych projektów i stopniowo dodawaj funkcje:

  • Przerób kilka różnych stron – np. statyczny blog (Cheerio) oraz sklep z dynamiczną listą produktów (Puppeteer);
  • Dodaj:
    • obsługę paginacji (przechodzenie po kolejnych stronach „1, 2, 3…”),
    • harmonogram uruchamiania (np. cron raz dziennie),
    • prostą bazę danych (SQLite, Postgres) zamiast plików.

Dzięki połączeniu Node.js + Cheerio + Puppeteer obsłużysz większość typowych scenariuszy web scrapingu w JavaScript.

Udostępnij ten artykuł
Obserwuj
Redaktor IINTE.edu.pl, na co dzień zajmuje się technologiami internetowymi i tłumaczeniem skomplikowanych tematów na prosty język. Pisze poradniki o tym, jak załatwiać sprawy przez internet, jak bezpiecznie korzystać z sieci i jak dobierać sprzęt oraz oprogramowanie. Prywatnie tropi nowinki technologiczne i testuje je, zanim opisze.
Brak komentarzy

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *