TypeScript वेब स्क्रैपिंग: चीरियो और नोड के साथ टाइपेड एक्सट्रैक्शन
Web Data Collection Specialist
TL;DR:
- नोड 22
node --experimental-strip-typesके साथ सीधे TypeScript को चलाता है, इसलिए एक स्क्रैपर को कोई निर्माण चरण और कोई बंडलर की आवश्यकता नहीं होती है। fetchरनटाइम में निर्मित है, जिससे HTML पार्सिंग और CSS चयन के लिएcheerioएकमात्र निर्भरता बचती है।- आप जो रिकॉर्ड निकालते हैं उसका टाइपिंग एक स्क्रैपर को बनाए रखने के लिए महत्वपूर्ण है: कंपाइलर उस बिंदु पर पुनः नामांकित फ़ील्ड को चिह्नित करता है जब इसे उपभोग किया जाता है, इसके बजाय कि डेटा पहले से ही डाउनस्ट्रीम चला गया हो।
- प्रकार उस आकार का वर्णन करते हैं जिसकी आप अपेक्षा करते हैं, न कि उस पृष्ठ की जिसे आपने प्राप्त किया — क्लाइन्ट-रेन्डर्ड पृष्ठ अभी भी एक वैध प्रतिक्रिया लौटाता है जो शून्य रिकॉर्ड में पार्स होता है।
- स्क्रैपलेस यूनिवर्सल स्क्रैपिंग एपीआई पहले पृष्ठ को रेंडर करता है, और उसी अपरिवर्तित
cheerioचयनकर्ता तब सभी 10 रिकॉर्ड लौटाते हैं। - स्क्रैपलेस मुफ्त योजना पर शुरू करें और पिवट उदाहरण को अपने लक्षित पृष्ठ पर इंगित करें।
TypeScript को स्क्रैपर में अपनी जगह मिलती है एक कारण के लिए: डेटा जिसे आप निकालते हैं उसका एक आकार होता है, और वह आकार कमजोर होता है। एक साइट एक फ़ील्ड का पुनः नामकरण करती है, एक चयनकर्ता एक खाली स्ट्रिंग लौटाना शुरू करता है, और एक साधारण जावास्क्रिप्ट स्क्रैपर इसे चुपचाप जो कुछ भी इसे उपभोग करता है, में ले जाता है। एक टाइप किया हुआ रिकॉर्ड इसे एक संकलन त्रुटि में बदल देता है।
हाल ही में जो परिवर्तन हुआ है वह सेटअप की लागत है। नोड 22 ने स्वाभाविक रूप से प्रकारों को हटा दिया है, इसलिए कोई tsc चरण नहीं है, कोई बंडलर नहीं है, और निर्भरता पेड़ में कोई ts-node नहीं है।
आपको क्या चाहिए
2026 में TypeScript वेब स्क्रैपिंग के लिए नोड 22 या इसके बाद का संस्करण और एकमात्र निर्भरता चाहिए। नीचे दिए गए संस्करण वे हैं जिन पर ये उदाहरण चलाए गए:
| घटक | संस्करण | कार्य |
|---|---|---|
| Node.js | 22.22.3 | रनटाइम, स्वदेशी fetch, स्वदेशी प्रकार छानना |
cheerio |
1.2.0 | HTML पार्सिंग और CSS चयनकर्ता |
fetch रनटाइम में निर्मित है, इसलिए इसे कोई आयात और कोई HTTP पुस्तकालय की आवश्यकता नहीं है। cheerio एक पार्स किए गए दस्तावेज़ पर jQuery-आकार के एपीआई की पेशकश करता है, जो नोड पारिस्थितिकी तंत्र में सर्वर-साइड HTML क्वेरींग के लिए मानक के सबसे करीबी चीज है। यह HTML पार्सिंग विशिष्टता के अनुसार पार्स करता है, न कि मार्कअप को टेक्स्ट के रूप में पैटर्न के खिलाफ मिलाने के लिए।
इंस्टॉल करें
प्रोजेक्ट बनाएं और एकमात्र निर्भरता जोड़ें:
bash
mkdir ts-scraper && cd ts-scraper
npm init -y
npm pkg set type=module
npm install cheerio@1.2.0
type=module सेटिंग महत्वपूर्ण है: नीचे दिए गए उदाहरण टॉप-लेवल await का उपयोग करते हैं, जिसके लिए ES मोड्यूल सिंटैक्स की आवश्यकता होती है।
एक टाइप किया हुआ रिकॉर्ड निकालें
पहले आकार को घोषित करें, फिर निष्कर्षण को इसे उत्पन्न करने के लिए बनाएं। कंपाइलर आपको इसके लिए रोकेगा:
typescript
import * as cheerio from "cheerio";
interface Quote {
text: string;
author: string;
tags: string[];
}
const res = await fetch("https://quotes.toscrape.com/");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const $ = cheerio.load(await res.text());
const quotes: Quote[] = $("div.quote")
.map((_, el) => ({
text: $(el).find("span.text").text(),
author: $(el).find("small.author").text(),
tags: $(el).find("a.tag").map((_, t) => $(t).text()).get(),
}))
.get();
console.log(`quotes parsed: ${quotes.length}`);
console.log(JSON.stringify(quotes[0], null, 2));
इसे बिना निर्माण चरण के चलाएं:
bash
node --experimental-strip-types static.ts
text
quotes parsed: 10
{
"text": "“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”",
"author": "Albert Einstein",
"tags": [
"change",
"deep-thoughts",
"thinking",
"world"
]
}
वहाँ तीन चीजें वास्तविक काम कर रही हैं।
quotes पर Quote एनोटेशन यह सुनिश्चित करता है कि .map() कॉलबैक का प्रकार चेक किया गया है। एक ऑब्जेक्ट लौटाएं जिसमें tags गायब है, या इसे tag लिखें, और त्रुटि उस पंक्ति पर आएगी न कि बाद में इसे उपभोग करने पर undefined के रूप में।
res.ok वह चेक है जिसे लोग छोड़ देते हैं। fetch 404 या 403 पर बाहर नहीं फेंकता - यह सामान्य रूप से हल करता है और ok को false पर सेट करता है, और त्रुटि पृष्ठ शून्य मेल पर सीधे पार्स होता है जैसे कि एक खाली परिणाम। इस तरह व्यवहार करने वाली स्थिति श्रेणियाँ HTTP अर्थशास्त्र विशिष्टता में परिभाषित की गई हैं।
सन्निहित .map(...).get() cheerio का पदयात्रा है चयन को वास्तविक ऐरे में बदलने के लिए। आंतरिक कॉल टैग स्ट्रिंगों को इकट्ठा करती है, ताकि tags string[] के रूप में आए न कि एक cheerio ऑब्जेक्ट के रूप में।
जहाँ प्रकार मदद करना बंद करते हैं
एक प्रकार उस रिकॉर्ड का वर्णन करता है जिसकी आप अपेक्षा करते हैं, न कि उस पृष्ठ की जिसे आपने प्राप्त किया। न तो fetch और न ही cheerio जावास्क्रिप्ट चलाते हैं, इसलिए एक पृष्ठ पर जो अपने सामग्री को ब्राउज़र में बनाता है, चयनकर्ता कुछ भी मेल नहीं खाते और प्रकार एक खाली ऐरे द्वारा संतुष्ट होते हैं।
उपरोक्त साइट /js/ पर समान डेटा का एक क्लाइन्ट-रेन्डर्ड जुड़वां प्रकाशित करती है। वही पार्सिंग कोड, उस पर इंगित:
typescript
import * as cheerio from "cheerio";
const res = await fetch("https://quotes.toscrape.com/js/");
text
यदि (!res.ok) तो नई त्रुटि फेंकें(`HTTP ${res.status}`);
const html = await res.text();
const $ = cheerio.load(html);
console.log(`html बाइट्स: ${html.length}`);
console.log(`उद्धरणों की संख्या: ${$("div.quote").length}`);
text
html बाइट्स: 5806
उद्धरणों की संख्या: 0
अनुरोध सफल था, res.ok सही था, और 5,806 वर्णों का मान्य HTML बिना किसी शिकायत के पार्स किया गया। Quote[] एक पूरी तरह से सही टाइप वाला खाली सरणी है। यह विफलता का मोड है जिसकी योजना बनानी चाहिए, क्योंकि प्रकार प्रणाली या HTTP परत में से कुछ भी इसे रिपोर्ट नहीं करता है - उद्धरण मार्कअप एक स्क्रिप्ट चलने के बाद DOM में लिखा गया है।
पहले रेंडर करें, फिर पार्स करें
Scrapeless Universal Scraping API इस अंतर को बंद करता है जिससे पृष्ठ को क्लाउड ब्राउज़र में रेंडर किया जाता है और परिणामी HTML लौटाया जाता है, ताकि TypeScript की ओर एक टाइप किया हुआ fetch कॉल बना रहे।
अपनी कुंजी सेट करें:
bash
export SCRAPELESS_API_KEY="your_api_key_here"
सिर्फ़ फ़ेच परत में परिवर्तन होता है - Quote इंटरफ़ेस और चयनकर्ता कोड पहले के उदाहरण के समान हैं:
typescript
import * as cheerio from "cheerio";
interface Quote {
text: string;
author: string;
tags: string[];
}
const res = await fetch("https://api.scrapeless.com/api/v2/unlocker/request", {
method: "POST",
headers: {
"x-api-token": process.env.SCRAPELESS_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
actor: "unlocker.webunlocker",
input: {
url: "https://quotes.toscrape.com/js/",
js_render: true,
headless: true,
},
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const envelope: { data: string } = await res.json();
const $ = cheerio.load(envelope.data);
const quotes: Quote[] = $("div.quote")
.map((_, el) => ({
text: $(el).find("span.text").text(),
author: $(el).find("small.author").text(),
tags: $(el).find("a.tag").map((_, t) => $(t).text()).get(),
}))
.get();
console.log(`html बाइट्स: ${envelope.data.length}`);
console.log(`उद्धरणों की संख्या: ${quotes.length}`);
console.log(`पहला लेखक: ${quotes[0]?.author}`);
text
html बाइट्स: 8940
उद्धरणों की संख्या: 10
पहला लेखक: अल्बर्ट आइंस्टीन
एक ही पृष्ठ, एक ही चयनकर्ता, एक ही इंटरफ़ेस। रिकॉर्ड की संख्या 0 से 10 बढ़ जाती है और पेलोड 5,806 से 8,940 वर्णों में बढ़ जाता है, और एकमात्र अंतर यह है कि HTML को कौन से परत ने फेच किया।
उस कॉल में दो TypeScript विवरण हैं जो नकल करने लायक हैं। लिफाफे को { data: string } के रूप में एनोटेट करने से await res.json() को फ़ाइल के बाकी हिस्से में any फैलाने से रोकता है, जो वह स्थान है जहां टाइप सुरक्षा आमतौर पर एक स्क्रैपर से लीक हो जाती है। और quotes[0]?.author इस तथ्य का सम्मान करता है कि एक सरणी का अनुक्रमांक undefined हो सकता है - जब noUncheckedIndexedAccess सक्षम होता है, तो कंपाइलर इसकी आवश्यकता करता है।
data फ़ील्ड रेंडर की गई दस्तावेज़ को एक स्ट्रिंग के रूप में रखती है, यही कारण है कि यह सीधे cheerio.load में जाती है। रेंडर विकल्पों का वर्णन Scrapeless दस्तावेज़ीकरण में किया गया है, और वही js_render व्यवहार को JS रेंडरिंग गाइड में और गहराई से खोजा गया है।
समस्या निवारण
ERR_UNKNOWN_FILE_EXTENSION एक .ts फ़ाइल पर। --experimental-strip-types फ़्लैग गायब है, या Node 22 से पुराना है। टाइप स्ट्रिपिंग लोड समय पर एनोटेशन को हटा देती है; यह टाइप-चेक नहीं करती है, इसलिए जब आप कंपाइलर की राय चाहते हैं तो tsc --noEmit को अलग से चलाएं।
Cannot use import statement outside a module. पैकेज में "type": "module" गायब है। शीर्ष स्तर का await ES मॉड्यूल की आवश्यकता होती है।
टाइप स्ट्रिपिंग एक एन्गम या पैरामीटर प्रॉपर्टी को अस्वीकार करती है। ये निर्माण वास्तविक रनटाइम कोड उत्पन्न करते हैं बजाय इसके कि इसे मिटाया जा सके, इसलिए स्ट्रीपिंग इन्हें संभाल नहीं सकती। एक एन्गम के बजाय स्ट्रिंग लिटेरल्स का एक संघ का उपयोग करें, और कंस्ट्रक्टर फ़ील्डों को स्पष्ट रूप से निर्दिष्ट करें।
चयनकर्ता ब्राउज़र में मेल खाते हैं लेकिन स्क्रिप्ट में नहीं। दृश्य-स्रोत के खिलाफ तुलना करें न कि निरीक्षक के खिलाफ। निरीक्षक स्क्रिप्ट चलने के बाद DOM दिखाता है, जो कि fetch ने प्राप्त किया नहीं है - पहले प्रतिक्रिया की लंबाई प्रिंट करें, जैसे कि ऊपर के उदाहरण में किया गया है।
किसी लाइव लक्ष्य पर इंगित करने से पहले, साइट के शर्तों और इसके /robots.txt निर्देशों की जांच करें, जो रोबोट्स प्रतिबंध प्रोटोकॉल मानक, का पालन करते हैं, और सार्वजनिक डेटा को उस मात्रा में संग्रहित रखें जिसे साइट आराम से सर्व कर सके।
निष्कर्ष
TypeScript एक स्क्रैपर को एक कॉन्ट्रैक्ट देता है: रिकॉर्ड घोषित करें, और कंपाइलर आपको बताता है कि कब निकासी इसे संतोषजनक नहीं बनाती है। Node 22 में प्रकारों को स्वाभाविक रूप से स्ट्रिपिंग करना और fetch बिल्ट-इन होना, वह अनुबंध केवल एक निर्भरता और बिना किसी निर्माण चरण के खर्च करता है।
यह प्रकार आपको यह बताने में असमर्थ हैं कि क्या पृष्ठ जिसे आपने प्राप्त किया, उसमें डेटा बिल्कुल मौजूद था या नहीं। उस चेक को स्पष्ट होना चाहिए - एक अच्छे प्रकार का खाली एरे वही है जो क्लाइंट-Rendered पृष्ठ लौटाता है, और यह बिल्कुल एक ऐसा पृष्ठ जैसा दिखता है जिसमें कोई परिणाम नहीं है। इससे अंतर को मापना एक ऐसी आदत है जो बनाए रखने लायक है: 10 रिकॉर्ड सर्वर-Rendered, JavaScript जुड़वां पर 0, और फिर 10 जब कुछ पृष्ठ को रेंडर करता है इससे पहले कि cheerio इसे देखे।
Scrapeless मुफ्त योजना के साथ प्रारंभ करें ताकि आप अपने लक्ष्यों के खिलाफ रेंडर चरण चला सकें, और जब आप एक नौकरी का आकार निर्धारित करें, तब वर्तमान Scrapeless मूल्य निर्धारण की जांच करें।
सामान्य प्रश्न
प्रश्न: क्या मुझे TypeScript को स्क्रैप करने के लिए संकलित करने की आवश्यकता है?
नहीं। Node 22 और बाद के संस्करण सीधे .ts फ़ाइलों को node --experimental-strip-types के साथ चलाते हैं, जो लोड समय पर प्रकार एनोटेशन को हटा देता है। इसका मतलब है कि एक स्क्रैपर के लिए कोई निर्माण चरण और कोई बंडलर नहीं है। प्रकार स्ट्रिपिंग प्रकारों की जांच नहीं करती है, इसलिए जब आप चाहते हैं कि कंपाइलर वास्तव में उन्हें सत्यापित करे, तो CI में tsc --noEmit चलाएँ।
प्रश्न: मुझे TypeScript के साथ कौन सी HTML पार्सिंग लाइब्रेरी का उपयोग करना चाहिए?
cheerio अधिकांश कार्य को कवर करता है - यह HTML-विशिष्ट अनुरूप पार्सर के साथ पार्स करता है और TypeScript परिभाषाओं के साथ jQuery-शैली चयनकर्ता एपीआई को उजागर करता है। केवल तब हेडलेस ब्राउज़र या एक रेंडरिंग API की ओर बढ़ें जब सामग्री DOM में स्क्रिप्ट द्वारा लिखी जाती है, जिसे कोई पार्सर अपनेआप नहीं पुनर्प्राप्त कर सकता।
प्रश्न: क्या Node में 404 पर fetch त्रुटि फेंकता है?
नहीं, और यह लोगों को पकड़ लेता है। fetch किसी भी HTTP प्रतिक्रिया के लिए सामान्य रूप से हल होता है और केवल नेटवर्क-स्तरीय विफलता पर अस्वीकृत होता है, इसलिए आपको खुद res.ok की जांच करनी होगी। उस चेक के बिना, एक त्रुटि पृष्ठ शून्य मेलों के लिए पार्स करता है और एक ऐसा पृष्ठ जो वास्तव में कोई परिणाम नहीं था, उससे अलग नहीं होता।
प्रश्न: जब उत्तर JSON हो, तो मैं प्रकारों को ईमानदार कैसे रख सकता हूँ?
सीमा पर एनोटेट करें। await res.json() any लौटाता है, इसलिए इसे const envelope: { data: string } जैसे टाइप वाले वेरिएबल पर असाइन करना any को फ़ाइल के बाकी हिस्से में फैलने से रोकता है। अविश्वसनीय अपस्ट्रीम डेटा के लिए, एनोटेशन पर केवल भरोसा करने के बजाय एक स्कीमा लाइब्रेरी के साथ रन-टाइम पर मान्य करें।
प्रश्न: क्या TypeScript एक ऐसा पृष्ठ स्क्रैप कर सकता है जो ब्राउज़र में रेंडर होता है?
एकला नहीं। भाषा का यह तय करने में कोई प्रभाव नहीं है कि JavaScript निष्पादित होता है या नहीं - fetch सर्वर द्वारा भेजे गए बाइट्स को लौटाता है, और ऊपर का उदाहरण दिखाता है कि उन बाइट्स क्लाइंट-Rendered पृष्ठ पर शून्य रिकॉर्ड के लिए पार्स हो रहे हैं। रेंडरिंग कहीं और होनी चाहिए, या तो एक हेडलेस ब्राउज़र में जिसे आप संचालित करते हैं या एक API के माध्यम से जो रेंडर किया हुआ DOM लौटाता है।
स्क्रैपलेस में, हम केवल सार्वजनिक रूप से उपलब्ध डेटा का उपयोग करते हैं, जबकि लागू कानूनों, विनियमों और वेबसाइट गोपनीयता नीतियों का सख्ती से अनुपालन करते हैं। इस ब्लॉग में सामग्री केवल प्रदर्शन उद्देश्यों के लिए है और इसमें कोई अवैध या उल्लंघन करने वाली गतिविधियों को शामिल नहीं किया गया है। हम इस ब्लॉग या तृतीय-पक्ष लिंक से जानकारी के उपयोग के लिए सभी देयता को कोई गारंटी नहीं देते हैं और सभी देयता का खुलासा करते हैं। किसी भी स्क्रैपिंग गतिविधियों में संलग्न होने से पहले, अपने कानूनी सलाहकार से परामर्श करें और लक्ष्य वेबसाइट की सेवा की शर्तों की समीक्षा करें या आवश्यक अनुमतियाँ प्राप्त करें।



