2025, Oct 19 06:32

Headless Chrome में Selenium फेल होने पर Access Denied का समाधान

headless Chrome में Selenium के फेल होने की असली वजह जानें: Access Denied की पहचान, page source डंप, और User-Agent व स्क्रीन मेट्रिक्स सेट कर स्थिर, समान रन पाएं.

हेडलेस Selenium अक्सर सामान्य ब्राउज़र विंडो जैसा व्यवहार नहीं करता। एक आम संकेत यह है कि वही स्क्रिप्ट जो दिखाई देने वाले Chrome सत्र में चलती है, headless मोड में पहले ही एलिमेंट-लुकअप पर फेल हो जाती है। नीचे एक व्यावहारिक उदाहरण है, जहाँ दृश्य ब्राउज़र में ID से इनपुट ढूँढना सफल होता है, लेकिन headless Chrome में त्रुटि आती है—और फिर दोनों मोड्स को एक जैसा व्यवहार करवाने का तरीका।

दिखने वाले ब्राउज़र में काम करने वाला उदाहरण

यह स्निपेट FAA runway safety diagrams पेज खोलता है, id=ident वाले इनपुट में कोड दर्ज करता है, फ़ॉर्म सबमिट करता है, परिणाम तालिका को स्कैन करता है और अपेक्षित डोमेन से मेल खाने वाली पहली लिंक लौटाता है।

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import webbrowser
def locate_faa_diagram_url(icao):
    browser = webdriver.Chrome()
    browser.get("https://www.faa.gov/airports/runway_safety/diagrams/")
    search_box = browser.find_element(By.ID, "ident")
    search_box.send_keys(icao)
    search_box.send_keys(Keys.RETURN)
    grid = browser.find_element(By.XPATH, "//table")
    anchors = grid.find_elements(By.TAG_NAME, "a")
    for a in anchors:
        link_url = a.get_attribute("href")
        if link_url:
            if "aeronav.faa" in link_url:
                print(link_url)
                return link_url
webbrowser.open(locate_faa_diagram_url("ATL"))

हेडलेस मोड में वही प्रवाह, लेकिन त्रुटि

हेडलेस मोड पर स्विच करने पर स्क्रिप्ट ID के आधार पर इनपुट फ़ील्ड ढूँढते ही फेल हो जाती है। विंडो को छोटा करना या विंडो का आकार सेट करना इस समस्या को नहीं सुलझाता।

from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
import webbrowser
def locate_faa_diagram_url_headless(icao):
    opts = Options()
    opts.add_argument("--headless")
    opts.add_argument("--window-size=1920x1080")
    browser = webdriver.Chrome(options=opts)
    browser.get("https://www.faa.gov/airports/runway_safety/diagrams/")
    search_box = browser.find_element(By.ID, "ident")  # हेडलेस में यहीं त्रुटि आती है
    search_box.send_keys(Keys.RETURN)
    grid = browser.find_element(By.XPATH, "//table")
    anchors = grid.find_elements(By.TAG_NAME, "a")
    for a in anchors:
        link_url = a.get_attribute("href")
        if link_url:
            if "aeronav.faa" in link_url:
                print(link_url)
                return link_url
webbrowser.open(locate_faa_diagram_url_headless("ATL"))

एयरपोर्ट कोड टाइप करने वाला कीस्ट्रोक भी इसी प्रवाह का हिस्सा होना चाहिए, लेकिन उसकी अनुपस्थिति एलिमेंट-लुकअप के फेल होने का कारण नहीं है; विफलता इससे पहले ही हो जाती है।

असल में हो क्या रहा है

हेडलेस मोड में साइट ऐक्सेस रोक देती है और अपेक्षित सामग्री के बजाय Access Denied पेज देती है। नतीजतन ड्राइवर एक अलग दस्तावेज़ में ID से एलिमेंट ढूँढने की कोशिश करता है, इसलिए लुकअप फेल हो जाता है।

<html>
 <head>
  <title>Access Denied</title>
 </head>
 <body>
  <h1>Access Denied</h1>
  You don't have permission to access "http://www.faa.gov/airports/runway_safety/diagrams/" on this server.
  <p>Reference #18.56633b8.1754209447.14b9f2c8</p>
  <p>https://errors.edgesuite.net/18.56633b8.1754209447.14b9f2c8</p>
 </body>
</html>

यह अंतर इसलिए आता है क्योंकि headless Chrome अपनी पहचान अलग तरीके से भेजता है और एंटी-बॉट/CDN परतें उसे अलग तरह से संभालती हैं। हेडलेस मोड आम तौर पर थोड़ा अलग User-Agent स्ट्रिंग और कुछ डिफ़ॉल्ट सेटिंग्स (जैसे viewport) भेजता है, और कुछ इंफ्रास्ट्रक्चर इसके जवाब में ब्लॉक कर देते हैं या कम किया हुआ मार्कअप देते हैं। एक प्रचलित User-Agent पास करने से headed और headless रन के बीच का फर्क घट जाता है।

कैसे जाँचें कि आपको ब्लॉक किया गया है

नेविगेशन के तुरंत बाद पेज सोर्स डंप करें और देखें कि वास्तव में क्या मिला। अगर अपेक्षित पेज की जगह Access Denied दस्तावेज़ दिखे, तो एलिमेंट लुकअप इसलिए फेल होगा क्योंकि DOM वही नहीं है।

from bs4 import BeautifulSoup
# इसे browser.get(...) के तुरंत बाद रखें
dom = BeautifulSoup(browser.page_source)
with open("faa_dump.html", "w", encoding="utf-8") as fh:
    fh.writelines(dom.prettify())

समाधान: headless Chrome में User-Agent सेट करें

Chrome options में एक User-Agent स्ट्रिंग जोड़ें। इससे headless सत्र सामान्य डेस्कटॉप Chrome जैसा दिखेगा और पेज वैसा ही लोड होगा जैसा दृश्य सत्र में होता है।

from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
import webbrowser
def fetch_diagram_link_headless(icao):
    opts = Options()
    opts.add_argument("--headless")
    opts.add_argument("--window-size=1920x1080")
    opts.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
    browser = webdriver.Chrome(options=opts)
    browser.get("https://www.faa.gov/airports/runway_safety/diagrams/")
    search_box = browser.find_element(By.ID, "ident")
    search_box.send_keys(icao)
    search_box.send_keys(Keys.RETURN)
    grid = browser.find_element(By.XPATH, "//table")
    anchors = grid.find_elements(By.TAG_NAME, "a")
    for a in anchors:
        link_url = a.get_attribute("href")
        if link_url:
            if "aeronav.faa" in link_url:
                print(link_url)
                return link_url
webbrowser.open(fetch_diagram_link_headless("ATL"))

यदि आपका प्रवाह किसी खास viewport पर निर्भर है, तो ध्यान दें कि आधुनिक headless Chrome में सामान्य window-size स्विच हमेशा लागू नहीं होते। स्क्रीन मेट्रिक्स स्पष्ट रूप से निर्धारित करने के लिए यह वैकल्पिक फ्लैग उपयोग कर सकते हैं: --screen-info={0,0 1920x1080}.

यह क्यों मायने रखता है

हेडलेस ऑटोमेशन CI पाइपलाइनों और सर्वर‑साइड स्क्रैपिंग की नींव है। जब कोई साइट हेडलेस सत्रों को अलग तरह से पहचानती या संभालती है, तो आपके टेस्ट या डेटा संग्रह वास्तविक व्यवहार से चुपचाप अलग हो सकते हैं। User-Agent मिलाने से ये असंगतियाँ घटती हैं और वे नाज़ुक स्क्रिप्ट्स बचती हैं जो लोकल में पास होती हैं लेकिन ऑटोमेशन में फेल होती हैं। जो DOM वास्तव में मिला है उसकी पुष्टि करने से आप काल्पनिक सेलेक्टर समस्याओं के पीछे भागने से बचते हैं, जब असली मुद्दा अपस्ट्रीम ऐक्सेस कंट्रोल होता है।

मुख्य बातें

यदि कोई स्क्रिप्ट दृश्य ब्राउज़र में चलती है लेकिन उन्हीं सेलेक्टर्स पर हेडलेस मोड में विफल होती है, तो पहले यह पक्का करें कि आपको कौन‑सा HTML मिला। अगर साइट Access Denied दस्तावेज़ या काट‑छाँट किया हुआ मार्कअप दे रही है, तो एक प्रचलित User-Agent सेट करके हेडलेस सत्र को सामान्य ब्राउज़र जैसा बना दें। फ़ॉर्म सबमिट करने से पहले मान दर्ज करना समेत पूरा फ्लो बरकरार रखें, और हेडलेस मोड में केवल window-size स्विच पर निर्भर न रहें; ज़रूरत पड़े तो स्क्रीन मेट्रिक्स स्पष्ट रूप से परिभाषित करें। इससे आपके हेडलेस रन पूर्वानुमेय रहते हैं और वास्तविक उपयोगकर्ता व्यवहार के करीब।

यह लेख StackOverflow के एक प्रश्न (लेखक: RJTTAZ) और Ajeet Verma के उत्तर पर आधारित है।