Web scraping-ul poate părea intimidant la început, dar, ca orice abilitate, se învață cel mai bine prin practică directă. În aceste prime trei capitole, vom explora fundamentele extragerii de date din pagini HTML statice.
Capitolul 1: Chad-ul scraping-ului HTML
Călătoria noastră începe cu cel mai simplu scenariu posibil - extragerea textului dintr-o pagină HTML de bază. Acest capitol te introduce în conceptele de bază ale:
- Efectuării de request-uri HTTP pentru a prelua pagini web
- Încărcării conținutului HTML într-un parser
- Selecției DOM de bază folosind selectori CSS
Deși exemplul poate părea trivial (până la urmă e doar un „hello world”!), el stabilește fundația pentru tot ce urmează.
<!-- Example HTML structure -->
<div class="content">
<p>Some text we want to extract</p>
</div>
Iată o mostră din ce avem de lucru:
// Basic concepts (not the solution!)
import * as cheerio from 'cheerio';
// Loading HTML content
const $ = cheerio.load(htmlContent);
// Using CSS selectors
const text = $('p').text(); // Selects all <p> tags
const specific = $('.content p').text(); // More specific selection
Capitolul 2: Date structurate
Lucrurile devin mai interesante când intrăm într-o pagină de produs mock de e-commerce. Aici ne confruntăm cu mai multe elemente cu structuri similare:
<!-- Example product structure (simplified) -->
<div class="product">
<h2>Product Name</h2>
<span class="price">$99.99</span>
<div class="specs">
<ul>
<li>Size: M</li>
<li>Color: Blue</li>
</ul>
</div>
</div>
Când lucrezi cu date structurate de acest tip, e bine să te gândești la:
// Conceptual approach (not the solution!)
$('.product').each((index, element) => {
// For each product, we might want to:
// 1. Extract the basic info
const name = $(element).find('h2').text();
// 2. Parse nested data
const specs = $(element).find('.specs li');
// 3. Structure the output
const data = {
name,
specs: specs.map(/* ... */),
};
});
Sfat util: Înainte să scrii orice cod, ia-ți timp să analizezi structura HTML. Caută tipare în modul în care sunt organizate datele - există nume de clase consecvente? Cum sunt relaționate elementele părinte și copil?
Capitolul 3: Scraping asistat de AI
Acum lucrurile devin interesante! Dacă provocările anterioare ne-au învățat tehnici tradiționale de scraping, Capitolul 3 introduce o abordare modernă: web scraping asistat de AI. Ne confruntăm cu un scenariu de coșmar - structuri HTML inconsistente, nume de clase ofuscate și mai multe tipare de framework amestecate laolaltă.
Hai să vedem ce face această provocare specială:
<!-- Traditional product structure -->
<div data-testid="product-container-1" class="_3xj_item">
<h2 data-qa="name">Red Sneakers</h2>
<span data-price-current="5999">$59.99</span>
</div>
<!-- React-style component -->
<div class="ProductCard-root-1a2b3c">
<div class="ProductCard-title-4d5e6f">Pink Walking Shoes</div>
<div class="ProductCard-pricing-7g8h9i">$84.99</div>
</div>
<!-- Vue-style template -->
<div data-v-abcdef class="product">
<h2 data-v-abcdef>Navy Boat Shoes</h2>
<span data-v-abcdef>$79.99</span>
</div>
Abordările tradiționale de scraping s-ar chinui aici pentru că:
- Numele claselor sunt randomizate sau specifice framework-ului
- Structurile de date variază între produse
- Framework-uri diferite folosesc tipare diferite
- Sensul semantic se pierde în markup
Aici intervine AI-ul. În loc să scriem selectori fragili, putem descrie în limbaj natural ce ne dorim și să lăsăm AI-ul să se ocupe de recunoașterea tiparelor. Conceptele-cheie din acest capitol includ:
- Prompt engineering pentru web scraping
- Folosirea AI-ului pentru a înțelege sensul semantic
- Gestionarea structurilor de date inconsistente
- Lucrul cu markup specific diferitelor framework-uri
- Menținerea consistenței datelor între tipare diferite
Deși AI-ul nu este magie, excelează la sarcini care cer recunoaștere de tipare și adaptare. Asta îl face deosebit de valoros pentru scraping-ul aplicațiilor web moderne, unde tiparele de markup consecvente nu pot fi garantate.
O notă despre utilizarea AI
Ține minte că asistența AI nu înseamnă soluții complet automatizate. Cele mai bune rezultate vin din combinarea dintre:
- Definirea clară a problemei
- Prompt-uri bine structurate
- Validarea datelor
- Supraveghere umană
Provocarea ta va fi să construiești prompt-uri care ajută AI-ul să înțeleagă atât structura, cât și intenția a ceea ce încerci să extragi.
Ești gata să combini cunoștințele tradiționale de web scraping cu capabilități moderne de AI? Hai să vedem cum poate AI-ul să ajute la abordarea chiar și a celui mai haotic HTML!
Indicii
- Experimentează cu diferiți selectori CSS:
// Different ways to select elements
$('.class') // By class
$('#id') // By ID
$('div > p') // Direct children
$('div p') // All descendants
$('[data-type="x"]') // By attribute
- Încearcă să modifici formatul output-ului
- Gândește-te la tratarea erorilor și la cazurile-limită
- Ia în calcul cum s-ar putea scala soluția ta pentru seturi de date mai mari
Tot codul de care ai nevoie ca să începi se află în repository-ul proiectului. Clonează-l, configurează-ți mediul și începe să faci scraping!
git clone https://github.com/jonaylor89/housefly.git
cd housefly
npm install
Pornește local serverele capitolelor — fiecare capitol rulează pe propriul port (3001–3011):
turbo dev
Apoi editează scraper-ul tău în exercises/chapter-NN/starter/src/index.ts și validează-l:
npm run validate -- <chapter>
Cauți indicii? Rulează npm run hint -- <chapter> pentru ghidare progresivă. HTML-ul sursă pentru fiecare provocare este disponibil în directorul apps/chapter{n}/, iar soluțiile de referință sunt în exercises/chapter-NN/solution/src/. Studiază structura, planifică-ți abordarea și ține minte - orice expert a fost cândva începător.
Nu uita să tratezi request-urile în mod responsabil:
// Basic error handling example
async function fetchPage(url: string) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.text();
} catch (error) {
console.error('Failed to fetch page:', error);
throw error;
}
}
Spor la scraping!