गूगल खोज परिणामों को ट्रेस करने योग्य अनुरोध संदर्भ के साथ पृष्ठबद्ध करें
Expert Network Defense Engineer
TL;DR:
- गूगल सर्च एपीआई पेजिनेशन ने संग्रहित स्लाइस को बदल दिया है। हर प्रतिक्रिया के साथ
startऔर पूरी अनुरोध को रखें, बजाय इसके कि पृष्ठों को परस्पर विनिमेय बैचों के रूप में माना जाए। - केवल परिभाषित योजना और पुनरावलोकित प्रतिक्रिया अनुबंध के भीतर जारी रहें। उदाहरण में अगले लिंक की जांच की जाती है जो लौटाई गई है, इससे पहले कि ऑफसेट बदलें और अस्पष्ट निरंतरता डेटा पर रुकें।
- स्थगित कार्य और डुप्लिकेट अवलोकनों को दृश्यमान रखें। प्रत्येक कच्चे पृष्ठ प्रतिक्रिया को संग्रहित करें; डुप्लिकेशन एक व्युत्पन्न दृश्य की принадлежता है, और HTTP 201 एक खाली पृष्ठ नहीं है।
पेजिनेशन प्रयोग में बदलाव छिपा सकता है। एक संग्राहक संभवतः एक देश सेटिंग खोते हुए ऑफसेट को आगे बढ़ा सकता है, या एक स्थगित प्रतिक्रिया को पूर्ण पृष्ठों के साथ संयोजित कर सकता है और परिणाम को पूर्ण कह सकता है। परिणामी यूआरएल सूची यह नहीं बताती कि वे विभिन्नताएँ संग्रह में कैसे शामिल हुईं।
स्क्रैपलेस गूगल सर्च एपीआई start के माध्यम से खोज ऑफसेट का समर्थन करता है। यह गूगल सर्च एपीआई पेजिनेशन गाइड जानबूझकर सीमाबद्ध संग्रह में हर अनुरोध का एक रिकॉर्ड और रुकने का एक कारण बनाता है। यह हर परिणाम तक पहुंच का वादा किए बिना अनुप्रयोग नियंत्रण प्रवाह को प्रदर्शित करता है या एक अनवरत ऐतिहासिक रैंकिंग अनुक्रम को।
आवश्यकताएँ और सीमाबद्ध संग्रह योजना
कार्यक्रम पायथन के मानक पुस्तकालय का उपयोग करता है और वास्तविक संग्रह के लिए SCRAPELESS_API_KEY में एक खाता एपीआई कुंजी की आवश्यकता होती है। पर्यावरण-चर का नाम इस उदाहरण का एक मानक है। कुंजी को अनुरोध-शरीर लॉग और उत्पन्न कैप्चर फ़ाइलों के बाहर रखें।
गूगल सर्च पैरामीटर start को परिणाम ऑफसेट के रूप में वर्णित करते हैं, जिसमें 0, 10, और 20 के उदाहरण शामिल हैं। कार्यक्रम अपनी योजना को उन्हीं ऑफसेट तक सीमित करता है। यह एक अनुप्रयोग बंधित है, सेवा की अधिकतम गहराई के बारे में एक प्रवचन नहीं है या यह गारंटी नहीं है कि प्रत्येक पृष्ठ में जैविक आइटम की एक निश्चित संख्या होती है।
मूल क्वेरी coffee है जिसमें gl=us, hl=en, और डेस्कटॉप इनपुट शामिल हैं। ये सेटिंग एक चित्रात्मक अनुरोध कॉन्फ़िगरेशन हैं। इन्हें एक अवलोकित खोज नमूने के रूप में प्रस्तुत नहीं किया गया है। अपनी खुद की संग्रह की सीमा तय करने के बाद ही कॉन्फ़िगरेशन में परिवर्तन करें।
इस लेख के लिए प्रामाणिक अनुरोध निष्पादित नहीं किए गए क्योंकि कोई खाता कुंजी प्रदान नहीं की गई। स्थानीय परीक्षण निरंतरता और स्थिति तर्क को कृत्रिम प्रतिक्रियाओं के साथ परीक्षा करते हैं। वर्तमान प्रतिक्रिया व्यवहार को मान्य करने के लिए एक जीवित खाता चलाना एक आवश्यकता बनी हुई है।
हर कच्चे कैप्चर के बगल में पृष्ठ ऑफसेट रखें
गूगल सर्च अनुरोध कार्यप्रवाह scraper.google.search को POST https://api.scrapeless.com/api/v1/scraper/request पर प्रस्तुत करता है जिसमें x-api-token में प्रमाणीकरण होता है। संग्रहकर्ता प्रस्तुत किए गए शरीर को प्रतिक्रिया से अलग रिकॉर्ड करता है और ग्राहक टाइमस्टैम्प और अपने स्वयं के रन पहचानकर्ता को जोड़ता है।
HTTP 200 में कार्य डेटा होता है; HTTP 201 एक ऐसा कार्य प्रस्तुत करता है जो अभी भी प्रक्रिया में है। पिछली प्रतिक्रिया को रोकने से पहले सहेजने की आवश्यकता होती है। इसका कार्य पहचानकर्ता कच्ची प्रतिक्रिया में अलग से सत्यापित पूर्णता कार्यप्रवाह के लिए रहता है; यह उदाहरण एक कार्य-प्राप्ति अंत बिंदु का आविष्कार नहीं करता है।
कैप्चर लिफाफा अनुप्रयोग-स्वामित्व वाला है। इसका request, response, टाइमस्टैम्प, और त्रुटि फ़ील्ड को मूल एपीआई लपेटने वाले के रूप में नहीं परिकल्पित किया गया है। इन्हें अलग रखना JSON डेटा मॉडल का पालन करता है और एक बाद के मैपर के लिए अंतर्निहित साक्ष्य को बरकरार रखता है।
आगे बढ़ने से पहले निरंतरता साक्ष्य की जांच करें
त्वरित उत्तर उदाहरण में pagination.next शामिल है, लेकिन नमूना यूआरएल संक्षिप्त है। उस संक्षिप्त मान को निष्पादित न करें। कोड को इसके ऑफसेट को निरंतरता संकेत के रूप में उपयोग करने से पहले वास्तविक, नॉनट्रंकटेड HTTPS गूगल सर्च यूआरएल की आवश्यकता होती है।
उदाहरण केवल पुनरावलोकित गूगल होस्ट को स्वीकार करता है और यह जांचता है कि लौटे लिंक में क्वेरी, देश, और भाषा मूल कॉन्फ़िगरेशन से मेल खाती है या नहीं। यह सभी प्रस्तुत की गई मूल सेटिंग्स को बरकरार रखता है और केवल start को बदलता है। अगले लिंक में एक गायब देश फ़ील्ड एक समीक्षा रोकने का कारण बनता है, सेवा ने क्या इरादा रखा था उसके बारे में अनुमान नहीं।
ये जांचें यूआरएल घटक पार्सिंग का उपयोग करती हैं। ये अनुप्रयोग की संकीर्ण निरंतरता नीति को परिभाषित करती हैं, हर मान्य गूगल यूआरएल को नहीं। संग्रहकर्ता कभी भी लौटे हुए यूआरएल का सीधे अनुसरण नहीं करता; यह पुनरावलोकित पैरामीटर-मोड शरीर के साथ उसी एपीआई एंडपॉइंट पर अगले अनुरोध को भेजता है।
स्पष्ट रोक कारण के साथ संग्राहक चलाएँ
प्रोग्राम को paginate_search.py के रूप में सहेजें। अपने कुंजी को वातावरण में सेट करने के बाद, python3 paginate_search.py को एक writable डायरेक्टरी में चलाएं। स्क्रिप्ट एक विशेष रूप से नामित आउटपुट डायरेक्टरी बनाती है, अनुक्रमिक रूप से अनुरोध भेजती है, और प्रत्येक पृष्ठ कैप्चर के साथ collection-summary.json रखती है।
नोट: लाइव API संग्रह एक पूर्वापेक्षा है और इस लेख के लिए प्रदर्शन नहीं किया गया था। कोड के स्थानीय नियंत्रण प्रवाह का परीक्षण सिन्थेटिक प्रतिक्रियाओं का उपयोग करके किया गया था। अगले लिंक नीति पर भरोसा करने से पहले वास्तविक खाता आउटपुट का निरीक्षण करें, और यदि अनुरोध HTTP 201 लौटाता है, तो कार्य पुनर्प्राप्ति को अलग से सत्यापित करें।
python
import json
import os
import uuid
from datetime import datetime, timezone
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.parse import parse_qs, urlsplit
from urllib.request import Request, urlopen
ENDPOINT = 'https://api.scrapeless.com/api/v1/scraper/request'
OFFSETS = (0, 10, 20)
BASE = {'q': 'coffee', 'gl': 'us', 'hl': 'en', 'device': 'desktop'}
def now():
return datetime.now(timezone.utc).isoformat()
def fetch(body, key):
request = Request(ENDPOINT, data=json.dumps(body).encode(), method='POST',
headers={'Content-Type': 'application/json', 'x-api-token': key})
try:
with urlopen(request, timeout=60) as response:
status, raw = response.status, response.read().decode('utf-8')
except HTTPError as error:
status, raw = error.code, error.read().decode('utf-8', errors='replace')
except (URLError, TimeoutError) as error:
return None, None, type(error).__name__
try:
return status, json.loads(raw), None
except json.JSONDecodeError:
return status, {'unparsed_body': raw}, 'response_not_json'
def next_offset(payload, current):
pagination = payload.get('pagination')
link = pagination.get('next') if isinstance(pagination, dict) else None
if not isinstance(link, str) or not link:
return None, 'next_link_unavailable'
try:
parts = urlsplit(link)
if (parts.scheme != 'https' or parts.hostname not in ('google.com', 'www.google.com')
or parts.username or parts.password or parts.port or parts.path != '/search'
or parts.fragment or '...' in link or '…' in link):
return None, 'next_link_needs_review'
query = parse_qs(parts.query, keep_blank_values=True)
if any(query.get(k) != [BASE[k]] for k in ('q', 'gl', 'hl')):
return None, 'next_context_needs_review'
values = query.get('start', [])
if len(values) != 1 or not values[0].isascii() or not values[0].isdigit():
return None, 'next_offset_needs_review'
offset = int(values[0])
if offset <= current or offset not in OFFSETS:
return None, 'next_offset_outside_plan'
return offset, None
except ValueError:
return None, 'next_link_needs_review'
def collect(directory, key):
directory = Path(directory)
directory.mkdir(parents=True, exist_ok=False)
seen, visited, pages = set(), set(), []
offset, stop = 0, None
while offset in OFFSETS and offset not in visited:
visited.add(offset)
body = {'actor': 'scraper.google.search', 'input': dict(BASE, start=offset)}
started = now()
status, payload, error = fetch(body, key)
run_id = uuid.uuid4().hex
capture = {'run_id': run_id, 'requested_at': started, 'received_at': now(),
'request': body, 'http_status': status, 'response': payload, 'error': error}
filename = f'{offset}-{run_id}.json'
(directory / filename).write_text(json.dumps(capture, ensure_ascii=False, indent=2), encoding='utf-8')
page = {'start': offset, 'capture': filename, 'new_exact_urls': None}
pages.append(page)
if status == 201:
stop = 'pending'
break
if status != 200 or error:
stop = 'collection_error'
break
rows = payload.get('organic_results') if isinstance(payload, dict) else None
if not isinstance(rows, list) or any(not isinstance(row, dict) for row in rows):
stop = 'unmapped_organic_results'
break
links = {row['link'] for row in rows if isinstance(row.get('link'), str) and row['link']}
page['new_exact_urls'] = len(links - seen)
seen.update(links)
if not rows:
stop = 'empty_organic_slice'
break
if not links:
stop = 'no_usable_link_strings'
break
if page['new_exact_urls'] == 0:
stop = 'no_new_exact_urls'
break
if len(visited) == len(OFFSETS):
stop = 'planned_page_limit'
break
offset, stop = next_offset(payload, offset)
if stop:
break
summary = {'pages': pages, 'stop_reason': stop, 'unique_exact_url_strings': len(seen)}
(directory / 'collection-summary.json').write_text(json.dumps(summary, indent=2), encoding='utf-8')
return summary
if __name__ == '__main__':
key = os.environ['SCRAPELESS_API_KEY']
output = 'search-pages-' + uuid.uuid4().hex
print(json.dumps(collect(output, key), indent=2))
टाइमआउट एक स्थानीय क्लाइंट सेटिंग है, सेवा प्रदर्शन दावा नहीं। एक परिवहन अपवाद या गैर-JSON प्रतिक्रिया एक त्रुटि रिकॉर्ड उत्पन्न करती है और संग्रह को रोकती है। प्रोग्राम पहले के कैप्चर को रखता है न कि एक आंशिक रन को एक संपूर्ण स्वीप के रूप में प्रस्तुत करता है।
Scrapeless के साथ स्क्रैपिंग शुरू करें
Scrapeless के साथ अपनी वेब स्क्रैपिंग और ऑटोमेशन वर्कफ़्लो को पावर अप करें!
आज ही साइन अप करें और $5 फ्री क्रेडिट प्राप्त करें — क्रेडिट कार्ड की आवश्यकता नहीं।अपने मुफ्त क्रेडिट को Scrapeless डैशबोर्ड में अभी क्लेम करें।
खोज साक्ष्य से डुप्लिकेशन को अलग करें
संक्षेप में प्रत्येक पृष्ठ पर नए सटीक URL स्ट्रिंग्स की गिनती की जाती है जबकि हर मूल प्रतिक्रिया को बनाए रखा जाता है। बार-बार आने वाले URLs उन कैप्चर में उनके पृष्ठ संदर्भ के साथ रहते हैं। यह एक समीक्षक को ओवरलैप का निरीक्षण करने की अनुमति देता है न कि इसे निर्यात के दौरान खोने के।
सटीक-स्ट्रिंग डुप्लिकेशन जानबूझकर संकीर्ण है। यह ट्रैकिंग विविधताओं, टुकड़ों, कैनोनिकल URLs, या एक डोमेन से विभिन्न पृष्ठों को मिलाता नहीं है। एक व्यापक grouping नीति को एक अलग संस्करणित रूपांतरण में होना चाहिए और इसे मूल लिंक को बनाए रखना चाहिए।
प्रोग्राम तब रुकता है जब एक उपयोगी पृष्ठ कोई नया सटीक URL स्ट्रिंग योगदान नहीं करता। यह संग्रह-बजट निर्णय है, यह प्रमाण नहीं है कि और कोई प्रासंगिक पृष्ठ नहीं हैं। इसी तरह, एक मौजूदा खाली जैविक ऐरे इस रन को बिना Exhaustive खोज सीमा के स्थापित किए रोक देती है।
आंशिक संग्रह की ईमानदारी से व्याख्या करें
उस URL गिनती का उपयोग करने से पहले संक्षेप के रोकने के कारण को पढ़ें। planned_page_limit का अर्थ है कि स्थानीय सीमा तक पहुंच गई थी। next_link_unavailable का अर्थ है कि निरंतरता स्थापित नहीं की गई। लंबित, अनमैप्ड, और संग्रह-त्रुटि स्थितियाँ अधूरी या अनुपयोगी साक्ष्यों का वर्णन करती हैं, सफल परिणामों की पहचान नहीं करतीं।
प्रत्येक अनुरोध का अपना टाइमस्टैम्प होता है। अनुक्रमिक पृष्ठ एक साथ संग्रहित नहीं किए गए थे, और प्रोग्राम कॉल के बीच साझा सर्वर सत्र का दावा नहीं करता। इस रन की तुलना करते समय संग्रह विंडो को संरक्षित करें।
प्रभावना मॉडल कच्चे पृष्ठ अवलोकनों, संग्रह गतिविधि, और एक व्युत्पन्न डुप्लीकेटेड सूची को अलग करने में मदद करता है। एक छोटा फ़ाइल सिस्टम लेआउट उन संबंधों को बनाए रख सकता है यदि संक्षेप हर कैप्चर की ओर इशारा करता है।
निष्कर्ष
एक सीमित संग्रह की योजना बनाएँ, प्रत्येक प्रस्तुत अनुरोध को संरक्षित करें, और केवल तब आगे बढ़ें जब प्रतिक्रिया आवेदन की निरंतरता नियम का समर्थन करती है। स्पष्ट रोकने के कारण और रखी गई डुप्लीकेट्स एक आंशिक डेटा सेट को समझने योग्य बनाते हैं बिना यह दावा किए कि यह प्रत्येक Google परिणाम को शामिल करता है।
एक SERP स्नैपशॉट डेटा सेट दृष्टिकोण संग्रहीत अवलोकनों को व्यवस्थित करने में मदद कर सकता है; तुलना करते समय पृष्ठ ऑफसेट्स को दृश्यमान रखें।
अगले खोज अवलोकन का निर्माण करें
इस वर्कफ़्लो में खोज डेटा के लिए Scrapeless Google Search API का उपयोग करें। संग्रह की योजना बनाते समय Scrapeless मूल्य निर्धारण की समीक्षा करें, और अपनी कॉन्फ़िगरेशन के पास Google खोज पैरामीटर रखें।
समुदाय में Discord या Telegram पर अपनी कार्यान्वयन चर्चा करें।
अक्सर पूछे जाने वाले प्रश्न
प्रश्न: क्या start=10 दस जैविक पंक्तियों की गारंटी देता है?
नहीं। start एक ऑफसेट निर्दिष्ट करता है। अनुरोधित ऑफसेट से इसकी लंबाई निकालने के बजाय वास्तविक जैविक ऐरे का निरीक्षण करें।
प्रश्न: क्या यह स्क्रिप्ट प्रत्येक Google परिणाम को एकत्र करती है?
नहीं। यह एक छोटे अनुप्रयोग योजना द्वारा बाउंडेड है और जब निरंतरता या उपयोगी डेटा अनुपलब्ध होता है तो रुक जाती है।
प्रश्न: HTTP 201 का क्या होता है?
प्रतिक्रिया सहेज ली गई है और संग्रह रुक गया है जैसा कि लंबित है। अंतिम खोज डेटा की व्याख्या करने से पहले एक सत्यापित कार्य-पूर्णता वर्कफ़्लो की आवश्यकता है।
प्र: जब अगला लिंक संदर्भ फ़ील्ड को छोड़ देता है तो क्यों रुकें?
उदाहरण के लिए स्पष्ट क्वेरी, देश और भाषा के अनुबंध की आवश्यकता होती है। गायब साक्ष्य समीक्षा को उत्तेजित करता है न कि निरंतरता के बारे में मौन अनुमान लगाने के लिए।
प्र: क्या कच्चे कैप्चर से दोहराए गए URLs हटा दिए जाते हैं?
नहीं। केवल सारांश के सटीक-स्ट्रिंग गिनती को डेडुप्लिकेट किया जाता है। मूल अवलोकन निरीक्षण के लिए उपलब्ध रहते हैं।
स्क्रैपलेस में, हम केवल सार्वजनिक रूप से उपलब्ध डेटा का उपयोग करते हैं, जबकि लागू कानूनों, विनियमों और वेबसाइट गोपनीयता नीतियों का सख्ती से अनुपालन करते हैं। इस ब्लॉग में सामग्री केवल प्रदर्शन उद्देश्यों के लिए है और इसमें कोई अवैध या उल्लंघन करने वाली गतिविधियों को शामिल नहीं किया गया है। हम इस ब्लॉग या तृतीय-पक्ष लिंक से जानकारी के उपयोग के लिए सभी देयता को कोई गारंटी नहीं देते हैं और सभी देयता का खुलासा करते हैं। किसी भी स्क्रैपिंग गतिविधियों में संलग्न होने से पहले, अपने कानूनी सलाहकार से परामर्श करें और लक्ष्य वेबसाइट की सेवा की शर्तों की समीक्षा करें या आवश्यक अनुमतियाँ प्राप्त करें।



