Scrapling में page_action के साथ कैप्चा कैसे हल करें

Scrapling में कैप्चा का काम साफ़ तौर पर दो हिस्सों में बँट जाता है, और यह जानना कि आप किस हिस्से में हैं, आपकी पूरी दोपहर बचा सकता है। Cloudflare के पास अपना स्विच है: StealthyFetcher को solve_cloudflare पास करें और Turnstile या interstitial challenge आपके लिए संभाल लिया जाता है। बाक़ी सब आपका काम है। reCAPTCHA v2, reCAPTCHA v3, GeeTest और image कैप्चा fetcher के बाहर हल होते हैं और page_action hook के ज़रिए पेज में इंजेक्ट किए जाते हैं। यह गाइड उसी दूसरे हिस्से को समझाती है, साथ ही उस एक बात को भी जो चुपचाप इसे तोड़ देती है।
आपको क्या चाहिए
- Python 3.10 या उससे नया। Scrapling को इसकी ज़रूरत है।
- Scrapling, fetchers extra के साथ इंस्टॉल किया हुआ, साथ में उसका एक बार वाला browser डाउनलोड स्टेप।
- सुरक्षित पेज का URL। आपको sitekey पहले से नहीं चाहिए, क्योंकि पहला pass उसे पढ़ लेता है।
- Local mode में चलता CapSkip, अगर स्क्रैपर और सॉल्वर एक ही machine साझा करते हैं, या Server mode में अगर वे ऐसा नहीं करते। दोनों का वर्णन यहाँ है: कनेक्शन सेटिंग्स.
# pip install capskip pip install capskip pip install "scrapling[fetchers]" # Scrapling needs one more step. The bare package is the parser # engine only, and importing from scrapling.fetchers without this # raises ModuleNotFoundError. scrapling install
solve_cloudflare क्या कवर करता है, और क्या नहीं
इस बारे में सटीक होना ज़रूरी है, क्योंकि नाम फ़ीचर से ज़्यादा बड़ा लगता है। StealthyFetcher का solve_cloudflare argument आपको रिस्पॉन्स सौंपने से पहले Cloudflare के Turnstile और interstitial challenges पार कर लेता है। यह सचमुच सुविधाजनक है और आपको इसे इस्तेमाल करना चाहिए। और यही पूरी सूची भी है।
| पेज पर challenge | इसे कौन संभालता है |
|---|---|
| Cloudflare Turnstile, और पूरे पेज वाला interstitial | Scrapling, solve_cloudflare argument के ज़रिए |
| reCAPTCHA v2, invisible और enterprise वैरिएंट समेत | आप, page_action hook के ज़रिए |
| action नाम के साथ reCAPTCHA v3 | आप, page_action hook के ज़रिए |
| GeeTest v3, वह slider जिसके जवाब में तीन फ़ील्ड होते हैं | आप, page_action hook के ज़रिए |
| विकृत टेक्स्ट वाला image कैप्चा | आप, page_action hook के ज़रिए |
तो काम का ढाँचा हर बार एक जैसा रहता है। पेज से challenge के parameters निकालें, उन्हें कहीं और हल करें, फिर जवाब वापस DOM में डालें और साइट के अपने फ़ॉर्म को उसे आगे ले जाने दें। उस बीच वाले हिस्से के लिए Scrapling आपको ठीक एक जगह देता है, और वह है page_action।
स्टेप 1: browser शुरू किए बिना sitekey पढ़ें
Scrapling में तीन fetchers हैं और वे आपस में बदले नहीं जा सकते। Fetcher सादा HTTP है। DynamicFetcher एक Playwright browser चलाता है। StealthyFetcher सख़्त किया हुआ वाला है, और version 0.3.13 से यह पहले वाले Camoufox बिल्ड के बजाय Patchright पर चलता है, जो जानना ज़रूरी है अगर आप कोई पुरानी गाइड फ़ॉलो कर रहे हैं।
sitekey के लिए आपको लगभग कभी browser की ज़रूरत नहीं पड़ती। यह मान markup में एक data attribute के रूप में मौजूद रहता है, इसलिए सस्ता fetcher भी इसे पढ़ सकता है।
# pip install capskip
from scrapling.fetchers import Fetcher
PAGE_URL = "https://example.com/page-with-recaptcha"
# Plain HTTP. No browser starts, so this costs almost nothing
# and tells you which CAPTCHA you are actually facing.
page = Fetcher.get(PAGE_URL)
sitekey = page.css("[data-sitekey]::attr(data-sitekey)").get()
print(sitekey)अगर वह खाली आता है, तो widget को JavaScript लिखता है और वह सर्व किए गए HTML में नहीं होता। उसी पेज को एक बार DynamicFetcher से फ़ेच करें और रेंडर हुए DOM से पढ़ें, या उसे browser में खोलकर मान हार्डकोड कर दें। sitekey सार्वजनिक होता है और स्थिर रहता है, इसलिए उसे हार्डकोड करना ऐसा शॉर्टकट नहीं है जिसके लिए माफ़ी माँगनी पड़े।
स्टेप 2: इसे अपने ही हार्डवेयर पर हल करें
एक ही कॉल। हर reCAPTCHA वैरिएंट वही method है, बस keyword arguments अलग होते हैं: invisible को 1, enterprise को 1, या version को v3 और साथ में एक action नाम। Turnstile और GeeTest के अपने methods हैं, ढाँचा वही है, और parameters की पूरी सूची यहाँ है: CapSkip API डॉक्यूमेंटेशन.
# CapSkip listens on your own machine, so this is a loopback call. from capskip import CapSkip solver = CapSkip(host="127.0.0.1", port=8080) token = solver.recaptcha(sitekey=sitekey, url=PAGE_URL)["code"]
वह कॉल पोल करते समय ब्लॉक करती है, और पोलिंग किसी एक समान अंतराल पर नहीं होती: SDK 250 मिलीसेकंड से शुरू होता है और pollingInterval की तरफ़ धीरे-धीरे बढ़ता है, इसलिए यह आमतौर पर raw endpoint पर हाथ से लिखे loop से जल्दी जवाब देता है। ऊपरी सीमा recaptchaTimeout है, जिसका डिफ़ॉल्ट 300 सेकंड है।
स्टेप 3: page_action में token इंजेक्ट करें
page_action एक function लेता है, Playwright का page ऑब्जेक्ट पाता है, और navigation के बाद तथा network_idle के इंतज़ार के बाद चलता है, पर wait_selector से पहले। यही क्रम काम का हिस्सा है: जब तक आपका function चलता है, widget रेंडर हो चुका होता है, और उसके बाद आप जिस चीज़ का भी इंतज़ार करते हैं, उसे आपके किए का नतीजा दिखता है।
from playwright.sync_api import Page
def inject_token(page: Page):
# The response textarea is hidden, so set the value directly
# rather than trying to type into it.
page.evaluate(
"(t) => document.getElementById('g-recaptcha-response').value = t",
token,
)
page.click("button[type=submit]")function को कुछ भी लौटाने की ज़रूरत नहीं है। Scrapling के पुराने वर्ज़न page ऑब्जेक्ट वापस चाहते थे और मौजूदा डॉक्यूमेंटेशन नहीं चाहता, इसलिए कुछ न लौटाना दोनों ही हालात में सुरक्षित तरीक़ा है।
isolated execution context, और यही वह हिस्सा है जो फँसाता है
StealthyFetcher डिफ़ॉल्ट रूप से आपके JavaScript को Patchright के isolated execution context में चलाता है। DOM साझा होता है, इसलिए एलिमेंट पढ़ना और लिखना ठीक वैसे ही काम करता है जैसी आप उम्मीद करेंगे। पेज के अपने JavaScript globals साझा नहीं होते, इसलिए साइट ने window पर जो कुछ भी रखा है वह बस ग़ायब रहता है।
यही फ़र्क़ तय करता है कि आपका injection काम करेगा या नहीं। response textarea का मान सेट करना सिर्फ़ DOM को छूता है, और isolated दुनिया में ठीक काम करता है। साइट का reCAPTCHA callback कॉल करना काम नहीं करता, क्योंकि वह callback एक ऐसे global पर रहता है जिसे पेज की अपनी script ने बनाया था। जो साइटें सामान्य फ़ॉर्म submit के बजाय callback इस्तेमाल करती हैं, वे ऐसी लगेंगी जैसे उन्होंने एक बिलकुल सही token को नज़रअंदाज़ कर दिया।
def inject_and_fire_callback(page: Page):
# isolated_context=False drops into the page's own world,
# where the site's grecaptcha object actually exists.
page.evaluate(
"""(t) => {
document.getElementById('g-recaptcha-response').value = t;
window.onCaptchaSuccess(t);
}""",
token,
isolated_context=False,
)यह लिखने से पहले callback का नाम widget से पढ़ लें। यह वही होता है जो reCAPTCHA एलिमेंट पर data-callback attribute कहता है, और हर साइट पर अलग होता है।
पूरा चलने वाला उदाहरण
sitekey पढ़ने के लिए एक सस्ता HTTP pass, एक solve, फिर एक ही stealthy fetch जो इंजेक्ट करता है और submit करता है। ध्यान दें कि solve, fetch से पहले होता है, इसलिए जब page_action चलता है तब token पहले से हाथ में होता है।
# pip install capskip
from capskip import CapSkip
from playwright.sync_api import Page
from scrapling.fetchers import Fetcher, StealthyFetcher
PAGE_URL = "https://example.com/page-with-recaptcha"
solver = CapSkip(host="127.0.0.1", port=8080)
sitekey = Fetcher.get(PAGE_URL).css("[data-sitekey]::attr(data-sitekey)").get()
token = solver.recaptcha(sitekey=sitekey, url=PAGE_URL)["code"]
def inject_token(page: Page):
page.evaluate(
"(t) => document.getElementById('g-recaptcha-response').value = t",
token,
)
page.click("button[type=submit]")
page = StealthyFetcher.fetch(
PAGE_URL,
headless=True,
network_idle=True,
page_action=inject_token,
wait_selector=".dashboard",
)
print(page.css(".dashboard h1::text").get())वहाँ दो arguments भार उठाते हैं। network_idle से fetcher तब तक इंतज़ार करता है जब तक 500 मिलीसेकंड तक कोई network कनेक्शन न हो, जो आमतौर पर widget के रेंडर होने के लिए काफ़ी है। wait_selector वह है जो साबित करता है कि submit काम कर गया: उसे किसी ऐसी चीज़ पर लगाएँ जो सिर्फ़ फ़ॉर्म के दूसरी तरफ़ मौजूद हो, और तब नाकाम submit चुपचाप मिली सफलता के बजाय timeout बन जाता है।
एक session के साथ कई पेज करना
हर class-level fetch एक browser शुरू करता है और फिर उसे फेंक देता है। दो-चार से ज़्यादा पेज के लिए, इसके बजाय एक session खोलें और requests के बीच browser को बनाए रखें। ज़्यादातर fetch arguments session पर एक बार सेट किए जा सकते हैं और हर request पर बदले जा सकते हैं, जिनमें page_action, wait_selector और solve_cloudflare शामिल हैं।
from scrapling.fetchers import StealthySession
# solve_cloudflare here handles the Cloudflare layer for every
# page in the session. Anything else still goes through
# page_action, per request.
with StealthySession(headless=True, solve_cloudflare=True) as session:
for url in urls:
page = session.fetch(url, page_action=inject_token)
print(page.css("title::text").get())जितनी देर से हो सके, उतनी देर से हल करें। एक reCAPTCHA token लगभग दो मिनट तक चलता है, इसलिए पहले से बीस token हल करके फिर एक क़तार चलाने पर उनमें से ज़्यादातर expire हो जाएँगे। loop के अंदर हल करें, ठीक उस fetch से पहले जो उसे इस्तेमाल करता है। व्यवहार में इस अवधि का क्या मतलब है, यह यहाँ बताया गया है: reCAPTCHA token expiration की गाइड.
सॉल्वर को किसी दूसरी मशीन पर चलाना
स्क्रैपर एक जगह नहीं रहते। कोई VPS, कोई कंटेनर या कोई शेड्यूल किया हुआ worker वह मशीन नहीं है जिस पर सॉल्वर है, और वहाँ loopback ख़ुद उसी worker की तरफ़ इशारा करता है, जहाँ कुछ भी सुन नहीं रहा होता।
ठीक इसी के लिए CapSkip में दो कनेक्शन मोड हैं। Local, 127.0.0.1 से बंधता है और सिर्फ़ उसी डिवाइस को जवाब देता है। Server, आपके network पते या public IP से बंधता है, इसलिए कहीं भी चलने वाला स्क्रैपर उसी Windows मशीन तक API के ज़रिए पहुँच सकता है। एक स्टैटिक public IP पते को स्थिर रखता है। दोनों ही हालात में यह आपका हार्डवेयर है और दोनों ही हालात में बिना मीटर के है, इसलिए पचास हज़ार challenges हल करने वाले रन की लागत उतनी ही है जितनी पचास हल करने वाले की।
# The SDK reads these three itself, so the same script runs # whether the solver is on this box or on another one: # CAPSKIP_HOST=192.0.2.10 # CAPSKIP_PORT=8080 # CAPSKIP_API_KEY=your-key solver = CapSkip()
जैसे ही सॉल्वर किसी network पते पर सुनने लगे, key validation चालू कर दें, और हर worker को उसकी अपनी key दें ताकि बाक़ी को छेड़े बिना किसी एक को रद्द किया जा सके। दोनों मोड यहाँ विस्तार से समझाए गए हैं: CapSkip सेटअप गाइड.
दोनों सिरों पर प्रॉक्सी
अगर साइट जाँचती है कि token उसी पते से आया है जो उसे submit कर रहा है, तो solve और fetch दोनों को एक ही exit से निकलना होगा। Scrapling fetchers पर एक proxy argument लेता है, और CapSkip reCAPTCHA, Turnstile और GeeTest के लिए हर task पर एक लेता है। Image कैप्चा प्रॉक्सी स्वीकार नहीं करते और उन्हें इसकी ज़रूरत भी नहीं होती।
PROXY = "http://user:[email protected]:3128" token = solver.recaptcha( sitekey=sitekey, url=PAGE_URL, proxy={"type": "HTTP", "uri": "user:[email protected]:3128"}, )["code"] page = StealthyFetcher.fetch(PAGE_URL, proxy=PROXY, page_action=inject_token)
दोनों की लिखावट जान बूझकर अलग है: सॉल्वर type और URI को अलग-अलग फ़ील्ड के रूप में लेता है, fetcher एक ही URL स्ट्रिंग लेता है। इनमें से एक भी ग़लत होने का मतलब है कि solve आपके असली पते से निकलता है जबकि fetch प्रॉक्सी से, और यह बिलकुल ख़राब token जैसा दिखता है, जबकि होता नहीं। प्रॉक्सी का प्रकार कैसे चुनें, यह यहाँ बताया गया है: हल करते समय प्रॉक्सी घुमाने की गाइड.
आम errors और उनका मतलब
| आप जो देखते हैं | कारण | फिक्स |
|---|---|---|
| fetchers import पर ModuleNotFoundError | सादा पैकेज सिर्फ़ parser इंजन है | fetchers extra के साथ इंस्टॉल करें, फिर scrapling install कमांड चलाएँ |
| sitekey selector कुछ नहीं लौटाता | widget को JavaScript इंजेक्ट करता है, इसलिए वह सर्व किए गए HTML में नहीं होता | उसे एक बार DynamicFetcher से पढ़ें, या हार्डकोड कर दें |
| token फ़ील्ड में पहुँच जाता है पर फ़ॉर्म कभी submit नहीं होता | साइट callback इस्तेमाल करती है, और वह global isolated दुनिया में मौजूद नहीं होता | evaluate कॉल पर isolated_context को False करके पास करें |
| साफ़ solve के बाद wait_selector पर timeout | submit नाकाम रहा, इसलिए दूसरी तरफ़ का एलिमेंट कभी दिखा ही नहीं | page_action में स्क्रीनशॉट लें और देखें कि पेज असल में क्या कह रहा है |
| वैध token अस्वीकार हो जाता है | solve और fetch अलग-अलग पतों से निकले | दोनों पर एक ही प्रॉक्सी लगाएँ, हर एक की अपनी लिखावट में |
| सॉल्वर से NetworkException | CapSkip चल नहीं रहा, या host और port गलत हैं | ऐप शुरू करें, या host एनवायरनमेंट वेरिएबल को server के पते पर लगाएँ |
| सॉल्वर से ValidationException | ऐसा argument जिसे वह कैप्चा प्रकार स्वीकार नहीं करता | प्रकार जाँचें। v2 पर action, या v3 पर invisible, यही इसे उठाता है |
FAQ
क्या solve_cloudflare reCAPTCHA भी संभालता है?
नहीं। यह Cloudflare के Turnstile widget और Cloudflare के interstitial challenge पेज को कवर करता है, जो Cloudflare के अपने प्रोडक्ट हैं। reCAPTCHA Google का है, GeeTest अपना अलग है, और image कैप्चा वही है जो साइट ने बनाया। ये तीनों page_action से होकर जाते हैं, उस token के साथ जो आपने ख़ुद हल किया।
क्या StealthyFetcher अब भी Camoufox पर बना है?
version 0.3.13 के बाद से नहीं। अब यह Patchright पर चलता है, जो Firefox के बजाय Chromium स्टैक है। डॉक्यूमेंटेशन अब भी session को subclass करके Camoufox पर लौटने का एक वैकल्पिक तरीक़ा बताता है, पर डिफ़ॉल्ट बदल चुका है, इसलिए जो गाइड आपसे कहती है कि StealthyFetcher एक Camoufox रैपर है, वह किसी पुराने रिलीज़ की बात कर रही है।
क्या मैं fetch से पहले के बजाय page_action के अंदर हल कर सकता हूँ?
कर सकते हैं, और reCAPTCHA v3 या GeeTest के लिए अक्सर करना ही पड़ता है, क्योंकि parameters तभी मौजूद होते हैं जब पेज चल चुका हो। बस याद रखें कि पूरे solve के दौरान browser ख़ाली बैठा रहता है। अगर sitekey सर्व किए गए HTML में है, तो पहले हल करना और बाद में इंजेक्ट करना browser को बहुत कम समय के लिए खुला रखता है।
क्या async fetcher इसमें कुछ बदलता है?
सिर्फ़ लिखावट। async fetch method इस्तेमाल करें, और page_action को एक async function बनाएँ जो async Playwright page लेता है। सॉल्वर की तरफ़ AsyncCapSkip इस्तेमाल करें, जो Python में किसी alias के बजाय सचमुच का async इम्प्लीमेंटेशन है, इसलिए यह एक thread रोके रखने के बजाय आपका event loop साझा करता है।
संक्षेप में
Cloudflare को solve_cloudflare के साथ Scrapling संभालने दें, और बाक़ी सब ख़ुद page_action में संभालें। sitekey को सादे HTTP fetcher से पढ़ें, उसे हल करें, फिर hook के अंदर से response फ़ील्ड सेट करें। अगर साइट फ़ॉर्म submit करने के बजाय कोई callback चलाती है, तो isolated context बंद करके evaluate करें, वरना token ऐसी दुनिया में जा गिरेगा जिसे पेज देख ही नहीं सकता। wait_selector को किसी ऐसी चीज़ पर लगाएँ जो सिर्फ़ सफल submit के बाद मौजूद हो, ताकि नाकामी शोर मचाए।
Python की व्यापक कहानी यहाँ मिलती है: Python कैप्चा सॉल्वर पेज, checkbox challenge की बारीक़ियाँ यहाँ: reCAPTCHA v2 सॉल्वर पेज, और Cloudflare वाला पक्ष यहाँ: Cloudflare Turnstile सॉल्वर पेज। वही तीन कॉल Node.js, PHP और C# में भी मौजूद हैं, जिनकी सूची यहाँ है: CAPTCHA solving SDK पेज.
इसे किसी असली crawl पर लगाने से पहले एक बात तौल लेना ज़रूरी है। CapSkip एक असीमित कैप्चा सॉल्वर है जो उस हार्डवेयर पर चलता है जो पहले से आपका है, इसलिए किसी बड़े स्क्रैप की कैप्चा वाली लागत प्रति-हल न होकर एक तय लागत होती है।
