यदि प्रॉक्सी का बिल एकत्र किए गए डेटा की मात्रा से तेजी से बढ़ रहा है, तो समस्या लगभग हमेशा retry-लॉजिक में होती है। पार्सर चुपचाप असफल अनुरोधों को कई बार दोहराता है, टाइमआउट और कैप्चा पर ट्रैफ़िक खर्च करता है, और डेवलपर इन खर्चों को लॉग में भी नहीं देखता। हम समझेंगे कि वास्तविक नुकसान की गणना कैसे करें और उन्हें कैसे कम करें बिना डेटा की गुणवत्ता खोए।
क्यों retry-लॉजिक ट्रैफ़िक खा जाती है
अधिकांश पार्सर्स को सरल retry-लॉजिक के साथ लिखा गया है: यदि अनुरोध सफल नहीं हुआ — तो दोहराएं, और ऐसा 3-5 बार तक करें। समस्या यह है कि प्रत्येक पुनरावृत्ति अनुरोध केवल एक नया HTTP अनुरोध नहीं है, बल्कि एक पूरा चक्र है: TCP-हैंडशेक, TLS-नेगोशिएशन, पृष्ठ का पूरा लोड (भले ही केवल एक डेटा ब्लॉक की आवश्यकता हो), और कभी-कभी छवियों या JS फ़ाइलों का पुनः लोड भी होता है, यदि पार्सर साधारण HTTP क्लाइंट के बजाय हेडलेस ब्राउज़र का उपयोग करता है।
विशेष रूप से रहवासी प्रॉक्सी के माध्यम से काम करते समय पुनरावृत्तियाँ महंगी होती हैं, जहां ट्रैफ़िक मात्रा के अनुसार चार्ज किया जाता है, न कि अनुरोधों की संख्या के अनुसार। एक असफल अनुरोध उत्पाद पृष्ठ पर Wildberries के चित्रों और स्क्रिप्टों के साथ 300-500 KB का खर्च कर सकता है। यदि पार्सर टाइमआउट पर 3 पुनरावृत्तियाँ करता है, तो आप एक ही असफल अनुरोध के लिए चार बार भुगतान करते हैं — और यह बिना यह सुनिश्चित किए कि चौथा प्रयास सफल होगा।
दूसरी वजह यह है कि कुछ त्रुटियों के लिए पुनरावृत्ति करना संभव नहीं है। यदि साइट ने बॉट का पता लगाने के कारण 403 लौटाया, तो उसी फ़िंगरप्रिंट और कुकी सत्र के साथ पुनरावृत्ति अनुरोध लगभग निश्चित रूप से वही उत्तर प्राप्त करेगा। पार्सर उन प्रयासों पर ट्रैफ़िक खर्च करता है, जो गणितीय रूप से सफल नहीं हो सकते, जब तक कि IP पता या ब्राउज़र का फ़िंगरप्रिंट नहीं बदलता।
वास्तव में कितनी ट्रैफ़िक पुनरावृत्तियों पर जाती है
समस्या के पैमाने को समझने के लिए, हम एक सरल उदाहरण लेते हैं। पार्सर मार्केटप्लेस से उत्पाद कार्ड एकत्र करता है, औसत प्रतिक्रिया का आकार — 250 KB (HTML + JSON API + आंशिक रूप से स्थैतिक)। स्थिर काम करते समय बिना किसी ब्लॉक के असफल अनुरोधों का हिस्सा 5-8% के स्तर पर रहता है। लेकिन सस्ते डेटा सेंटर प्रॉक्सी के माध्यम से आक्रामक पार्सिंग करते समय यह आंकड़ा 25-35% तक बढ़ सकता है, क्योंकि लक्षित प्रदाता जल्दी पैटर्न को पहचानता है और कैप्चा या अस्थायी IP बैन लौटाना शुरू करता है।
आइए संख्याओं पर विचार करें। मान लीजिए, 100,000 उत्पाद कार्ड एकत्र करने की आवश्यकता है:
| असफल अनुरोधों का हिस्सा | 1 अनुरोध पर पुनरावृत्तियाँ (औसतन) | कुल ट्रैफ़िक | अतिरिक्त खर्च |
|---|---|---|---|
| 5% | 0.15 | 28.75 GB | +15% |
| 15% | 0.45 | 36.25 GB | +45% |
| 30% | 0.90 | 47.5 GB | +90% |
जैसा कि देखा जा सकता है, 30% की विफलता के हिस्से और "3 बार दोहराने" की retry-रणनीति के साथ वास्तविक ट्रैफ़िक 25 GB के सिद्धांत न्यूनतम के मुकाबले लगभग दोगुना हो जाता है। ये अतिरिक्त 20+ GB — प्रॉक्सी पर बजट के सीधे नुकसान हैं, जिन्हें पुनरावृत्तियों की लॉजिक को फिर से देखने से कम किया जा सकता है।
पार्सर्स की retry-लॉजिक में सामान्य गलतियाँ
retry-लॉजिक को ठीक करने से पहले, उन सामान्य एंटी-पैटर्न को पहचानना महत्वपूर्ण है, जो 90% स्वनिर्मित पार्सर्स में पाए जाते हैं:
- त्रुटि कोड का बिना विश्लेषण के पुनरावृत्ति। पुनरावृत्ति किसी भी असामान्य स्थिति पर शुरू होती है — 403, 429, 500, टाइमआउट, कनेक्शन टूटना — जबकि उनके लिए प्रक्रिया की रणनीति भिन्न होनी चाहिए।
- पुनरावृत्तियों के बीच निश्चित देरी। उदाहरण के लिए, प्रयासों के बीच 2 सेकंड की देरी, चाहे यह पहला प्रयास हो या पांचवां — यह या तो साइट के लिए बहुत आक्रामक है, या बड़े वॉल्यूम के लिए बहुत धीमा है।
- उसी IP और उसी सत्र के साथ पुनरावृत्ति। यदि साइट ने फ़िंगरप्रिंट के कारण अनुरोध को अवरुद्ध कर दिया है, तो समान पैरामीटर के साथ पुनरावृत्ति परिणाम को नहीं बदलती, लेकिन ट्रैफ़िक खर्च करती है।
- प्रयासों की कोई ऊपरी सीमा नहीं। कुछ पार्सर्स "मृत" URL पर चक्रवात करते हैं और हार मानने से पहले दर्जनों पुनरावृत्तियाँ करते हैं।
- अस्थायी और स्थायी त्रुटियों के बीच अंतर की कमी। 404 (पृष्ठ मौजूद नहीं है) और 503 (सर्वर अस्थायी रूप से अनुपलब्ध है) को अलग-अलग लॉजिक की आवश्यकता होती है — लेकिन अक्सर इन्हें समान रूप से संसाधित किया जाता है।
Python में कोड के साथ एक्सपोनेंशियल बैकऑफ़
एक सरल, लेकिन प्रभावी समाधान — एक्सपोनेंशियल देरी के साथ जिटर (यादृच्छिक फैलाव), जो बेकार पुनरावृत्तियों की संख्या को कम करता है और समय में लोड को वितरित करता है। प्रयासों के बीच निश्चित विराम के बजाय, देरी एक्सपोनेंशियल रूप से बढ़ती है, जो साइट को ब्लॉक के बाद "ठंडा" होने का समय देती है, और स्वयं पार्सर को उन अनुरोधों पर ट्रैफ़िक खर्च नहीं करने देती, जो लगभग निश्चित रूप से विफल होंगे।
import time
import random
import requests
def fetch_with_backoff(url, proxies, max_retries=4, base_delay=1.0):
retryable_codes = {429, 500, 502, 503, 504}
non_retryable_codes = {404, 410}
for attempt in range(max_retries + 1):
try:
response = requests.get(url, proxies=proxies, timeout=10)
if response.status_code == 200:
return response
if response.status_code in non_retryable_codes:
# कोई पुनरावृत्ति का मतलब नहीं है — पृष्ठ भौतिक रूप से मौजूद नहीं है
return None
if response.status_code not in retryable_codes:
return None
except (requests.exceptions.Timeout,
requests.exceptions.ConnectionError):
pass # अस्थायी नेटवर्क त्रुटि — पुनरावृत्ति की जा सकती है
if attempt == max_retries:
return None
# जिटर के साथ एक्सपोनेंशियल देरी
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
return None
इस कोड का मुख्य विचार त्रुटियों को तीन श्रेणियों में विभाजित करना है: वे जो पुनरावृत्ति से ठीक नहीं की जा सकती (404, 410), वे जो देरी के साथ पुनरावृत्त की जा सकती हैं (429, 500-504, टाइमआउट), और बाकी सब कुछ, जिसे तुरंत विफल माना जाता है बिना अतिरिक्त प्रयासों पर खर्च किए। यह विभाजन अपने आप में 20-30% अतिरिक्त ट्रैफ़िक को कम करता है सरल "सब कुछ दोहराने" की तुलना में।
सलाह: Retry-After हेडर को प्रोसेसिंग में जोड़ें —
कई साइटें स्वयं बताती हैं कि पुनरावृत्ति से पहले कितने सेकंड प्रतीक्षा करनी है। इस हेडर की अनदेखी करना —
अतिरिक्त बैन और ट्रैफ़िक का एक सामान्य कारण है।
सर्किट ब्रेकर: कब रुकना चाहिए
एक्सपोनेंशियल बैकऑफ़ एकल अनुरोध के स्तर पर मदद करता है, लेकिन उस स्थिति से नहीं बचाता है जब पूरा डोमेन या विशिष्ट प्रॉक्सी नोड अस्थायी रूप से सैकड़ों URL के लिए अनुपलब्ध होता है। यहां सर्किट ब्रेकर पैटर्न की आवश्यकता होती है — "स्वचालित स्विच", जो पिछले समय में त्रुटियों के हिस्से की निगरानी करता है और यदि यह सीमा से अधिक हो जाती है, तो अस्थायी रूप से प्रयासों को रोक देता है, बजाय इसके कि बंद दरवाजे पर लगातार दस्तक देते रहें।
class CircuitBreaker:
def __init__(self, failure_threshold=0.5, window_size=50, cooldown=60):
self.failure_threshold = failure_threshold
self.window_size = window_size
self.cooldown = cooldown
self.results = []
self.open_until = 0
def is_open(self):
return time.time() < self.open_until
def record(self, success: bool):
self.results.append(success)
if len(self.results) > self.window_size:
self.results.pop(0)
if len(self.results) == self.window_size:
failure_rate = 1 - sum(self.results) / self.window_size
if failure_rate > self.failure_threshold:
self.open_until = time.time() + self.cooldown
self.results.clear()
लॉजिक सरल है: यदि पिछले 50 अनुरोधों में से आधे से अधिक विफल हो गए, तो पार्सर उस डोमेन या प्रॉक्सी पर प्रयासों को 60 सेकंड के लिए रोक देता है। इस समय के दौरान, आप IP बदल सकते हैं, अनुरोधों की गति को कम कर सकते हैं या प्रॉक्सी के दूसरे पूल पर स्विच कर सकते हैं। यह विशेष रूप से महत्वपूर्ण है लक्षित साइटों के साथ काम करते समय, जो अनुरोधों की आवृत्ति बढ़ने पर IP रेंज को अस्थायी रूप से बैन कर देती हैं — बंद दरवाजे पर दस्तक देना केवल बेकार ट्रैफ़िक को जलाना है।
पुनरावृत्तियों के दौरान स्मार्ट प्रॉक्सी रोटेशन
अतिरिक्त retry के खिलाफ सबसे प्रभावी उपायों में से एक यह है कि उसी IP से अनुरोध को न दोहराएं, जिसने पहले ही अस्वीकृति प्राप्त की है। लॉजिक सरल है: यदि त्रुटि IP द्वारा अवरुद्ध होने से संबंधित है (403, 429, कैप्चा पर रीडायरेक्ट), तो पुनरावृत्ति से पहले प्रॉक्सी बदलना सफलता की संभावना को मौलिक रूप से बढ़ाता है और प्रयासों की संख्या को कम करता है।
Wildberries, Ozon या Avito जैसे मार्केटप्लेस के लिए पार्सिंग करते समय एक संयोजन अच्छा काम करता है: सामान्य अनुरोध डेटा सेंटर प्रॉक्सी के माध्यम से जाते हैं — ये तेज़ और सस्ते होते हैं, और जैसे ही ब्लॉकिंग डिटेक्टर लगातार कुछ बार सक्रिय होता है, पार्सर स्विच करता है रहवासी प्रॉक्सी पर, जो एंटी-बॉट सिस्टम के फ़िल्टर में कम आते हैं। यह हाइब्रिड दृष्टिकोण कुल ट्रैफ़िक की खपत को कम करता है, क्योंकि महंगे रहवासी IP केवल तब उपयोग किए जाते हैं जब वास्तव में इसकी आवश्यकता होती है, न कि सभी अनुरोधों के लिए।
| त्रुटि का प्रकार | पुनरावृत्ति की रणनीति | क्या IP बदलना आवश्यक है? |
|---|---|---|
| कनेक्शन टाइमआउट | बैकऑफ़, 1-2 पुनरावृत्तियाँ | नहीं |
| 403 / कैप्चा | तत्काल रोटेशन | हाँ, अनिवार्य |
| 429 (रेट लिमिट) | Retry-After के अनुसार बैकऑफ़ | वांछनीय |
| 500-503 | बैकऑफ़, 2-3 पुनरावृत्तियाँ | नहीं |
| 404 / 410 | कोई पुनरावृत्तियाँ नहीं | — |
उन पार्सर्स के लिए जो मोबाइल ट्रैफ़िक का अनुकरण करते हैं (उदाहरण के लिए, मार्केटप्लेस या सोशल नेटवर्क के मोबाइल संस्करणों से डेटा एकत्र करना), मोबाइल प्रॉक्सी का उपयोग करना समझदारी है — वे सुरक्षा प्रणालियों द्वारा संदेह को कम करते हैं क्योंकि संचार ऑपरेटर एक ही IP को हजारों वास्तविक उपयोगकर्ताओं को एक साथ प्रदान करते हैं, और लक्षित साइट के लिए बिंदु अवरोधन अप्रभावी हो जाता है।
retry-मैट्रिक्स की निगरानी
बिना मैट्रिक्स के retry-लॉजिक का ऑप्टिमाइजेशन अटकलों में बदल जाता है। प्रत्येक अनुरोध पर लॉग करने के लिए न्यूनतम सेट संकेतक:
- Retry दर — उन अनुरोधों का हिस्सा, जिन्हें कम से कम एक पुनरावृत्ति की आवश्यकता थी।
- पुनरावृत्ति के बाद सफलता — कितने प्रतिशत पुनरावृत्तियाँ अंततः सफल हुईं (यदि यह संकेतक कम है, तो पुनरावृत्तियाँ केवल ट्रैफ़िक को जलाती हैं)।
- सफल परिणाम पर ट्रैफ़िक — कुल भेजे गए डेटा की मात्रा, सफलतापूर्वक एकत्रित रिकॉर्डों की संख्या से विभाजित। यह प्रभावशीलता का एक प्रमुख मैट्रिक्स है।
- त्रुटियों का कोड के अनुसार वितरण — यह समझने में मदद करता है कि ट्रैफ़िक का मुख्य रिसाव कहाँ हो रहा है: टाइमआउट, 403, 429 या कुछ और।
- विशिष्ट प्रॉक्सी-नोड पर retry दर — यदि एक IP 80% की retry दर देता है, जबकि अन्य 10%, तो समस्या स्थानीय है और इसे विशिष्ट नोड को बदलकर हल किया जा सकता है, न कि पूरी लॉजिक को।
यहां तक कि Google Sheets में एक साधारण तालिका या CSV में लॉग, इन पांच मैट्रिक्स के साथ, जो हर घंटे अपडेट होती है, पर्याप्त डेटा प्रदान करती है ताकि विसंगतियों को देखा जा सके और समय पर रणनीति को समायोजित किया जा सके — उदाहरण के लिए, किसी साइट के विशेष अनुभाग में अनुरोधों की आवृत्ति को कम करना या पूल में रहवासी IP का हिस्सा बढ़ाना।
retry पर ट्रैफ़िक ऑप्टिमाइज़ेशन चेकलिस्ट
- त्रुटि कोड को retryable और non-retryable में विभाजित करें — 404/410 को पुनरावृत्ति न करें।
- फिक्स्ड देरी के बजाय जिटर के साथ एक्सपोनेंशियल बैकऑफ़ लागू करें।
- यदि साइट इसे भेजती है तो
Retry-Afterहेडर का सम्मान करें। - 403 और बॉट डिटेक्शन के संदेह पर पुनरावृत्ति से पहले IP बदलें।
- प्रयासों की संख्या पर एक कठोर सीमा निर्धारित करें (आमतौर पर 3-4 पर्याप्त होते हैं)।
- उच्च विफलता दर वाले डोमेन और प्रॉक्सी-नोड के लिए सर्किट ब्रेकर लागू करें।
- retry दर और सफल परिणाम पर ट्रैफ़िक को लॉग करें — बिना मैट्रिक्स के ऑप्टिमाइजेशन असंभव है।
- प्रॉक्सी पूल को विभाजित करें: स्थिर क्षेत्रों के लिए सस्ते डेटा सेंटर, समस्याग्रस्त के लिए रहवासी या मोबाइल IP।
निष्कर्ष
Retry-लॉजिक पार्सर का एक छोटा सा हिस्सा नहीं है, बल्कि डेटा संग्रह की लागत को प्रभावित करने वाले मुख्य कारकों में से एक है। सरल "सब कुछ दोहराने" की रणनीति वास्तविक ट्रैफ़िक को सिद्धांत न्यूनतम की तुलना में 40-90% बढ़ा सकती है, जबकि अधिकांश पुनरावृत्तियाँ पहले प्रयास की तरह ही विफल होती हैं। त्रुटियों को प्रकारों में विभाजित करना, एक्सपोनेंशियल बैकऑफ़, सर्किट ब्रेकर और IP का स्मार्ट रोटेशन इन नुकसानों को कई गुना कम करने की अनुमति देता है बिना एकत्रित डेटा की पूर्णता को खोए।
यदि आपका पार्सर उन साइटों के साथ काम करता है, जो बॉट्स का आक्रामक रूप से पता लगाते हैं — मार्केटप्लेस, सोशल नेटवर्क, विज्ञापन प्लेटफार्मों — तो कार्य के आधार पर विभिन्न प्रकार के प्रॉक्सी को संयोजित करना उचित है। बुनियादी संचालन के लिए डेटा सेंटर प्रॉक्सी उपयुक्त हैं, और जहां अधिकतम अवरोधन प्रतिरोध की आवश्यकता होती है — रहवासी प्रॉक्सी जो वास्तविक उपयोगकर्ताओं के IP पते के साथ हैं। इस हाइब्रिड दृष्टिकोण के साथ सही retry-लॉजिक के संयोजन से एकत्रित डेटा की मात्रा में कमी के साथ ट्रैफ़िक की खपत में उल्लेखनीय कमी आती है।