Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. Boshlashdan oldin: tekshiruv ro'yxati
- 3. Statik HTML: cheerio
- 3.1 Sinov sahifasi
- 3.2 cheerio bilan o'qish
- 3.3 Narx va regex alternativasi
- 4. JavaScript bilan chiziladigan sahifalar: Playwright
- 5. So'rov yuborish: odob bilan
- 5.1 fetch va User-Agent
- 5.2 Sahifalar va tezlik cheklovi
- 6. robots.txt
- 6.1 Nima va qayerda
- 6.2 O'z tahlilchimiz
- 7. Etika va huquq
- 7.1 To'rt qoida
- 7.2 O'zbekiston: O'RQ-547
- 7.3 Hech qachon qilmang
- 8. CLI qadami: holat yo'q — scraping kerak emas
- 9. Ko'p uchraydigan xatolar
- 9.1 Natija bo'sh massiv
- 9.2 Selektor bir kun ishlamay qoldi
- 9.3 HTTP 403 yoki 429
- 9.4 Kodirovka buzildi
- 9.5 Narx sondek ko'rinadi, lekin satr
- 10. Mashqlar
- 1-mashq (oson): ruxsatmi?
- 2-mashq (o'rta): narxni tozalash
- 3-mashq (qiyin): xushmuomala o'rgimchak
- 11. Real ishda
- Xulosa
- Manbalar
Web scraping Node.js'da: cheerio, robots.txt, tezlik va huquqiy chegaralar
Qisqacha: Web scraping — sahifaning HTML kodidan ma'lumotni dastur bilan ajratib olish. Node'da statik sahifa uchun
fetch+ cheerio (jQuery'ga o'xshash selektorlar), JavaScript bilan chiziladigan sahifa uchun — Playwright (haqiqiy brauzer). Lekin birinchi qoida — skreyp qilishdan oldin API bormi tekshiring: CBU kurslarini JSON API beradi, scraping kerak emas. Skreyp qilsangiz —robots.txtva sayt shartlariga rioya qiling, so'rovlar orasida pauza qiling, o'zingizniUser-Agentbilan tanishtiring va shaxsiy ma'lumotni yig'mang (O'zbekistonda O'RQ-547).
Bu darsda
- Scraping'dan oldin nimani tekshirish kerakligini (API, robots.txt, shartlar) ketma-ket ayta olasiz.
- cheerio bilan lokal HTML'dan jadvalni o'qiysiz va nega regex mo'rt ekanini ko'rasiz.
- Statik sahifa va JavaScript bilan chiziladigan sahifa farqini va Playwright qachon kerakligini bilasiz.
- Sahifalarni ketma-ket o'qiydigan (pagination) va tezlikni cheklaydigan async generator yozasiz.
robots.txtni o'zingiz tahlil qilasiz va huquqiy-etik chegaralarni tushuntira olasiz.
Oldin bilishingiz kerak: Built-in fetch va undici, Async iteratorlar va Web Streams, Playwright I: e2e testlar asoslari, Analitika: foydalanuvchi xatti-harakatini o'lchash.
1. Nega bu kerak?
Ma'lumot doim qulay shaklda kelmaydi. Bozor narxlari — faqat sayt jadvalida. Universitet qabul kvotalari — PDF va HTML sahifada. O'zingizning eski blogingiz — eksport tugmasi yo'q. Bunday hollarda dastur sahifani o'qiydi va kerakli bo'lakni ajratadi. Bu — web scraping (veb-qirqib olish).
Lekin scraping — eng oxirgi yo'l. Sabablari:
- Mo'rt. Sayt dizayni o'zgarsa, kodingiz jim buziladi.
- Og'ir. HTML ichida keraksiz narsa ko'p, API'dagi JSON esa aniq.
- Huquqiy savollar. Sayt bunga ruxsat bermagan bo'lishi mumkin.
valyuta loyihasi aynan shu tanlovdan boshlangan: cbu.uz saytida kurslar jadvali bor. Uni skreyp qilish mumkin edi. Lekin CBU ochiq JSON API beradi — kalitsiz va hujjatlangan manzil bilan. Kanon API'ni tanladi, scraping esa faqat tajriba bo'lib qoldi.
O'xshatish: kutubxona. Kitobning elektron nusxasi bo'lsa — uni olasiz (API). Bo'lmasa — kerakli sahifalarni o'zingiz ko'chirasiz (scraping). Ko'chirishda ham qoidalar bor: o'quv zalidan chiqarmaslik, butun kitobni nusxalamaslik, boshqalarga xalaqit bermaslik.
2. Boshlashdan oldin: tekshiruv ro'yxati
flowchart TD
A["Ma'lumot kerak"] --> B{"Rasmiy API yoki eksport bormi?"}
B -- "ha" --> C["API'ni ishlating"]
B -- "yo'q" --> D{"robots.txt va shartlar ruxsat beradimi?"}
D -- "yo'q" --> E["To'xtang yoki egasidan ruxsat so'rang"]
D -- "ha" --> F{"Shaxsiy ma'lumot bormi?"}
F -- "ha" --> G["Yig'mang yoki qonuniy asos va rozilik"]
F -- "yo'q" --> H["Sekin, o'z User-Agent bilan skreyp"]Nimaga qarang: "kod yozish" faqat eng pastda. Undan oldin uchta savol — texnik emas, odob va qonun savollari. Ularni keyinroq batafsil ko'ramiz.
3. Statik HTML: cheerio
3.1 Sinov sahifasi
Haqiqiy saytni skreyp qilmadik — bu darsdagi hamma tajriba lokal fayl bilan. Kanonda CBU JSON javobidan (74 valyuta) HTML jadval yasalgan. Darsda uning kichik nusxasi, kurslar.html:
<!doctype html>
<html lang="uz">
<body>
<h1>Valyuta kurslari — 23.10.2026</h1>
<table class="kurslar">
<tr><th>Kod</th><th>Nomi</th><th>Kurs</th></tr>
<tr><td>USD</td><td>AQSH dollari</td>
<td data-nominal="1">11903.15</td></tr>
<tr><td>EUR</td><td>EVRO</td>
<td data-nominal="1">13329.15</td></tr>
<tr><td>IDR</td><td>Indoneziya rupiyasi</td>
<td data-nominal="10">6.59</td></tr>
</table>
<a class="keyingi" href="?sahifa=2">Keyingi</a>
</body>
</html>data-nominal — IDR kursi 10 birlik uchun berilgan (CBU API'dagi Nominal maydoni kabi). Bitta rupiya narxini olish uchun bo'lish kerak.
3.2 cheerio bilan o'qish
cheerio — HTML'ni tahlil qilib, uni jQuery uslubidagi selektorlar bilan so'rash imkonini beradi. Brauzer yo'q, JavaScript bajarilmaydi — faqat matn tahlili. Shuning uchun tez.
import { readFile } from "node:fs/promises";
import * as cheerio from "cheerio";
const html = await readFile("kurslar.html", "utf8");
const $ = cheerio.load(html);
console.log($("h1").text());
const kurslar = $("table.kurslar tr")
.slice(1) // sarlavha qatori kerak emas
.map((_, tr) => {
const td = $(tr).find("td");
const nominal = Number(td.eq(2).attr("data-nominal"));
return {
kod: td.eq(0).text(),
kurs: Number(td.eq(2).text()) / nominal,
};
})
.get();
console.log(kurslar);
console.log("keyingi:", $("a.keyingi").attr("href"));Biz cheerio 1.2.0 va Node 24.21.0 bilan ishga tushirdik:
Valyuta kurslari — 23.10.2026
[
{ kod: 'USD', kurs: 11903.15 },
{ kod: 'EUR', kurs: 13329.15 },
{ kod: 'IDR', kurs: 0.659 }
]
keyingi: ?sahifa=2nocheck — blok cheerio paketini va lokal faylni talab qiladi. Qadamlar:
| Kod | Nima qiladi |
|---|---|
cheerio.load(html) |
HTML'ni daraxtga aylantiradi, $ — so'rov funksiyasi |
$("table.kurslar tr") |
CSS selektor — brauzerdagi querySelectorAll kabi |
.slice(1) |
birinchi (sarlavha) qatorni tashlash |
.eq(2), .text(), .attr() |
uchinchi katak, uning matni, atributi |
.get() |
cheerio to'plamidan oddiy massiv |
CSS selektorlarni Elementlarni tanlash va CSS darslarida o'rgangansiz — bu yerda aynan o'sha bilim. Brauzer DevTools'da "Copy selector" bilan boshlash mumkin, lekin uzun avtomatik selektor (body > div:nth-child(3) > …) mo'rt — ma'noli sinf yoki atributga tayaning.
3.3 Narx va regex alternativasi
Kanon o'lchovi (t51-kutubxona.txt, t54-scraping.txt): cheerio 1.2.0 — 23 paket, 6.1 MB, import +239.7 ms. 74 qatorli jadvalni o'qish 46.8 ms. Bu — o'lchangan CLI kutubxonalari ichida eng og'iri.
Xuddi shu jadvalni bitta regex bilan ham o'qish mumkin edi — kanonda u ham 74 qator topdi. Lekin regex HTML tuzilishini emas, aniq matnni kutadi: <td data-nominal="1">. Sayt atributlar tartibini almashtirsa (<td class="raqam" data-nominal="1">) yoki qator bo'lsa — regex jim nolta natija beradi. cheerio esa tuzilma bo'yicha qidiradi va bunday o'zgarishga chidaydi.
Tekshirib ko'ring: Nega cheerio JavaScript bilan chiziladigan sahifada (React ilova) bo'sh natija beradi?
Javob
cheerio faqat serverdan kelgan HTML matnini o'qiydi va JavaScript'ni bajarmaydi. React ilovada server ko'pincha bo'sh <div id="root"></div> va skript yuboradi — jadval brauzerda, JS ishlagandan keyin paydo bo'ladi. cheerio uchun u yerda jadval yo'q. Bunday sahifaga haqiqiy brauzer kerak (keyingi bo'lim) — yoki sahifa ma'lumotni qaysi API'dan olayotganini DevTools'ning Network panelida topib, o'shani ishlatish.
4. JavaScript bilan chiziladigan sahifalar: Playwright
Playwright ni 22-qismda testlar uchun o'rgangansiz. U scraping uchun ham ishlaydi: haqiqiy brauzerni ochadi, JS bajariladi, keyin DOM'dan o'qiysiz:
import { chromium } from "playwright";
const brauzer = await chromium.launch();
const sahifa = await brauzer.newPage({
userAgent: "valyuta-darslik/1.0 (+https://example.com/aloqa)",
});
await sahifa.goto("https://example.com/kurslar");
await sahifa.waitForSelector("table.kurslar tr");
const kodlar = await sahifa
.locator("table.kurslar td:first-child")
.allTextContents();
console.log(kodlar);
await brauzer.close();Bu kod hujjat bo'yicha — biz uni ishga tushirmadik (example.com da bunday jadval yo'q; npm view bo'yicha playwright 1.64.1, 2026-10-23). Narxi katta: brauzerning o'zi yuzlab MB, har sahifa — soniyalar. Shuning uchun tartib: avval yashirin API'ni qidiring (Network panel → Fetch/XHR), topilmasa — Playwright.
Puppeteer — xuddi shu vazifadagi boshqa kutubxona (faqat Chrome/Firefox). Ikkalasi ham bir xil prinsipda ishlaydi.
5. So'rov yuborish: odob bilan
5.1 fetch va User-Agent
Built-in fetch darsidagi fetch scraping uchun yetarli. Ikki qo'shimcha:
const javob = await fetch("https://example.com/kurslar", {
headers: {
"user-agent": "valyuta-darslik/1.0 (+https://example.com/aloqa)",
},
signal: AbortSignal.timeout(10_000),
});
if (!javob.ok) throw new Error(`HTTP ${javob.status}`);
const html = await javob.text();User-Agent— o'zingizni tanishtirish. Sukut bo'yicha Nodenodedeb yuboradi. Sayt egasi logda "kim bu?" deb so'rasa, aloqa manzili bo'lsin.valyutaham holat 46 dan berivalyuta/<versiya> (Node.js <versiya>)yuboradi — CBU loglarida kim so'rayotgani ko'rinadi. Brauzer qiyofasiga kirish (Chrome User-Agent'ini ko'chirish) — aldash, buni qilmang.- Vaqt chegarasi — osilib qolgan so'rov skriptni to'xtatmasin.
5.2 Sahifalar va tezlik cheklovi
Ma'lumot ko'pincha bir nechta sahifada: "Keyingi" havolasi orqali. Sahifalarni ketma-ket o'qiydigan async generator yozamiz. Tarmoq o'rniga — soxta sahifaniOl (u ham 5 ms "kutadi"):
const kut = (ms) => new Promise((r) => setTimeout(r, ms));
const SAHIFALAR = {
1: { kurslar: ["USD", "EUR"], keyingi: 2 },
2: { kurslar: ["RUB", "GBP"], keyingi: 3 },
3: { kurslar: ["JPY"], keyingi: null },
};
async function sahifaniOl(n) {
await kut(5); // soxta tarmoq
return SAHIFALAR[n];
}
async function* hammaKurslar(boshi, oraliqMs, chegara = 50) {
let n = boshi;
for (let soni = 0; n !== null && soni < chegara; soni++) {
if (soni > 0) await kut(oraliqMs); // xushmuomala pauza
const s = await sahifaniOl(n);
console.log(`sahifa ${n}: ${s.kurslar.length} ta`);
yield* s.kurslar;
n = s.keyingi;
}
}
const t0 = Date.now();
const hammasi = [];
for await (const k of hammaKurslar(1, 200)) hammasi.push(k);
console.log(hammasi.join(", "));
console.log("kamida 400 ms:", Date.now() - t0 >= 400);Konsolda:
sahifa 1: 2 ta
sahifa 2: 2 ta
sahifa 3: 1 ta
USD, EUR, RUB, GBP, JPY
kamida 400 ms: trueBu blok saytda ham ishlaydi — «Ishga tushir» bilan sinang. Uch himoya bor:
- Pauza (
oraliqMs) — sahifalar orasida 200 ms. Haqiqiy saytda bir necha soniya bo'lishi kerak. Sizning skriptingiz — bitta, sayt esa minglab foydalanuvchiga xizmat qiladi. Pauzasiz skript sayt uchun hujumdan farq qilmaydi. - Chegara (
chegara = 50) — "Keyingi" havolasi aylana bo'lsa (3-sahifa yana 1 ga qaytsa), skript abadiy aylanmaydi. - Ketma-ketlik —
for awaitkeyingi sahifani faqat oldingisi tugagach so'raydi.Promise.allbilan 100 sahifani birdan so'rash — tez, lekin saytga zarba.
Tekshirib ko'ring: Sayt
429 Too Many Requestsjavobini vaRetry-After: 30sarlavhasini qaytardi. Skript nima qilishi kerak?
Javob
To'xtashi va kamida 30 soniya kutishi kerak — sayt aniq aytdi: "sekinroq". Keyin pauzani oshirib davom etish mumkin. Bir necha marta takrorlansa — butunlay to'xtash. timers darsidagi qayta urinish (qaytaUrin) shu yerda kerak bo'ladi, lekin kutish vaqtini sayt belgilaydi, siz emas.
6. robots.txt
6.1 Nima va qayerda
robots.txt — saytning ildizida (https://sayt/robots.txt) turgan oddiy matn fayl: avtomatik dasturlarga (botlarga) qaysi yo'llarga kirish mumkin emasligini aytadi. 2022 yil sentyabrida u standart bo'ldi — RFC 9309 (Robots Exclusion Protocol). RFC'ning o'zi aytadi: bu qoidalar kirish huquqini nazorat qilish vositasi emas. Ya'ni robots.txt — texnik to'siq emas, eshikdagi yozuv. Lekin uni e'tiborsiz qoldirish — odobsizlik va ko'p hollarda shartlarni buzish.
RFC 9309 dan yana to'rt amaliy qoida:
| Holat | RFC 9309 bo'yicha |
|---|---|
| robots.txt javobi 4xx (masalan 404) | fayl yo'q — botga hamma yo'l ochiq |
| javob 5xx yoki server javob bermaydi | to'liq taqiq deb hisoblang |
| keshlash | 24 soatdan uzoq eski nusxaga tayanmang |
Crawl-delay |
standartda yo'q — ba'zi botlar o'qiydi, lekin majburiy emas |
Kanon cbu.uz ning robots.txt ini bir marta o'z User-Agent bilan so'radi (t54-scraping.txt): 29 ta Disallow qoidasi, Crawl-delay yo'q. Natija: JSON API yo'li /uz/arkhiv-kursov-valyut/json/ — ruxsat; /bitrix/admin/ va /uz/?print=Y — taqiq. Kanon tekshiruvchisi soddalashtirilgan edi: faqat User-agent: * guruhi va faqat Disallow, Allow hisobga olinmagan — buni halol aytamiz.
6.2 O'z tahlilchimiz
Endi to'liqroq versiya: guruhlar, Allow, * naqshi va RFC 9309 qoidasi — eng uzun mos qoida yutadi. Namuna fayl (o'ylab topilgan, haqiqiy saytniki emas):
const robots = `
User-agent: *
Disallow: /bitrix/
Disallow: /*?print=
Disallow: /qidiruv/
Allow: /qidiruv/yordam/
User-agent: BadBot
Disallow: /
`;
// faqat "User-agent: *" guruhining qoidalari
function qoidalarniOl(matn) {
const qoidalar = [];
let bizniki = false;
for (const xom of matn.split(/\r?\n/)) {
const qator = xom.split("#")[0].trim();
const [kalit, ...qolgan] = qator.split(":");
const qiymat = qolgan.join(":").trim();
const k = kalit.toLowerCase();
if (k === "user-agent") bizniki = qiymat === "*";
const qoidami = k === "allow" || k === "disallow";
if (bizniki && qoidami && qiymat) {
qoidalar.push({ ruxsat: k === "allow", yol: qiymat });
}
}
return qoidalar;
}
function naqshgaMos(yol, naqsh) {
const re = naqsh
.replace(/[.+?^${}()|[\]\\]/g, "\\$&")
.replace(/\*/g, ".*");
return new RegExp("^" + re).test(yol);
}
function ruxsatmi(yol, qoidalar) {
// eng uzun mos qoida yutadi; teng bo'lsa — Allow (RFC 9309)
let eng = null;
for (const q of qoidalar) {
if (!naqshgaMos(yol, q.yol)) continue;
const uzunroq = !eng || q.yol.length > eng.yol.length;
const teng = eng && q.yol.length === eng.yol.length;
if (uzunroq || (teng && q.ruxsat)) eng = q;
}
return eng ? eng.ruxsat : true;
}
const qoidalar = qoidalarniOl(robots);
const yollar = ["/uz/kurslar/", "/bitrix/admin/", "/uz/?print=Y",
"/qidiruv/?q=usd", "/qidiruv/yordam/"];
for (const yol of yollar) {
const javob = ruxsatmi(yol, qoidalar) ? "ruxsat" : "TAQIQ";
console.log(yol.padEnd(18), javob);
}Konsolda:
/uz/kurslar/ ruxsat
/bitrix/admin/ TAQIQ
/uz/?print=Y TAQIQ
/qidiruv/?q=usd TAQIQ
/qidiruv/yordam/ ruxsatOxirgi qatorga qarang: /qidiruv/ taqiqlangan, lekin /qidiruv/yordam/ uchun uzunroq Allow bor — u yutdi. Kanondagi soddalashtirilgan tekshiruvchi bu yo'lni "TAQIQ" der edi. Uzunligi bir xil Allow va Disallow mos kelsa, RFC Allow ni tanlashni tavsiya qiladi — teng && q.ruxsat sharti shu uchun. naqshgaMos ichidagi birinchi replace — maxsus belgilarni (RegExp asoslari) oddiy belgiga aylantiradi, ikkinchisi * ni "har qanday belgilar"ga.
Bu tahlilchi hali to'liq emas: $ (yo'l oxiri) belgisi, aniq User-agent: valyuta guruhi va Crawl-delay yo'q. Haqiqiy loyihada tayyor kutubxonadan foydalaning yoki RFC 9309 ni to'liq o'qing.
7. Etika va huquq
7.1 To'rt qoida
- Shartlar (Terms of Service). Ko'p saytlar foydalanish shartlarida avtomatik yig'ishni taqiqlaydi. robots.txt ruxsat bersa ham, shartlar taqiqlasa — taqiq. Shubha bo'lsa, egasiga yozing.
- Tezlik. Sayt sizniki emas — uning serveri va trafikiga pul to'lanadi. Pauza, kechasi ishlash, keshlash (bir sahifani ikki marta so'ramaslik).
- Mualliflik huquqi. Ma'lumotni o'qish bir narsa, matn va rasmlarni o'z saytingizda qayta e'lon qilish — boshqa narsa. Faktlar (kurs, narx) va ijodiy matn (maqola) har xil himoyalanadi.
- Shaxsiy ma'lumot. Ism, telefon, email, rasm, manzil — hatto ochiq sahifada turgan bo'lsa ham.
7.2 O'zbekiston: O'RQ-547
Analitika darsida "Shaxsga doir ma'lumotlar to'g'risida"gi Qonun (O'RQ-547, 2019) bilan tanishgansiz. Unga ko'ra shaxsga doir ma'lumotni yig'ish va qayta ishlash uchun subyektning roziligi yoki boshqa qonuniy asos kerak, fuqarolar ma'lumoti O'zbekistondagi serverlarda saqlanishi talab qilinadi (2021 yildagi o'zgartirish). Scraping bilan odamlar ro'yxatini (masalan, e'lonlar saytidan telefon raqamlarini) yig'ish — rozilik yo'q, demak xavfli hudud. Bu yuridik maslahat emas: aniq holatda huquqshunos bilan gaplashing.
Qisqa qoida: odam haqidagi ma'lumotni skreyp qilmang. Kerak bo'lsa — rasmiy API va foydalanuvchining roziligi orqali.
7.3 Hech qachon qilmang
- Login ortidagi sahifalarni boshqa birovning hisobi bilan skreyp qilish.
- CAPTCHA va bot himoyasini aylanib o'tish — sayt "yo'q" degan.
- IP'ni almashtirib cheklovdan qochish.
- Saytni sekinlashtiradigan tezlikda so'rov yuborish.
Diqqat: Bu bo'limdagi qoidalar faqat "qo'lga tushmaslik" uchun emas. Kichik sayt — ko'pincha bitta odamning arzon serveri. Sizning tez skriptingiz uni yiqitishi va egasiga pul to'lattirishi mumkin. Birovning uyiga mehmon bo'lib kirgandek ish tuting.
8. CLI qadami: holat yo'q — scraping kerak emas
valyuta scraping qilmaydi. Kanon tajribasi (t54-scraping.txt): CBU JSON API beradi — birinchi qoida ("avval API") bajarildi. Tajribada robots.txt bir marta o'qildi. Lokal HTML fixture esa cheerio bilan o'qildi. Natija: 74 qator, 46.8 ms, IDR 1 birlik = 0.659. cbu.uz ning HTML sahifalari skreyp qilinmadi. cheerio kanonga kirmadi: kerak emas va +239.7 ms, 6.1 MB.
valyuta dan saqlab qolgan odob: o'z User-Agent (holat 46) va kesh (bitta kurs bir soatda bir marta so'raladi, o'tgan sanalar — umuman qayta so'ralmaydi). Commit yo'q.
9. Ko'p uchraydigan xatolar
9.1 Natija bo'sh massiv
Sahifa JavaScript bilan chiziladi yoki server sizga boshqa HTML beradi (masalan, "botlar uchun" sahifa). html ni faylga yozib, ichiga qarang — jadval bormi?
9.2 Selektor bir kun ishlamay qoldi
Dizayn o'zgardi. Himoya: natija soni kutilganidan kam bo'lsa (kurslar.length < 10) — xato bilan to'xtash, jim bo'sh fayl yozmaslik.
9.3 HTTP 403 yoki 429
403 — "sizga ruxsat yo'q" (ko'pincha bot sezildi), 429 — "juda tez". Ikkalasi ham sayt aniq gapirdi: to'xtang. Yechim — sekinlashish yoki ruxsat so'rash, chetlab o'tish emas.
9.4 Kodirovka buzildi
Eski saytlar windows-1251 yoki boshqa kodirovkada. javob.text() UTF-8 deb o'qiydi — kirill harflari buziladi. Content-Type sarlavhasidagi charset ni tekshiring va TextDecoder("windows-1251") bilan o'qing.
9.5 Narx sondek ko'rinadi, lekin satr
"11 903,15" — bo'shliq va vergul. Number(...) → NaN. Avval tozalang: bo'shliqlarni olib tashlang, vergulni nuqtaga almashtiring — va natijani tekshiring.
10. Mashqlar
Mashqlar kurs/mashqlar/24/54-scraping/ da.
1-mashq (oson): ruxsatmi?
Quyidagi robots.txt bo'yicha har yo'lga "ruxsat" yoki "taqiq" deb javob bering (biz User-agent: * guruhidamiz):
User-agent: *
Disallow: /admin/
Disallow: /e-lonlar/
Allow: /e-lonlar/toifalar//e-lonlar/12345/e-lonlar/toifalar/avto/admin/narxlar/
Yechim
- Taqiq —
/e-lonlar/mos keladi,Allowmos emas. - Ruxsat — ikkala qoida mos, lekin
Allow: /e-lonlar/toifalar/uzunroq. - Ruxsat — qoida
/admin/(oxirida/), yo'l esa/admin. Prefiks mos emas. Sayt egasi buni nazarda tutmagan bo'lishi mumkin — lekin robots.txt so'zma-so'z o'qiladi. Odob bilan: shubhali bo'lsa, kirmang. - Ruxsat — hech bir qoida mos emas.
2-mashq (o'rta): narxni tozalash
Saytlarda narxlar har xil yozilgan: "11 903,15", "11903.15 so'm", "6,59", "—". narxniOqi(matn) funksiyasini yozing: bo'shliqlarni (oddiy va uzilmas) olib tashlasin, vergulni nuqtaga almashtirsin, raqam, nuqta va minusdan boshqa belgilarni olib tashlasin va son qaytarsin. Son chiqmasa — null. Yordam: replace va /[^\d.-]/g (RegExp asoslari), Number.isFinite.
Yechim
function narxniOqi(matn) {
const toza = matn
.replace(/\s/g, "")
.replace(",", ".")
.replace(/[^\d.-]/g, "");
if (toza === "" || toza === "-") return null;
const son = Number(toza);
return Number.isFinite(son) ? son : null;
}
const misollar = ["11 903,15", "11903.15 so'm", "6,59", "—",
"-62,36"];
for (const m of misollar) {
console.log(JSON.stringify(m), "→", narxniOqi(m));
}Konsolda:
"11 903,15" → 11903.15
"11903.15 so'm" → 11903.15
"6,59" → 6.59
"—" → null
"-62,36" → -62.36"—" (uzun tire) — ma'lumot yo'q belgisi: null qaytardik, 0 emas. Nol — bu "kurs nolga teng", null — "bilmaymiz"; ularni aralashtirish hisobotni buzadi. Saytlar raqam guruhlari orasiga ko'pincha uzilmas bo'shliq (\u00a0) qo'yadi. Oddiy " " uni topmaydi, JavaScript'dagi \s esa uni ham oladi.
3-mashq (qiyin): xushmuomala o'rgimchak
«Sahifalar va tezlik cheklovi» dagi generatorni kengaytiring: oqiganlar to'plami (Set) bilan bir sahifani ikki marta so'ramasin (aylana havolalar), har sahifadan oldin ruxsatmi(yol) funksiyasini chaqirsin va taqiqlangan sahifani o'tkazib yuborib, taqiq: /sahifa/3 deb yozsin. Sahifalar: /sahifa/1 → /sahifa/2 → /sahifa/3 → /sahifa/1 (aylana); /sahifa/3 taqiqlangan bo'lsin, lekin uning keyingi havolasiga borish uchun uni o'qish kerak — demak o'rgimchak shu yerda to'xtaydi. Pauza 50 ms. Yordam: Set ning has/add (Set).
Yechim
const kut = (ms) => new Promise((r) => setTimeout(r, ms));
const SAYT = {
"/sahifa/1": { kurslar: ["USD"], keyingi: "/sahifa/2" },
"/sahifa/2": { kurslar: ["EUR", "RUB"], keyingi: "/sahifa/3" },
"/sahifa/3": { kurslar: ["GBP"], keyingi: "/sahifa/1" },
};
const ruxsatmi = (yol) => yol !== "/sahifa/3";
async function* orgimchak(boshi, oraliqMs) {
const oqiganlar = new Set();
let yol = boshi;
while (yol && !oqiganlar.has(yol)) {
if (!ruxsatmi(yol)) {
console.log("taqiq:", yol);
return;
}
if (oqiganlar.size > 0) await kut(oraliqMs);
oqiganlar.add(yol);
const s = SAYT[yol];
console.log("o'qildi:", yol);
yield* s.kurslar;
yol = s.keyingi;
}
if (yol) console.log("aylana:", yol);
}
const natija = [];
for await (const k of orgimchak("/sahifa/1", 50)) natija.push(k);
console.log(natija);Konsolda:
o'qildi: /sahifa/1
o'qildi: /sahifa/2
taqiq: /sahifa/3
[ 'USD', 'EUR', 'RUB' ]Taqiqlangan sahifaga yetganda o'rgimchak to'xtadi — GBP yo'q, va bu to'g'ri: biz u sahifani o'qishga haqli emasmiz. Agar /sahifa/3 ruxsat bo'lganida, keyingi havola /sahifa/1 ga qaytardi va oqiganlar uni ushlab, aylana: /sahifa/1 deb to'xtatardi. Ikkala himoya — robots va aylana — haqiqiy o'rgimchaklarda ham bor.
11. Real ishda
- Narx monitoringi va agregatorlar: bozorlar va do'konlar narxini kuzatish — scraping'ning eng keng tarqalgan qonuniy qo'llanishi. Ko'p hollarda ular hamkorlik orqali API yoki ma'lumot oqimi oladi.
- Ma'lumotlar bazasini to'ldirish: ilmiy tadqiqot, ochiq hukumat ma'lumotlari (data.gov.uz kabi ochiq ma'lumotlar portallari odatda API va yuklab olish beradi — avval shuni qidiring).
- Testlar va monitoring: o'z saytingizning sahifalarini tekshirish (havolalar buzilmadimi, sarlavhalar bormi) — bu ham texnik jihatdan scraping, lekin o'z mulkingiz.
- Intervyu: "Saytdan ma'lumot kerak — qanday yondashasiz?" Yaxshi javob API'dan boshlanadi, robots.txt va shartlar bilan davom etadi, kodni oxirida aytadi.
Xulosa
- Scraping — oxirgi yo'l: avval API, eksport yoki egasining ruxsati.
- Statik HTML —
fetch+ cheerio (23 paket, +239.7 ms); JS bilan chiziladigan sahifa — Playwright yoki yashirin API. - Regex HTML uchun mo'rt; tuzilma bo'yicha selektor ishonchliroq.
- Sahifalar — async generator, pauza, sahifalar chegarasi va aylanaga qarshi
Set. - robots.txt (RFC 9309): eng uzun mos qoida yutadi; u ruxsat bersa ham, shartlar va qonun ustun.
- Shaxsiy ma'lumotni skreyp qilmang — O'zbekistonda O'RQ-547 rozilik talab qiladi.
Keyingi dars: CLI'ni tarqatish — valyuta v1.0.0: npx, README va LICENSE, versiya chiqarish, update-notifier va bitta exe fayl (SEA).
Manbalar
- RFC 9309 — Robots Exclusion Protocol (2022-09; 2.2.2 eng aniq moslik va Allow, 2.3.1 javob kodlari, 2.4 kesh): https://www.rfc-editor.org/rfc/rfc9309
- cheerio hujjati: https://cheerio.js.org
- Playwright hujjati: https://playwright.dev
- O'zbekiston Respublikasining "Shaxsga doir ma'lumotlar to'g'risida"gi Qonuni (O'RQ-547): https://lex.uz
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!