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).
- 1. Czym jest web scraping i kiedy ma sens?
- 2. Aspekty prawne i etyczne scrapowania
- 3. Wybór podejścia – fetch + cheerio czy puppeteer?
- 4. Przygotowanie środowiska (Node.js)
- 5. Minimalny scraper – fetch + cheerio (statyczna strona)
- 6. Jak znaleźć właściwe selektory CSS (DevTools)
- 7. Scrapowanie dynamicznej strony – Puppeteer
- 8. Radzenie sobie z typowymi problemami
- 9. Zapisywanie danych – JSON, CSV
- 10. Dobre praktyki – jak scrapować „po ludzku”
- 11. Frameworki i narzędzia, gdy projekt rośnie
- 12. Prosty mini‑projekt krok po kroku (gotowy przykład)
- 13. Jak się dalej rozwijać?
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:
- Sprawdź regulamin serwisu (terms of service) – niektóre witryny wyraźnie zabraniają scrapingu;
- 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; - Szanuj infrastrukturę serwisu – nie rób dziesiątek zapytań na sekundę, wstawiaj opóźnienia między żądaniami;
- 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ście | Kiedy używać | Zalety | Wady |
|---|---|---|---|
| HTTP client + Cheerio (fetch / Axios + Cheerio) | Strony statyczne (HTML od razu w odpowiedzi) | Szybkie, lekkie, mało zasobożerne | Nie wykonuje JS, nie widzi treści generowanej w przeglądarce |
| Puppeteer | Strony dynamiczne z JS, SPA, React, Vue itp. | Renderuje stronę jak Chrome, obsługuje JS i logowanie | Wolniejsze, 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
- Pobierz instalator z oficjalnej strony Node.js (LTS).
- 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ć.
- Otwórz stronę w Chrome/Firefox.
- Kliknij prawym → „Zbadaj” (Inspect), aby otworzyć DevTools.
- 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ę.
- Spróbuj z tymi selektorami CSS:
.article-title– wszystkie elementy z tą klasą,.article-card .article-title–.article-titlewewną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”
- 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)"); - 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 - Loguj błędy i statusy
Obsługuj kody HTTP 4xx/5xx i czytelnie loguj, który URL aktualnie przetwarzasz.
- Waliduj i czyść dane
Stosuj
trim(), zamieniaj formaty liczb (np. „1 234,56 zł” → 1234.56) i usuwaj zbędne znaki. - 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
- 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>
- W terminalu przygotuj projekt i zainstaluj paczki:
mkdir blog-scraper
cd blog-scraper
npm init -y
npm install axios cheerio json2csv
- 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();
- 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.








