2025, Oct 05 11:32
Playwright Python sync API में कई select को एक ही विकल्प पर सेट करें
Playwright Python sync API से कई HTML select पर एक ही विकल्प सेट करने के विश्वसनीय तरीके: query_selector_all या Locator + wait_for के साथ select_option सीखें
कई HTML select तत्वों पर एक ही मान सेट करना सुनने में आसान लगता है, लेकिन API असंगतता या टाइमिंग से जुड़ी दिक्कतें आते ही यह काम चिढ़ाने वाला हो सकता है। अगर आप Playwright की Python sync API इस्तेमाल कर रहे हैं और पेज पर मौजूद हर select को किसी खास विकल्प पर स्विच करना चाहते हैं, तो इसे बिना अप्रत्याशित समस्याओं के ऐसे करें।
समस्या को दोहराना
पेज में कई select तत्व हैं, उदाहरण के लिए:
<select class="sc-fzXfMv sc-fzXfMw dRuVWn">
  <option value="json">JSON</option>
  <option value="text">Text</option>
  <option value="raw">Hex</option>
</select>
शुरुआती कोशिशों में इटरेट करके विकल्प सेट करने पर missing attributes और non-iterable locators जैसी त्रुटियाँ मिलीं:
# प्रयास 1
pg.locator("select").all()    # AttributeError: 'Locator' ऑब्जेक्ट में 'all' नामक attribute नहीं है
# प्रयास 2
pg.query_selector_all("select")    # AttributeError: 'Page' ऑब्जेक्ट में 'query_selector_all' नामक attribute नहीं है
# प्रयास 3
for ddl in pg.locator("select"):
    ddl.select_option("raw")        # TypeError: 'Locator' ऑब्जेक्ट iterable नहीं है
# प्रयास 4
sels = pg.locator("select")
for s in sels:
    s.select_option("raw")          # वही त्रुटि, iterable नहीं है
असल में हो क्या रहा है
समस्या का मूल दो हिस्सों में बँटा है। पहला, Locator कोई ऐसी चीज़ नहीं है जिस पर आप सीधे लूप चला सकें; यह केवल एक क्वेरी का प्रतिनिधित्व करता है जो कई एलिमेंट्स से मेल खा सकती है, पर खुद iterable नहीं होता। दूसरा, टाइमिंग मायने रखती है। यदि select अभी मौजूद या दृश्य नहीं हैं, तो वे ऑपरेशन जो उनके मौजूद या इंटरैक्टेबल होने पर निर्भर हैं, विफल हो जाएँगे। इसलिए या तो शुरुआत में एलिमेंट्स की ठोस सूची निकालना ज़रूरी है, या लोकेटर को सूची में बदलने से पहले उचित इंतज़ार करना चाहिए।
दो कारगर तरीके
पहला तरीका है select तत्वों की ठोस सूची लेना और उस पर इटरेट करना। इसमें query_selector_all का उपयोग होता है और हर एलिमेंट पर इच्छित विकल्प चुना जाता है:
dropdown_nodes = pg.query_selector_all("select")
for node in dropdown_nodes:
    node.select_option("raw")
वैकल्पिक रूप से, आप लोकेटर्स के साथ रह सकते हैं और इंतज़ार करने के बाद ही उन्हें सूची में बदल सकते हैं। इंतज़ार करने से सुनिश्चित होता है कि इटरेट करने से पहले एलिमेंट्स तैयार हों। नीचे wait_for के बाद all का उपयोग किया गया है:
menus = pg.locator("select")
menus.first.wait_for(state="attached")
for item in menus.all():
    item.select_option("raw")
डिफ़ॉल्ट visible प्रतीक्षा-प्रीडिकेट पर भरोसा करना भी व्यावहारिक हो सकता है। यह रूपांतर सभी को गिनने से पहले पहले मेल खाते select के दृश्य होने का इंतज़ार करता है:
lists = pg.locator("select")
lists.first.wait_for()
for dd in lists.all():
    dd.select_option("raw")
यदि आपकी समस्या यह निकली कि एलिमेंट्स अभी दृश्य ही नहीं थे, तो यही wait चरण भरोसेमंदी की कुंजी है।
यह क्यों मायने रखता है
Playwright की sync API शक्तिशाली ऑटो-वेटिंग सेमांटिक्स देती है, लेकिन फिर भी सही एब्स्ट्रैक्शन स्तर चुनना पड़ता है। Locator पर सीधे इटरेट करना काम नहीं करेगा, और DOM तैयार होने से पहले चयन करने की हड़बड़ी अनावश्यक त्रुटियों को जन्म देती है। query_selector_all के साथ ठोस सूची निकालकर उसे गिनने या Locator पर इंतज़ार करके बाद में all का उपयोग करने से आपका कोड स्पष्ट और सुदृढ़ रहता है। यदि कई एलिमेंट्स मेल खाते हों, तो wait_for के लिए first का उपयोग सख्त परिदृश्यों में दिक्कतें भी टाल देता है।
निष्कर्ष और व्यावहारिक सलाह
जब आपको कई select तत्वों पर एक ही मान सेट करना हो, तो इन दो सुरक्षित पैटर्नों में से एक अपनाएँ। या तो query_selector_all से एलिमेंट्स की सूची लें और उस पर लूप चलाएँ, या Locator के साथ प्रतीक्षा करें और इटरेशन से पहले all के जरिए उसे फैलाएँ। यदि पेज असिंक्रोनस तरीके से सामग्री बनाता है, तो गिनती से पहले wait_for जोड़ें, और एलिमेंट्स के इंटरैक्शन के लिए तैयार होने की पुष्टि करने हेतु डिफ़ॉल्ट visible प्रीडिकेट पर भरोसा करने पर विचार करें। ये चुनाव कोड को संक्षिप्त और पूर्वानुमेय रखते हैं और Playwright के आशयित उपयोग के अनुरूप भी।