2025, Oct 16 17:31

Selenium में Relative Locators से आने वाला TypeError: कारण और समाधान

Selenium 4 में Relative Locators को element.find_element में देने पर TypeError क्यों आता है, और driver.find_element के साथ सही तरीका क्या है. व्यावहारिक सुझावों सहित

Selenium के रिलेटिव लोकेटर्स के साथ काम करते समय TypeError आना उलझा सकता है, खासकर तब जब मेथड सिग्नेचर से लगता है कि सब ठीक चलेगा। अगर आप WebElement पर find_element कॉल करते समय RelativeBy के JSON में सीरियलाइज़ न होने की अपवाद देखते हैं, तो यह गाइड बताती है कि यह क्यों होता है और बिना आपकी चुनी हुई सेलेक्टर लॉजिक बदले इसे कैसे ठीक करें।

समस्या को पुन: उत्पन्न करना

नीचे दिया गया उदाहरण समस्या समझाने के लिए सरल रखा गया है। वातावरण में Selenium 4.33.0 और Python 3.13.6 उपयोग किए गए हैं। कोड element-स्तर के find_element के साथ एक Relative Locator लगाने की कोशिश करता है, और यहीं त्रुटि आती है।

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
site_url = "https://www.lazyvim.org/"
browser = webdriver.Chrome(webdriver.ChromeOptions())
browser.maximize_window()
browser.get(site_url)
# डेमो के दौरान पेज देखने के लिए थोड़ी देर रुकें
time.sleep(3)
# सिर्फ डेमो के लिए इम्प्लिसिट वेट
browser.implicitly_wait(3)
# बायीं साइडबार
side_css = (By.CSS_SELECTOR, "div.sidebar_njMd")
side_panel = browser.find_element(*side_css)
# लिंक के दाईं ओर कैरेट बटन के लिए RelativeBy लोकेटर बनाएं
caret_rel = locate_with(
    By.CSS_SELECTOR, "button.clean-btn.menu__caret"
).straight_right_of({By.CSS_SELECTOR: 'a[href="/configuration"]'})
# समस्या वाली कॉल: element-स्तर के find_element में RelativeBy पास करना
caret_button = side_panel.find_element(caret_rel)
# कैरेट पर क्लिक करने का प्रयास
caret_button.click()
time.sleep(4)
browser.quit()

रन इस त्रुटि के साथ विफल होता है:

TypeError: Object of type RelativeBy is not JSON serializable

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

असल समस्या इस बात में है कि Selenium लोकेटर्स को WebDriver कमांड्स के जरिए कैसे भेजता है। locate_with से बने और RelativeBy के रूप में दर्शाए गए Relative Locators ड्राइवर स्तर पर समर्थित हैं। इसके विपरीत, जब आप किसी WebElement पर find_element कॉल करते हैं, तो Selenium एक सामान्य By लोकेटर की उम्मीद करता है, RelativeBy की नहीं। element.find_element में RelativeBy पास करने पर Selenium उस संदर्भ में अप्रत्याशित ऑब्जेक्ट को सीरियलाइज़ करने की कोशिश करता है, और यही JSON सीरियलाइज़ेशन त्रुटि पैदा करता है।

सरल शब्दों में: Relative Locators WebDriver इंस्टेंस के साथ काम करते हैं, WebElement इंस्टेंस के साथ नहीं। जैसे ही आप कॉल को driver.find_element के साथ RelativeBy पर ले आते हैं, त्रुटि गायब हो जाती है—भले ही पेज पर लक्षित तत्व वही हो।

समाधान

Relative Locators का उपयोग जारी रखें, बस find_element ड्राइवर पर कॉल करें। आप पहले एंकर तत्व खोजकर उसे WebElement के रूप में रिलेटिव चेन में पास करके स्कोप तय कर सकते हैं।

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
site_url = "https://www.lazyvim.org/"
browser = webdriver.Chrome(webdriver.ChromeOptions())
browser.maximize_window()
browser.get(site_url)
# डेमो में व्यवहार देखने के लिए रोकें
time.sleep(3)
# सिर्फ डेमो हेतु इम्प्लिसिट वेट
browser.implicitly_wait(3)
# बायीं साइडबार
side_panel = browser.find_element(By.CSS_SELECTOR, "div.sidebar_njMd")
# ड्राइवर-लेवल रिलेटिव लोकेटर का उपयोग करें; एंकर एक WebElement के रूप में रेसॉल्व होता है
caret_button = browser.find_element(
    locate_with(By.CSS_SELECTOR, "button.clean-btn.menu__caret").straight_right_of(
        side_panel.find_element(By.CSS_SELECTOR, 'a[href="/configuration"]')
    )
)
# कैरेट पर क्लिक करें
caret_button.click()
time.sleep(4)

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

यह जानना कि Relative Locators कहाँ समर्थित हैं, उलझाने वाली विफलताओं और ऐसे सीरियलाइज़ेशन एरर्स पर समय गंवाने से बचाता है जो सीधे गलत इस्तेमाल की ओर संकेत नहीं करते। साथ ही, जब आप एक ही प्रवाह में पारंपरिक By सेलेक्टर्स को रिलेटिव रणनीतियों के साथ मिलाते हैं, तो आपके टेस्ट स्थिर रहते हैं। driver.find_element और element.find_element के बीच का फर्क छोटा लग सकता है, लेकिन यहीं Selenium द्वारा ब्राउज़र को भेजे जाने वाले कमांड की पैकेजिंग बदल जाती है।

मुख्य निष्कर्ष

यदि आपको किसी लक्ष्य तत्व को किसी दूसरे तत्व के सापेक्ष चुनना है, तो पहले एंकर को WebElement के रूप में पाएँ और उसे ड्राइवर-लेवल Relative Locator में पास करें। RelativeBy को element.find_element में न दें; तत्व-स्तर की कॉल्स में सामान्य By लोकेटर्स ही होने चाहिए। अगर element-स्तर से driver-स्तर की कॉल पर स्विच करने से परिणाम बदल जाए, तो पेज पर एंकर और स्कोपिंग दोबारा जाँचें, पर मूल नियम याद रखें: Relative Locators ड्राइवर संदर्भ से संबंधित होते हैं।

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