स्काला वेब स्क्रैपिंग: प्राप्त करें, पार्स करें और सुरक्षित पृष्ठों को अनलॉक करें
Expert in Web Scraping Technologies
TL;DR:
- Scala वेब को दो भागों में स्क्रैप करता है: एक JVM HTTP क्लाइंट जो डेटा लाता है, और एक jsoup-आधारित पार्सर जो जानकारी निकालता है। requests-scala अनुरोध बनाता है; scala-scraper HTML को CSS-चयन योग्य नोड्स में बदलता है।
- पूरे प्रोजेक्ट में तीन sbt निर्भरताएँ हैं। HTTP के लिए requests-scala 0.9.0, पार्सिंग के लिए scala-scraper 3.2.0, और बाद में डिकोड करने के लिए एक JSON लिफाफा ujson 4.1.0 — सीखने के लिए कोई ढांचा नहीं।
- पैगिनेशन "अगला" लिंक पर लूप है। scala-scraper एक वैकल्पिक चयनकर्ता के साथ अगली पृष्ठ की href पढ़ता है, इसलिए कैटलॉग वॉक एक टेल-रिकर्सिव फ़ंक्शन है, किसी क्यू के बजाय।
- स्थिर फेच में एक कठिन सीमा है: यह जावास्क्रिप्ट नहीं चला सकता या बॉट चुनौती पास नहीं कर सकता। एक साधारण
requests.getएक क्लाइंट-रेन्डर्ड पृष्ठ के खाली शेल को लौटता है और सुरक्षित साइटों पर एक चुनौती इंटर-स्टीशियल प्राप्त करता है। - Scrapeless Universal Scraping API उस अंतर को एक साधारण HTTP POST के साथ बंद करता है।
js_render: trueपृष्ठ को सर्वर-साइड पर चलाता है और पूरा DOM लौटाता है; वही requests-scala क्लाइंट जो एक साइट से बात करता है API से भी बात कर सकता है। - अनलॉक कॉल लाइव एपीआई पर चलाया गया: HTTP 200, 51,275 बाइट्स का रेन्डर्ड HTML, 20 उत्पाद शीर्षक। इस गाइड में अनुरोध और प्रतिक्रिया का स्वरूप उस लाइव रन से सीधे आया है।
- शुरू करने के लिए मुफ्त। नए Scrapeless खाते मुफ्त रनटाइम के साथ आते हैं — app.scrapeless.com पर साइन अप करें।
परिचय: स्क्रैपिंग में Scala कहाँ बैठता है
Scala JVM पर चलता है, जिसका मतलब है कि इसमें लिखा गया स्क्रैपर jsoup, Akka, और एक परिपक्व HTTP पारिस्थितिकी तंत्र को मुफ्त में विरासत में पाता है। यह भाषा तब प्राकृतिक रूप से उपयुक्त होती है जब स्क्रैपिंग कुछ पहले से JVM पर हो रहा हो — एक स्पार्क जॉब, एक काफ्का उत्पादक, एक डेटा सेवा — और आप उसी कोडबेस में, उसी प्रकार के साथ, उसे उपभोग करने की पाइपलाइन के रूप में निकासी करना चाहते हैं।
उस कार्य के फेच-और-पार्स आधे का हिस्सा छोटा है। कुछ पंक्तियाँ एक पृष्ठ को खींचती हैं और उसमें से वैल्यूज़ को CSS चयनकर्ताओं के साथ पढ़ती हैं। अवरोध तब शुरू होता है जब हर स्क्रैपर का होता है: एक बढ़ता हुआ हिस्सा वेब का अपनी सामग्री को जावास्क्रिप्ट के साथ बनाता है जिसे वास्तव में चलाना होगा ताकि डेटा मौजूद हो, और सुरक्षित साइटों पर पहुँच को TLS फिंगरप्रिंटिंग और चुनौती पृष्ठों के पीछे गेट किया जाता है जिससे एक कच्चा HTTP क्लाइंट कभी पार नहीं कर सकता।
यह गाइड पहले स्थिर स्क्रैपर बनाता है — sbt प्रोजेक्ट, एक HTTP फेच, चयनकर्ता-आधारित निकासी, पैजिनेशन — फिर उस ईमानदार रेखा को खींचता है जहाँ वह दृष्टिकोण रुकता है और कठिन पृष्ठों को Scrapeless Universal Scraping API को सौंपता है। अंत में API कॉल लाइव चलाया गया; इसके नंबर एक वास्तविक कैप्चर हैं।
इस स्टैक के साथ आप क्या कर सकते हैं
- JVM पर फेच और पार्स करें — अनुरोध के लिए requests-scala, CSS-चयन आधारित निकासी के लिए scala-scraper (एक jsoup रैपर)।
- आपके डेटा कोडबेस में निकासी बनाए रखें — स्काला प्रकारों में मान पढ़ें जो उसी समय स्पार्क या काफ्का जॉब का उपयोग करता है।
- पैगिनेटेड लिस्टिंग को चलाएँ — जब तक अगला पृष्ठ लिंक समाप्त नहीं हो जाता, एक टेल-रिकर्सिव लूप में इसका पालन करें।
- जावास्क्रिप्ट-रेन्डर्ड और सुरक्षित पृष्ठों तक पहुँचें — उन्हें यूनिवर्सल स्क्रैपिंग एपीआई पर POST करें और उसी तरह रेन्डर्ड HTML को पार्स करें।
- एंटी-बॉट स्टैक को दरकिनार करें — TLS फिंगरप्रिंटिंग, आवासीय IPs, और चुनौती हल करने का काम API में होता है, आपके Scala कोड में नहीं।
क्यों Scrapeless Universal Scraping API
Scrapeless Universal Scraping API एक लक्षित URL लेता है और रेन्डर्ड, अनब्लॉक HTML लौटाता है। विशेष रूप से एक Scala क्लाइंट के लिए, यह लाता है:
- सर्वर-साइड जावास्क्रिप्ट रेन्डेरिंग —
js_render: trueपूरा DOM लौटाता है, इसलिए scala-scraper वास्तविक सामग्री देखता है न कि एक खाली शेल। - 195+ देशों में आवासीय प्रॉक्सी — फेच विश्वसनीय IPs से होता है; आप कभी भी Scala में एक पूल का निर्माण या घुमाव नहीं करते।
- एंटी-बॉट हैंडलिंग — TLS फिंगरप्रिंटिंग और चुनौती समाधान API-साइड होते हैं, आपके JVM प्रक्रिया से बाहर।
- एक साधारण HTTPS POST —
build.sbtमें जोड़ने के लिए कोई SDK नहीं; आपके पास पहले से मौजूद requests-scala क्लाइंट पर्याप्त है। - एक छोटा लिफाफा —
{"code":200,"data":"<html>…"}, उसी ujson के साथ डिकोड किया गया जो आप अन्यत्र उपयोग करते हैं।
app.scrapeless.com पर मुफ्त योजना पर अपना API कुंजी प्राप्त करें।
पूर्वापेक्षाएँ
- एक JDK (11 या नया) और sbt स्थापित होना चाहिए।
- Scala 2.13 (नीचे दिए गए निर्भरता संस्करण 2.13 बिल्ड हैं)।
- एक Scrapeless खाता और API कुंजी — app.scrapeless.com पर साइन अप करें।
- टर्मिनल के साथ बुनियादी परिचितता।
नोट: नीचे के बिल्ड और स्टेप सेक्शन में Scala कोड इस गाइड की सत्यापन में एक पूर्वापेक्षा-गैप है — सत्यापन मशीन पर कोई JVM/sbt रनटाइम उपलब्ध नहीं था, इसलिए उन ब्लॉक्स को लाइब्रेरी के वर्तमान APIs और Maven Central संस्करणों के खिलाफ रचित और जांचा गया, न कि निष्पादित। लोड-बेयरिंग Scrapeless अनलॉक कॉल लाइव रूप से एपीआई के खिलाफ चलाया गया; इसका अनुरोध और प्रतिक्रिया एक वास्तविक कैप्चर है।
इंस्टॉल
दो फ़ाइलों के साथ एक प्रोजेक्ट डायरेक्टरी बनाएं। build.sbt भाषा और तीन निर्भरता को पिन करता है:
scala
ThisBuild / scalaVersion := "2.13.16"
lazy val scraper = (project in file("."))
.settings(
name := "scala-scraper-demo",
scala
libraryDependencies ++= Seq(
"com.lihaoyi" %% "requests" % "0.9.0",
"net.ruippeixotog" %% "scala-scraper" % "3.2.0",
"com.lihaoyi" %% "ujson" % "4.1.0"
)
)
project/build.properties sbt स्वयं को पिन करता है:
text
sbt.version=1.12.13
scala-scraper ट्रांज़िटिव रूप से jsoup को लाता है, इसलिए आप एक प्रकार की Scala DSL के माध्यम से jsoup के इंजन के साथ पार्स करते हैं बिना jsoup पर सीधे निर्भर हुए। पहले एक बार sbt update चलाएँ ताकि सब कुछ हल हो जाए, फिर REPL के लिए sbt console या main के लिए sbt run चलाएँ।
चरण 1 — एक पृष्ठ प्राप्त करें
requests-scala एक पतला, समकालिक HTTP क्लाइंट है। एक कॉल पृष्ठ का शरीर एक स्ट्रिंग के रूप में प्राप्त करता है:
scala
val res = requests.get(
"https://books.toscrape.com/",
headers = Map("User-Agent" -> "Mozilla/5.0 (compatible; scala-scraper-demo)")
)
println(res.statusCode) // 200
val html: String = res.text()
res.text() कच्चा HTML है। इस तरह के सर्वर द्वारा प्रस्तुत पृष्ठ के लिए, वह स्ट्रिंग पहले से ही डेटा धारण करती है; एक क्लाइंट द्वारा प्रस्तुत पृष्ठ के लिए, इसमें एक खाली छShell होती है, जो Step 4 की सीमा को संबोधित करती है।
चरण 2 — scala-scraper के साथ पार्स करें
scala-scraper स्ट्रिंग को एक दस्तावेज़ में पार्स करता है और अपनी DSL के माध्यम से CSS चयनकर्ताओं के साथ नोड का चयन करता है। >> ऑपरेटर निकालता है; elementList, attr, और texts परिणाम को Scala मूल्यों में आकार देते हैं:
scala
import net.ruippeixotog.scalascraper.browser.JsoupBrowser
import net.ruippeixotog.scalascraper.dsl.DSL._
import net.ruippeixotog.scalascraper.dsl.DSL.Extract._
val doc = JsoupBrowser().parseString(html)
val titles: List[String] = doc >> elementList("article.product_pod h3 a") >> attr("title")
val prices: List[String] = doc >> texts("p.price_color")
val books = titles.zip(prices)
books.foreach { case (t, p) => println(s"$p $t") }
article.product_pod h3 a यहाँ का मजबूत चयनकर्ता है — उत्पाद कार्ड क्लास और इसके शीर्षक के अंदर का लिंक — और title पूरा नाम ले जाता है भले ही दृश्यमान पाठ छोटा हो। एक गुण से मान निकालना, बजाय प्रदर्शित पाठ के, एक अधिक स्थिर पढ़ाई है जब भी साइट इसे प्रदान करती है।
चरण 3 — पृष्ठांकन का अनुसरण करें
सूची पृष्ठों के पार जारी है, प्रत्येक अगली को li.next a तत्व के माध्यम से लिंक करता है। scala-scraper का वैकल्पिक चयनकर्ता >?> उस लिंक के अभाव में None लौटाता है, जो कि लूप का रुकने की स्थिति है:
scala
import net.ruippeixotog.scalascraper.model.Document
def nextUrl(doc: Document, base: String): Option[String] =
(doc >?> element("li.next a")).map(a => base + a.attr("href"))
@annotation.tailrec
def crawl(url: String, base: String, acc: List[String]): List[String] = {
val doc = JsoupBrowser().parseString(requests.get(url).text())
val names = doc >> elementList("article.product_pod h3 a") >> attr("title")
nextUrl(doc, base) match {
case Some(next) => crawl(next, base, acc ++ names)
case None => acc ++ names
}
}
val all = crawl("https://books.toscrape.com/catalogue/page-1.html",
"https://books.toscrape.com/catalogue/", Nil)
println(all.size)
लूप को सौम्य रखें - एक समय में एक होस्ट, पृष्ठों के बीच में थोड़ा विराम - और अनुपस्थित क्षेत्रों का उपचार Option के रूप में करें, कभी भी उस मान के रूप में नहीं जिसे आप मानते हैं कि वह मौजूद है।
अपनी API कुंजी मुफ़्त योजना पर प्राप्त करें: app.scrapeless.com
जहाँ स्थैतिक अधिग्रहण रुकता है
requests.get एक ही कार्य करता है: यह सर्वर द्वारा एक अज्ञात क्लाइंट को भेजे गए बाइट्स को लौटाता है। यह एक सर्वर द्वारा प्रस्तुत सूची के लिए पर्याप्त है और कुछ नहीं। दो मामले इसे बाधित करते हैं, और दोनों सामान्य हैं:
- क्लाइंट द्वारा प्रस्तुत पृष्ठ। जब एक साइट अपनी सामग्री को जावास्क्रिप्ट के साथ बनाती है, तो HTML जिसे आप प्राप्त करते हैं, वह एक खाली छShell है जिसमें डेटा अभी भी स्क्रिप्ट में बंद है। scala-scraper के पास चयन करने के लिए कुछ भी नहीं है क्योंकि सामग्री कभी बाइट्स में नहीं थी।
- संरक्षित पृष्ठ। ऐसे साइट्स जिनमें सक्रिय एंटी-बोट सुरक्षा होती है, एक अज्ञात अनुरोध का उत्तर चुनौती अंतराल के साथ देते हैं, पृष्ठ नहीं। एक सामान्य HTTP क्लाइंट इसे साफ़ करने का कोई तरीका नहीं रखता है।
Scala में समाधान को दोहराना - जावास्क्रिप्ट चलाने के लिए एक हेडलेस ब्राउज़र, एक आवासीय प्रॉक्सी पूल, एक चुनौती हल करने वाला - खुद स्क्रैप करने की तुलना में एक बहुत बड़ा प्रोजेक्ट है। व्यावहारिक कदम यह है कि Scala से उस भाग को करने का प्रयास करना बंद करें और उन URL को एक रेंडरिंग API को दें।
क्लाउड मोड़: सर्वर-साइड रेंडर करें, Scala में पार्स करें
Scrapeless यूनिवर्सल स्क्रैपिंग API एक लक्षित URL लेता है, इसे एक असली ब्राउज़र और आवासीय निकासी के माध्यम से सर्वर-साइड चलाता है, और फिनिश HTML लौटाता है। Scala से यह एक ही POST है, उसी requests-scala क्लाइंट के साथ, और ujson प्रतिक्रिया को डिकोड करता है:
scala
val apiKey = sys.env("SCRAPELESS_API_KEY")
val payload = ujson.Obj(
"actor" -> "unlocker.webunlocker",
"input" -> ujson.Obj(
"url" -> "https://books.toscrape.com/",
"method" -> "GET",
"redirect" -> true,
"js_render" -> true
)
)
val res = requests.post(
"https://api.scrapeless.com/api/v1/unlocker/request",
hi
headers = Map("Content-Type" -> "application/json", "x-api-token" -> apiKey),
data = ujson.write(payload),
readTimeout = 120000
)
val env = ujson.read(res.text())
val html = env("data").str // एक स्ट्रिंग के रूप में रेंडर की गई DOM
js_render: true वह लोड-बेयरिंग ध्वज है: यह API को बताता है कि वह पृष्ठ का JavaScript चलाए और पूरा DOM लौटाए, ताकि एक साइट जो अपने सामग्री को क्लाइंट-साइड बनाती है, वास्तविक मार्कअप के रूप में वापस आए। यहाँ से, html सीधे उसी JsoupBrowser().parseString(html) में जाता है और चरण 2 के वही सिलेक्टर - आपके स्क्रैपर के पार्सिंग आधे में कोई बदलाव नहीं होता है, केवल फ़ेच।
आपको क्या वापस मिलता है
API प्रतिक्रिया एक छोटा, भविष्यवाणी योग्य लिफाफा है:
json
{
"code": 200,
"data": "<html>...रेंडर की गई DOM...</html>"
}
// चित्रात्मक नमूना: स्कीमा लाइव कॉल से वास्तविक आकार है; "data" स्ट्रिंग यहाँ संक्षिप्त है। सत्यापित रन में "data" ने 51,275 बाइट्स JSON-एस्केप की रेंडर की गई HTML को पकड़ा।
ऊपर दिए गए कैटलॉग पृष्ठ के लिए गतिशील कॉल ने HTTP 200 के साथ 51,275 बाइट्स की रेंडर की गई HTML लौटाई; उस HTML पर चरण 2 के सिलेक्टर चलाने पर 20 उत्पाद शीर्षक मिलते हैं, पहला "A Light in the Attic" £51.77 पर। रन से कुछ नोट्स:
js_render: trueलेटेंसी की कीमत चुकाता है लेकिन सामग्री खरीदता है। स्थतिक पृष्ठों के लिए तेज़ जाने के लिए इसे बंद करें; जब पृष्ठ इसके बिना ख Blank हो तो इसे चालू करें।ujsonवह एक फ़ील्ड पढ़ता है जिसकी आपको आवश्यकता है।env("data").strपूरी डिकोड है; लिफाफे का बाकी हिस्सा केवल स्थितिcodeहै।- सिलेक्टर Scala में रहते हैं। API HTML लौटाता है, इसलिए निष्कर्षण लॉजिक, प्रकार और परीक्षण आपके कोडबेस में रहते हैं, न कि किसी प्रबंधित स्कीमा के पीछे।
- अनुपस्थित फ़ील्ड को
Optionके रूप में मानें। एक nullable सिलेक्टर के साथ>?>सही पढ़ाई है जब भी एक कार्ड कीमत या शीर्षक छोड़ सकता है।
निष्कर्ष: पार्स के लिए Scala, कठिन फ़ेच के लिए API
एक Scala स्क्रैपर वहीं पर छोटा होता है जहाँ JVM मजबूत होता है - अनुरोध के लिए requests-scala, CSS-चयनकर्ता निष्कर्षण के लिए scala-scraper, अगले-पृष्ठ लिंक के लिए एक टेल-रिकर्सिव वॉक। यह हर स्थिर स्क्रैपर की तरह उसी दीवार में चलाता है: क्लाइंट-रेंडर किए गए पृष्ठ और सक्रिय एंटी-बॉट सुरक्षा जो एक साधारण HTTP क्लाइंट पार नहीं कर सकता। उन URL को यूनिवर्सल स्क्रैपिंग API के माध्यम से रूट करना एक ही POST के लिए समाधान रखता है और आपके पार्स को बिना छुए छोड़ देता है। किसी अन्य भाषा में समान फ़ेच-फिर-न पड़ा split के लिए, JavaScript और Node.js स्क्रैपिंग गाइड देखें; दस्तावेज़ पूर्ण API और इसके पैरामीटर को कवर करते हैं। js_render को पृष्ठ की ज़रूरत के अनुसार पिन करें, Scala में सिलेक्टर रखें, और हर फ़ील्ड को वैकल्पिक मानें।
अपनी AI-संचालित डेटा पाइपलाइन बनाने के लिए तैयार हैं?
हमारे समुदाय में शामिल हों एक मुफ्त योजना का दावा करने और JVM स्क्रैपर्स बनाने वाले डेवलपर्स से जुड़ने के लिए: Discord · Telegram।
app.scrapeless.com पर साइन अप करें मुफ्त रनटाइम के लिए और ऊपर दिए गए कार्यक्रम को उन साइटों और सिलेक्टर्स के अनुसार अनुकूलित करें जिनकी आपकी Scala पाइपलाइन को आवश्यकता है। मूल्य निर्धारण देखें।
सामान्य प्रश्न
प्रश्न: क्या Scala के साथ स्क्रैपिंग कानूनी है?
सार्वजनिक रूप से दृश्यमान डेटा को स्क्रैप करना आमतौर पर अनुमति योग्य होता है, लेकिन नियम क्षेत्राधिकार और साइट के अनुसार अलग होते हैं। लक्ष्य के सेवा प्रतिबंधों की समीक्षा करें, रोबोट निर्देशों का सम्मान करें, व्यक्तिगत या प्रतिबंधित डेटा से बचें, और व्यावसायिक कुछ भी के लिए सलाह लें।
प्रश्न: क्या मुझे एक प्रॉक्सी की आवश्यकता है?
एक सर्वर-रेंडर की गई साइट के हल्के स्क्रैपिंग के लिए, नहीं। सुरक्षित या क्लाइंट-रेंडर किए गए पृष्ठों के लिए, अनुरोध यूनिवर्सल स्क्रैपिंग API के आवासीय प्रॉक्सियों के माध्यम से 195+ देशों में निकलता है, इसलिए आप Scala में एक पूल नहीं बनाते हैं।
प्रश्न: एक बॉट चुनौती कैसी दिखती है, और मुझे साफ़ रेंडर कैसे मिलता है?
पृष्ठ के बजाय, एक गुमनाम अनुरोध को एक चुनौती अंतराल मिलता है। उस URL को js_render: true के साथ यूनिवर्सल स्क्रैपिंग API के माध्यम से रूट करें; यह विश्वसनीय आवासीय IP से पृष्ठ को सर्वर-साइड चलाता है और पूरा HTML लौटाता है।
प्रश्न: सीधे jsoup को कॉल करने के बजाय scala-scraper क्यों?
scala-scraper jsoup को एक टाइप्ड Scala DSL में लपेटता है, इसलिए सिलेक्टर List[String] या Option[Element] लौटाते हैं, न कि Java कलेक्शनों। आपको jsoup का पार्सर मिलता है जिसके परिणाम Scala पैटर्न मिलान में फिट होते हैं।
प्रश्न: जब साइट बदल गई तो मेरे सिलेक्टर टूट गए। अब क्या?
मार्कअप घूमता है। पृष्ठ की फिर से जांच करें और चयनकर्ता को कसते हैं - एक स्थिर कंटेनर क्लास के साथ एक विशेषता पढ़ाई (article.product_pod h3 a → title) को प्राथमिकता दें, जो अगली डिज़ाइन पर बदलते एक हैशेड CSS क्लास के मुकाबले।
प्रश्न: क्या मैं कई पृष्ठों को समानांतर में चला सकता हूँ?
हाँ, लेकिन इसे प्रति होस्ट लगभग तीन कार्यकर्ताओं तक सीमित रखें ताकि आप विनम्र रहें और दर सीमा से बचें। एक छोटे विलंब के साथ एकल-होस्ट वॉक का पूंछ-पुनरावर्ती तरीका सुरक्षित डिफ़ॉल्ट है।
स्क्रैपलेस में, हम केवल सार्वजनिक रूप से उपलब्ध डेटा का उपयोग करते हैं, जबकि लागू कानूनों, विनियमों और वेबसाइट गोपनीयता नीतियों का सख्ती से अनुपालन करते हैं। इस ब्लॉग में सामग्री केवल प्रदर्शन उद्देश्यों के लिए है और इसमें कोई अवैध या उल्लंघन करने वाली गतिविधियों को शामिल नहीं किया गया है। हम इस ब्लॉग या तृतीय-पक्ष लिंक से जानकारी के उपयोग के लिए सभी देयता को कोई गारंटी नहीं देते हैं और सभी देयता का खुलासा करते हैं। किसी भी स्क्रैपिंग गतिविधियों में संलग्न होने से पहले, अपने कानूनी सलाहकार से परामर्श करें और लक्ष्य वेबसाइट की सेवा की शर्तों की समीक्षा करें या आवश्यक अनुमतियाँ प्राप्त करें।



