स्क्रेपलेस स्क्रेपिंग ब्राउज़र के साथ फॉर्म इनपुट वैलिडेशन
Lead Scraping Automation Engineer
TL;DR:
element.valueको सीधे असाइन करने से कोई इवेंट नहीं फायर होते। एक मापी गई रन में, सीधे असाइनमेंट ने एक खाली इवेंट सूची उत्पन्न की जबकिlocator.fill()नेfocus,beforeinput, औरinputउत्पन्न किए — मूल्य DOM में किसी भी तरह से पहुँचता है, इसलिए विफलता मौन है।- सीधा असाइनमेंट अभी भी HTML5 प्रतिबंध मान्यता को संतुष्ट करता है और अभी भी
FormDataको भरता है।valueको सेट करना ब्राउज़र द्वारा अस्वीकृत नहीं किया गया है; यह बस अवेक्षित है, और जो टूटता है वह कोई पृष्ठ तर्क है जो घटनाओं का प्रतिक्रिया करता है। - वे क्षेत्र जो वास्तव में टूटते हैं, वे हैं जिन पर अन्य क्षेत्रों को निर्भर करते हैं। सीधा एक
<select>का मूल्य सेट करने से संबंधित इनपुट छिपा रह गया और सबमिट बटन निष्क्रिय हो गया, जबकिselectOption()ने दोनों को प्रकट किया। - JavaScript तारीख चुनने वाले आपके द्वारा टाइप किए गए को त्याग सकते हैं। एक सार्वजनिक तारीख क्षेत्र पर, भरने के बाद Escape दबाने या क्लिक करने से वह क्षेत्र एक खाली स्ट्रिंग पर लौट आया; Enter के साथ प्रतिबद्धता ने विजेट के अपने सामान्यीकृत प्रारूप को उत्पन्न किया।
setInputFiles()काम करता है हालांकि ब्राउज़र आपके मशीन पर नहीं है। Playwright स्थानीय फ़ाइल को दूरस्थ सत्र में स्ट्रीम करता है, और अपलोड सबमिट किए गए फ़ॉर्म डेटा में दिखाई देता है।- मान्यता त्रुटियाँ स्क्रीनशॉट के बिना पढ़ने योग्य हैं।
validity,validationMessage, और एक अवरुद्धrequestSubmit()स्पष्ट रूप से बताते हैं कि कौन सा प्रतिबंध विफल हुआ और क्यों। - शुरू करने के लिए स्वतंत्र। नए Scrapeless खातों में मुफ्त Scraping Browser रनटाइम शामिल है — app.scrapeless.com पर साइन अप करें।
क्यों भरे हुए क्षेत्र में कोई उपयोगी रूप नहीं हो सकता
एक फ़ॉर्म फ़ील्ड सही पाठ रख सकता है और फिर भी कुछ उपयोगी सबमिट नहीं कर सकता। मूल्य DOM में है, स्क्रीनशॉट सही दिखता है, और पृष्ठ ऐसा व्यवहार करता है मानो फ़ील्ड को कभी छुआ नहीं गया — अगला फ़ील्ड कभी प्रकट नहीं होता, सबमिट बटन निष्क्रिय रहता है, या एक मान्यता संदेश जो पृष्ठ स्वयं प्रस्तुत करता है कभी साफ नहीं होता।
कारण मूल्य नहीं है। यह वे घटनाएँ हैं जो उसके साथ कभी प्रेषित नहीं की गईं। आधुनिक फ़ॉर्म्स आमतौर पर सबमिट समय पर कच्चे DOM मूल्यों को नहीं पढ़ते; वे input और change की सदस्यता लेते हैं, अपने राज्य की एक प्रति रखते हैं, और सभी अन्य चीज़ों को उसी प्रति से प्रवाहित करते हैं। .value पर लिखें और आप DOM को अपडेट करते हैं जबकि हर सदस्य को अनजान छोड़ देते हैं।
यह गाइड इस व्यवहार को सिद्ध करने के बजाय मापता है, फिर उन विजेट वर्गों के माध्यम से काम करता है जहाँ यह अंतर वास्तव में प्रकट होता है: निर्भर चयन, JavaScript तारीख चुनने वाले, फ़ाइल इनपुट, और फ़ॉर्म जो सबमिशन को सीधे अस्वीकार करते हैं। नीचे दिया गया सब कुछ Playwright पर Scrapeless Scraping Browser से जुड़ा हुआ चलता है, एक अनुकूलन योग्य, विरोधी-डिटेक्शन क्लाउड ब्राउज़र जो आत्म-निर्मित क्रोमियम द्वारा संचालित है। यदि आप पहले भरने और सबमिट करने के मूलभूत सिद्धांत की आवश्यकता है, तो Puppeteer फ़ॉर्म सबमिशन गाइड उस क्षेत्र को कवर करता है।
आवश्यकताएँ
- Node.js 18 या नया
- एक Scrapeless खाता और API कुंजी — app.scrapeless.com पर साइन अप करें
- CSS चयनकर्ताओं और DOM घटना मॉडल का कार्यकारी ज्ञान
इंस्टॉल करें
ब्राउज़र दूरस्थ है, इसलिए playwright-core आपको केवल यही चाहिए — कोई बंडल किया हुआ क्रोमियम डाउनलोड नहीं:
bash
pnpm add playwright-core@1.56.1
अपने API कुंजी को वातावरण से सेट करें, बजाय कि इसे स्रोत में डालने के:
bash
export SCRAPELESS_API_KEY="paste-your-key-here"
कॉन्फ़िगर करें: Playwright को क्लाउड ब्राउज़र से कनेक्ट करें
Scraping Browser Chrome DevTools प्रोटोकॉल से बात करता है, इसलिए connectOverCDP प्रवेश बिंदु है। नीचे का सार्वजनिक परीक्षण फ़ॉर्म Selenium परियोजना का है और विशेष रूप से स्वचालन अभ्यास के लिए मौजूद है:
js
import { chromium } from 'playwright-core';
const endpoint = 'wss://browser.scrapeless.com/api/v2/browser?' + new URLSearchParams({
token: process.env.SCRAPELESS_API_KEY,
sessionTTL: '300',
});
const browser = await chromium.connectOverCDP(endpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
await page.goto('https://www.selenium.dev/selenium/web/web-form.html', {
waitUntil: 'domcontentloaded',
});
console.log('chromium:', browser.version());
console.log('title:', await page.title());
console.log('form method:', await page.getAttribute('form', 'method'));
await browser.close();
text
chromium: 140.0.7339.35
title: Web form
form method: get
एक नोट जो दूरस्थ सत्रों पर विशेष है: डिफ़ॉल्ट पृष्ठ विश्वासयोग्य प्रकारों को लागू करता है, इसलिए page.setContent() को मार्कअप लिखने से पहले अस्वीकृत कर दिया जाता है। data: URL पर नेविगेट करना काम करने का विकल्प है, और नीचे दिए गए माप में ठीक वही उपयोग किया गया है।
बुनियादी कार्यान्वयन: मापें कि प्रत्येक तकनीक क्या उत्पन्न करती है
एक नियम के बजाए इनपुट को इंस्ट्रूमेंट करें। यह फ़िक्स्चर हर इवेंट को रिकॉर्ड करता है जो क्षेत्र तक पहुँचता है, और एक input श्रवणकर्ता से अपना स्वयं का मान्यता संदेश भी प्रस्तुत करता है — यह पैटर्न मौन विफलताओं को दिखाई देने वाला बनाता है:
js
import { chromium } from 'playwright-core';
const endpoint = 'wss://browser.scrapeless.com/api/v2/browser?' + new URLSearchParams({
token: process.env.SCRAPELESS_API_KEY,
sessionTTL: '300',
});
const browser = await chromium.connectOverCDP(endpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
const fixture = `<!doctype html><meta charset=utf-8><title>fixture</title>
<form id=f>
<input id=t name=t type=text required minlength=4>
<output id=err></output>
</form>
<script>
window.__ev = [];
var el = document.getElementById('t');
['focus','beforeinput','input','change','keydown','keyup'].forEach(function(type){
el.addEventListener(type, function(){ window.__ev.push(type); });
});
el.addEventListener('input', function(){
document.getElementById('err').textContent = el.validity.valid ? 'ok' : 'too short';
});
</script>`;
const fixtureUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(fixture);
async function trial(name, action) {
await page.goto(fixtureUrl, { waitUntil: 'load' });
await action();
await page.waitForTimeout(200);
const state = await page.evaluate(() => ({
events: window.__ev.slice(),
formData: new FormData(document.getElementById('f')).get('t'),
valid: document.getElementById('t').validity.valid,
errorUi: document.getElementById('err').textContent,
}));
console.log(name);
console.log(' events :', JSON.stringify(state.events));
console.log(' formData:', JSON.stringify(state.formData), '| valid:', state.valid);
console.log(' error-UI:', JSON.stringify(state.errorUi));
}
await trial('A: el.value = "hello"', () =>
page.$eval('#t', el => { el.value = 'hello'; }));
await trial('B: el.value + dispatchEvent(input)', () =>
page.$eval('#t', el => {
el.value = 'hello';
el.dispatchEvent(new Event('input', { bubbles: true }));
}));
await trial('C: locator.fill("hello")', () => page.fill('#t', 'hello'));
await trial('D: locator.pressSequentially("hello")', () =>
page.locator('#t').pressSequentially('hello'));
await browser.close();
text
A: el.value = "hello"
events : []
formData: "hello" | valid: true
error-UI: ""
B: el.value + dispatchEvent(input)
events : ["input"]
formData: "hello" | valid: true
error-UI: "ok"
C: locator.fill("hello")
events : ["focus","beforeinput","input"]
formData: "hello" | valid: true
error-UI: "ok"
D: locator.pressSequentially("hello")
events : ["focus","keydown","beforeinput","input","keyup","keydown","beforeinput","input","keyup","keydown","beforeinput","input","keyup","keydown","beforeinput","input","keyup","keydown","beforeinput","input","keyup"]
formData: "hello" | valid: true
error-UI: "ok"
पहले मामले को ध्यान से पढ़ें। सीधे असाइनमेंट ने एक खाली इवेंट सूची उत्पन्न की, और फिर भी FormData ने "hello" ले लिया और क्षेत्र ने खुद को वैध बताया। मूल्य वास्तव में वहाँ है। जो कभी नहीं हुआ वह पृष्ठ की अपनी प्रतिक्रिया है: त्रुटि आउटपुट खाली रहा क्योंकि कुछ भी इसे अपडेट करने के लिए नहीं कहा गया था।
उस परिणाम ने सामान्य सलाह को फिर से संक्षिप्त किया। .value सेट करना स्वाभाविक रूप से टूटना नहीं है — यह अदृश्य है। एक सामान्य HTML फ़ॉर्म जिसमें कोई स्क्रिप्टिंग नहीं होती है, इसे सही तरीके से सबमिट करता है। एक फ़ॉर्म जिसका व्यवहार घटनाओं से वेयर किया गया है, फ़ील्ड को अछूता मानता है, और लक्षण कहीं और पूरी तरह से प्रकट होता है।
fill() कॉम्पैक्ट अनुक्रम उत्पन्न करता है जिसकी अधिकांश पृष्ठों को आवश्यकता होती है: ध्यान, फिर beforeinput, फिर input। pressSequentially() पूर्ण प्रति-पत्र कुंजीपोषण अनुक्रम उत्पन्न करता है, जो तब ही महत्वपूर्ण होता है जब पृष्ठ व्यक्तिगत कुंजी-प्रविष्टियों का निरीक्षण करता है, जैसे कि एक ऑटोकम्पलीट जो हर अक्षर पर प्रश्न पूछता है। W3C UI इवेंट्स विनिर्देश इन तकनीकों के अनुक्रम को परिभाषित करता है, और WHATWG DOM मानक यह परिभाषित करता है कि एक मैन्युअल रूप से प्रेषित इवेंट कैसे फैलता है — जिसमें isTrusted ध्वज शामिल है जो इसे एक वास्तविक उपयोगकर्ता कार्रवाई से अलग करता है।
अपने API कींजी मुफ्त योजना पर प्राप्त करें: app.scrapeless.com
उन्नत पैटर्न: वह विजेट जो सिर्फ एक मूल्य से अधिक की आवश्यकता होती है
चयन जो अन्य क्षेत्रों को अनलॉक करते हैं
यहीं पर प्रत्यक्ष असाइनमेंट केवल अदृश्य होना बंद कर देता है और आपको डेटा की लागत आने लगती है। नीचे का फ़िक्स्चर एक दूसरा क्षेत्र प्रकट करता है और चयन के change हैंडलर से सबमिट बटन को सक्षम करता है:
js
import { chromium } from 'playwright-core';
const endpoint = 'wss://browser.scrapeless.com/api/v2/browser?' + new URLSearchParams({
token: process.env.SCRAPELESS_API_KEY,
sessionTTL: '300',
});
const browser = await chromium.connectOverCDP(endpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
const fixture = `<!doctype html><meta charset=utf-8><title>conditional</title>
<form id=f>
<select id=plan name=plan>
<option value="">choose</option>
<option value="basic">Basic</option>
<option value="team">Team</option>
</select>
<div id=extra hidden><input id=seats name=seats type=number></div>
<button id=go type=submit disabled>Continue</button>
</form>
<script>
var plan = document.getElementById('plan');
plan.addEventListener('change', function(){
document.getElementById('extra').hidden = (plan.value !== 'team');
document.getElementById('go').disabled = !plan.value;
});
</script>`;
const url = 'data:text/html;charset=utf-8,' + encodeURIComponent(fixture);
async function trial(name, action) {
await page.goto(url, { waitUntil: 'load' });
await action();
await page.waitForTimeout(200);
console.log(name, '->', JSON.stringify(await page.evaluate(() => ({
selectValue: document.getElementById('plan').value,
seatsVisible: !document.getElementById('extra').hidden,
submitEnabled: !document.getElementById('go').disabled,
}))));
}
await trial('A: select.value = "team"', () =>
page.$eval('#plan', el => { el.value = 'team'; }));
await trial('B: select.value + dispatchEvent(change)', () =>
page.$eval('#plan', el => {
el.value = 'team';
el.dispatchEvent(new Event('change', { bubbles: true }));
}));
await trial('C: locator.selectOption("team")', async () => {
await page.selectOption('#plan', 'team');
await page.waitForSelector('#seats', { state: 'visible' });
await page.fill('#seats', '25');
});
await browser.close();
text
A: select.value = "team" -> {"selectValue":"team","seatsVisible":false,"submitEnabled":false}
B: select.value + dispatchEvent(change) -> {"selectValue":"team","seatsVisible":true,"submitEnabled":true}
C: locator.selectOption("team") -> {"selectValue":"team","seatsVisible":true,"submitEnabled":true}
केस A वह असफलता है जिसे याद रखना चाहिए। चयन वास्तव में "team" रखता है, इसलिए एक स्क्रिप्ट जो अपने स्वयं के कार्य की पुष्टि करती है कि उसे वापस पढ़ने से सफलता की रिपोर्ट मिलती है — जबकि सीटों का क्षेत्र जिसे भरने के लिए कहा गया था वह अभी भी छिपा हुआ है और बटन जिस पर क्लिक करने के लिए कहा गया था वह अभी भी निष्क्रिय है। selectOption() पूरे समस्या वर्ग से बचता है क्योंकि यह input और change को एक उपयोगकर्ता चयन की तरह प्रेषित करता है।
चेकबॉक्स और रेडियो
check() और uncheck() का उपयोग करें बजाय click() के। वे अंधाधुंध टॉगल करने के बजाय परिणामी अवस्था को निर्धारित करते हैं, इसलिए एक बॉक्स जो पहले से मार्कअप में checked रखता है वह गलत दिशा में नहीं बदलता:
js
await page.check('#my-check-2');
await page.uncheck('#my-check-1');
await page.check('#my-radio-2');
दिनांक चयनकर्ता जो आप जो टाइप करते हैं उसे अस्वीकार करते हैं
एक क्षेत्र जो एक दिनांक इनपुट की तरह दिखता है अक्सर एक पाठ इनपुट होता है जिसमें एक जावास्क्रिप्ट कैलेंडर जुड़ा होता है, और कैलेंडर मूल्य का मालिक होता है। एक ही सार्वजनिक दिनांक क्षेत्र में एक ही दिनांक डालने के छह तरीकों ने चार अलग-अलग संग्रहीत मान उत्पन्न किए:
| तकनीक | बाद में क्षेत्र का मूल्य | ओवरले |
|---|---|---|
fill('2026-08-06') |
"2026-08-06" |
अभी भी खुला |
fill(...) फिर Escape |
"" |
बंद |
fill(...) फिर कहीं और क्लिक करें |
"" |
बंद |
fill(...) फिर Enter |
"08/06/2026" |
अभी भी खुला |
el.value = '2026-08-06' |
"2026-08-06" |
कभी नहीं खुला |
pressSequentially('2026-08-06') फिर Escape |
"10/08/6" |
बंद |
उनमें से तीन जाल हैं। Escape से ओवरले को अस्वीकार करने या कहीं और क्लिक करने से क्षेत्र को एक खाली स्ट्रिंग पर वापस लाया, क्योंकि विजेट अस्वीकार को छोड़ दिया गया संपादन मानता है। अक्षर द्वारा अक्षर टाइप करने से कैलेंडर को मध्य-प्रविष्टि में क्षेत्र को फिर से स्वरूपित करने की अनुमति मिली और एक मूल्य उत्पन्न किया जो कुछ भी मेल नहीं खाता। प्रत्यक्ष असाइनमेंट केवल उस सटीक पाठ को बनाए रखता है क्योंकि विजेट ने कभी भी संलग्न नहीं किया — जिसका मतलब है कि कैलेंडर की आंतरिक स्थिति और क्षेत्र असहमति रखते हैं।
Enter के साथ प्रतिबद्ध करना वह अंत है जो काम करता है, और विजेट मूल्य को अपने स्वयं के प्रदर्शन प्रारूप में फिर से लिखता है। पुष्टि किए गए मूल्य को सत्यापित करें बजाय इसके कि आपका इनपुट बच गया है:
js
await page.fill('input[name="my-date"]', '2026-08-06');
await page.press('input[name="my-date"]', 'Enter');
console.log(await page.inputValue('input[name="my-date"]'));
// 08/06/2026
जहां एक सच्चा <input type="date"> इसके बजाय उपयोग किया जाता है, चित्र सरल है: मूल्य को दिखाए गए प्रारूप के बावजूद एक ISO YYYY-MM-DD स्ट्रिंग होना चाहिए।
फ़ाइल इनपुट एक ब्राउज़र पर जो स्थानीय नहीं है
एक क्लाउड ब्राउज़र के साथ एक यथार्थवादी चिंता यह है कि फ़ाइल अपलोड काम नहीं कर सकते, क्योंकि फ़ाइल आपके मशीन पर होती है और ब्राउज़र में नहीं होती। setInputFiles() प्रोटोकॉल के माध्यम से ट्रांसफर को हैंडल करता है, इसलिए कोई ऑपरेटिंग सिस्टम संवाद कभी भी शामिल नहीं होता:
js
import fs from 'node:fs';
import { chromium } from 'playwright-core';
fs.writeFileSync('upload-sample.txt', 'scrapeless form upload fixture\n');
const endpoint = 'wss://browser.scrapeless.com/api/v2/browser?' + new URLSearchParams({
token: process.env.SCRAPELESS_API_KEY,
sessionTTL: '300',
});
const browser = await chromium.connectOverCDP(endpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
await page.goto('https://www.selenium.dev/selenium/web/web-form.html', {
waitUntil: 'domcontentloaded',
});
await page.setInputFiles('input[name="my-file"]', './upload-sample.txt');
console.log(await page.$eval('input[name="my-file"]', el => ({
files: el.files.length,
name: el.files[0].name,
hasBytes: el.files[0].size > 0,
})));
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button[type="submit"]'),
]);
console.log('submitted my-file:',
JSON.stringify(new URL(page.url()).searchParams.get('my-file')));
await browser.close();
text
{ files: 1, name: 'upload-sample.txt', hasBytes: true }
submitted my-file: "upload-sample.txt"
दूरस्थ सत्र ने फ़ाइल प्राप्त की, FileList भरा गया है, और फ़ाइल नाम सबमिट किए गए फॉर्म डेटा में दिखाई देता है।
बहु-चरण फॉर्म
प्रत्येक चरण को एक पूर्व शर्त के रूप में मानें बजाय देरी के। फॉर्म को आगे बढ़ाने वाले क्षेत्र को प्रतिबद्ध करने के बाद, इसके स्पर्श करने से पहले अगले चरण पर केवल मौजूद नियंत्रण की प्रतीक्षा करें:
js
await page.selectOption('#plan', 'team');
await page.waitForSelector('#seats', { state: 'visible' });
await page.fill('#seats', '25');
स्वयं तत्व पर प्रतीक्षा करने से स्क्रिप्ट को फॉर्म की वास्तविक स्थिति से बांधकर रखता है, जो वही सिद्धांत है जो चयनात्मक चयन केस को काम करता है।
सबमिट की गई स्थिति को वापस पढ़ें
एकमात्र अधिकृत पुष्टि यह है कि सर्वर ने क्या प्राप्त किया। यह फॉर्म GET द्वारा सबमिट होता है, इसलिए स्वीकृत मूल्य अगले पृष्ठ पर प्रश्न स्ट्रिंग में पहुंच जाते हैं:
js
import { chromium } from 'playwright-core';
const endpoint = 'wss://browser.scrapeless.com/api/v2/browser?' + new URLSearchParams({
token: process.env.SCRAPELESS_API_KEY,
sessionTTL: '300',
});
const browser = await chromium.connectOverCDP(endpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
await page.goto('https://www.selenium.dev/selenium/web/web-form.html', {
waitUntil: 'domcontentloaded',
});
await page.fill('#my-text-id', 'Ada Lovelace');
await page.selectOption('select[name="my-select"]', '2');
await page.check('#my-check-2');
await page.uncheck('#my-check-1');
await page.check('#my-radio-2');
await page.fill('input[name="my-date"]', '2026-08-06');
await page.press('input[name="my-date"]', 'Enter');
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button[type="submit"]'),
]);
const params = Object.fromEntries(new URL(page.url()).searchParams.entries());
for (const key of ['my-text', 'my-select', 'my-check', 'my-date']) {
console.log(key.padEnd(10), JSON.stringify(params[key]));
}
await browser.close();
text
my-text "Ada Lovelace"
my-select "2"
my-check "on"
my-date "08/06/2026"
सर्वर के दृश्य की जांच से पता चलता है कि फॉर्म को स्वीकार किया गया, केवल इतना नहीं कि क्षेत्रों को भरा गया था। ध्यान दें कि my-date विजेट के प्रतिबद्ध प्रारूप को ले जाता है, जो स्ट्रिंग नहीं है जो टाइप की गई थी।
DOM से मान्यता त्रुटियों को पढ़ना
जब एक सबमिशन अस्वीकृत होता है, तो ब्राउज़र पहले से ही एक संरचित व्याख्या रखता है। HTML मानक में प्रतिबंध सत्यापन API यह दर्शाता है कि कौन सा नियम विफल हुआ और वह संदेश जो ब्राउज़र प्रदर्शित करेगा, इसलिए पृष्ठ का स्क्रीनशॉट लेने और पिक्सल पढ़ने की कोई आवश्यकता नहीं है:
js
import { chromium } from 'playwright-core';
const endpoint = 'wss://browser.scrapeless.com/api/v2/browser?' + new URLSearchParams({
token: process.env.SCRAPELESS_API_KEY,
sessionTTL: '300',
});
const browser = await chromium.connectOverCDP(endpoint);
const context = browser.contexts()[0];
const page = context.pages()[0] || await context.newPage();
const fixture = `<!doctype html><meta charset=utf-8><title>validation</title>
<form id=f>
<input id=email name=email type=email required>
<input id=code name=code type=text required minlength=4>
<button type=submit>Send</button>
</form>
<script>
window.__submitted = false;
document.getElementById('f').addEventListener('submit', function(e){
e.preventDefault(); window.__submitted = true;
});
</script>`;
await page.goto('data:text/html;charset=utf-8,' + encodeURIComponent(fixture),
{ waitUntil: 'load' });
await page.fill('#email', 'not-an-address');
await page.fill('#code', 'ab');
const report = await page.evaluate(() => {
const form = document.getElementById('f');
form.requestSubmit();
return {
submitted: window.__submitted,
fields: [...form.elements]
.filter(el => el.willValidate && !el.checkValidity())
.map(el => ({
name: el.name,
message: el.validationMessage,
failed: Object.keys(ValidityState.prototype)
.filter(k => k !== 'valid' && el.validity[k]),
})),
};
});
console.log(JSON.stringify(report, null, 1));
await browser.close();
text
{
"submitted": false,
"fields": [
{
"name": "email",
"message": "Please include an '@' in the email address. 'not-an-address' is missing an '@'.",
"failed": [
"typeMismatch"
]
},
{
"name": "code",
"message": "Please lengthen this text to 4 characters or more (you are currently using 2 characters).",
"failed": [
"tooShort"
]
}
]
}
submitted false है क्योंकि ब्राउज़र ने हैंडलर के चलने से पहले सबमिशन को अवरोधित कर दिया, और प्रत्येक विफल फ़ील्ड अपने टूटे नियम का नाम देती है। यह आपको लॉग करने के लिए एक मशीन-पठनीय कारण देता है न कि परिणामों की अस्पष्ट अनुपस्थिति। क्लाइंट-साइड फ़ॉर्म सत्यापन पर MDN संदर्भ इन झंडों द्वारा मैप की गई बाधाओं के व्यापक सेट को कवर करता है।
पृष्ठ जो अपने स्वयं के त्रुटि पाठ को दर्शाते हैं, न कि ब्राउज़र पर निर्भर करते हैं, पहले मापदंड में पहले ही समझाया गया मामला है: उन संदेशों का प्रकट होना तब ही संभव है जब वे सुनने के लिए ईवेंट प्रेषित किए गए थे।
जहां एक स्थानीय ब्राउज़र समाप्त होता है
ऊपर दिए गए प्रत्येक तकनीक सामान्य प्ले राइट हैं और स्थानीय क्रोमियम के खिलाफ भी चलते हैं। प्ले राइट इनपुट दस्तावेज़ समान विधियों का विवरण देता है। एक स्थानीय ब्राउज़र आपको जिस चीज़ की सहायता नहीं करता है, वह फॉर्म का मूल्यांकन करने के लिए एक स्थिर वातावरण है।
फॉर्म किसी साइट का वह हिस्सा है जो धोखाधड़ी और दुर्व्यवहार नियंत्रणों से सबसे निकटता से जुड़ा हुआ है, और ये नियंत्रण मार्कअप के बजाय सत्र पर ध्यान देते हैं: निकासी पता, फिंगरप्रिंट, और क्या ब्राउज़र एक वास्तविक स्थापना के रूप में प्रस्तुत करता है। यही वह हिस्सा है जो स्क्रेपलेस स्क्रेपिंग ब्राउज़र प्रदान करता है: एक अनुकूलनीय, एंटी-डिटेक्शन क्लाउड ब्राउज़र जो आत्म-विकसित क्रोमियम द्वारा संचालित है, जो कनेक्ट समय पर sessionTTL जैसी पैरामीटर के माध्यम से प्रति सत्र कॉन्फ़िगर किया गया है, सभी उसी connectOverCDP कॉल के पीछे जो आपका कोड पहले से ही उपयोग करता है। विजेट हैंडलिंग में कुछ भी नहीं बदलता है; केवल वातावरण बदलता है। स्क्रेपिंग ब्राउज़र उत्पाद पृष्ठ और दस्तावेज़ीकरण पूर्ण सत्र सतह को कवर करते हैं।
समस्या निवारण
| लक्षण | कारण | समाधान |
|---|---|---|
| फ़ील्ड मूल्य रखता है लेकिन पृष्ठ पर कुछ और प्रतिक्रिया नहीं करता | सीधे .value असाइनमेंट ने कोई ईवेंट प्रेषित नहीं किए |
fill() का उपयोग करें, या input और change को स्पष्ट रूप से प्रेषित करें |
| निर्भर फ़ील्ड कभी प्रकट नहीं होता | change हैंडलर जो इसे प्रकट करता है, कभी नहीं चला |
selectOption() का उपयोग करें, फिर निर्भर चयनकर्ता के लिए प्रतीक्षा करें |
| सबमिट बटन अक्षम रहता है | पृष्ठ इसे एक ईवेंट से सक्षम करता है जिसे आपने उत्पन्न नहीं किया | नियंत्रित फ़ील्ड को एक लोकेटर विधि से संचालित करें |
| दिनांक फ़ील्ड भरने के बाद खाली है | पिकर ने अस्वीकरण को एक छोड़ दिया गया संपादन माना | Enter के साथ कमिट करें और मूल्य पढ़ें |
| दिनांक मूल्य पहेली जैसी दिखती है | कैलेंडर ने कीस्ट्रोक के बीच फ़ील्ड को पुनः स्वरूपित किया | प्रति-चरacter टाइपिंग के बजाय fill() और Enter का उपयोग करें |
page.setContent() अस्वीकृत है |
डिफ़ॉल्ट पृष्ठ विश्वसनीय प्रकारों को लागू करता है | इसके बजाय data: URL पर नेविगेट करें |
| सबमिशन चुपचाप कुछ भी नहीं करता | प्रतिबंध सत्यापन ने इसे अवरोधित किया | प्रत्येक फ़ील्ड के लिए validationMessage और validity पढ़ें |
निष्कर्ष
फॉर्म ऑटोमेशन समस्याएँ जो रहस्यमय लगती हैं, आमतौर पर एक मापने योग्य चीज़ होती हैं: एक मूल्य जो DOM में है बिना ऐसे ईवेंट के जो पृष्ठ को इसे नोटिस कराते हैं। सीधे असाइनमेंट मूल्य सेट करता है, प्रतिबंध सत्यापन को संतुष्ट करता है, और FormData को भरता है — और किसी को भी नहीं बताता। लोकेटर विधियाँ जैसे कि fill, check, और selectOption उस पर मानसिकता उत्पन्न करती हैं जिस पर पृष्ठ सुन रहा है, यही कारण है कि वे तब भी काम करना जारी रखते हैं जब एक फॉर्म एक निर्भर फ़ील्ड, एक पिकर विजेट, या एक सत्यापन परत जोड़ता है।
परिणाम की पुष्टि करने की आदत बनाएं न कि इनपुट की: एक विजेट से कमिट किया गया मूल्य पढ़ें, उस तत्व के लिए प्रतीक्षा करें जिसे एक परिवर्तन प्रकट करना था, और validity का निरीक्षण करें जब एक सबमिशन कहीं नहीं जाता। स्क्रेपलेस स्क्रेपिंग ब्राउज़र पर चलने से उसके नीचे सभी चीजें सुसंगत बनी रहती हैं, इसलिए एकमात्र चर आपके चयनकर्ता तर्क है।
क्या आप अपने AI-पावर्ड डेटा पाइपलाइन बनाने के लिए तैयार हैं?
समुदाय में शामिल हों और एक मुफ्त योजना का दावा करें और फ़ॉर्म-चालित वर्कफ़्लोज़ को स्वचालित करने वाले डेवलपर्स के साथ नोट्स साझा करें: Discord · Telegram।
app.scrapeless.com पर मुफ्त स्क्रैपिंग ब्राउज़र रUNTIME के लिए साइन अप करें, और जब आप स्केल अप करें तो मूल्य निर्धारण देखें।
FAQ
Q: क्या element.value को सीधे सेट करना कभी काम करता है?
हाँ, उन फ़ॉर्म के लिए जो सबमिट समय पर DOM को पढ़ते हैं। मापी गई रन में, डायरेक्ट असाइनमेंट FormData को भरता है और बाधा मान्यता पास करता है। यह तब विफल होता है जब पृष्ठ अपनी ही स्थिति की प्रति बनाए रखता है या input या change श्रोता से कुछ रेंडर करता है, क्योंकि असाइनमेंट कोई इवेंट नहीं भेजता है।
Q: यदि मुझे मैन्युअली मान सेट करना है तो मुझे कौन से इवेंट भेजने की आवश्यकता है?
पाठ फ़ील्ड के लिए एक उभड़ता हुआ input इवेंट और चयन, चेकबॉक्स, और रेडियो के लिए एक उभड़ता हुआ change इवेंट भेजें। कुछ फ्रेमवर्क तत्व पर पिछले मान को ट्रैक करते हैं और उस इवेंट को अनदेखा करते हैं जिसका मान उन्हें लगता है कि उन्होंने पहले ही रिकॉर्ड किया है; डिस्पैच करने से पहले प्राकृतिक प्रोटोटाइप सेटर को कॉल करना इसे बचाता है। fill(), check(), या selectOption() का उपयोग करना पूरे मुद्दे से बचता है।
Q: मेरा दिनांक फ़ील्ड खाली क्यों है जब मैंने इसे भरा था?
एक जावास्क्रिप्ट कैलेंडर विजेट शायद इसे वापस करता है। फ़ील्ड को भरने के बाद और फिर Escape दबाने या कहीं और क्लिक करने से परीक्षण में एक खाली स्ट्रिंग वापस आई, क्योंकि विजेट एक हटाए गए ओवरले को एक छोड़ दिए गए संपादन के रूप में मानता है। मान को एंटर के साथ कमिट करें और सबमिट करने से पहले इसे वापस पढ़ें।
Q: क्या मैं क्लाउड में ब्राउज़र चलने पर एक फ़ाइल अपलोड कर सकता हूँ?
हाँ। setInputFiles() स्थानीय फ़ाइल को प्रोटोकॉल के माध्यम से दूरस्थ सत्र में स्थानांतरित करता है, इसलिए कोई ऑपरेटिंग-सिस्टम फ़ाइल डायलॉग शामिल नहीं है। भरा हुआ FileList और जमा किया गया फ़ॉर्म डेटा दोनों अपलोड की पुष्टि करते हैं।
Q: मैं कैसे जानूं कि फ़ॉर्म ने सबमिट करने से क्यों मना किया?
फ़ॉर्म के तत्वों को इटरेट करें, उन तत्वों के लिए फ़िल्टर करें जहाँ checkValidity() गलत लौटाता है, और प्रत्येक के validationMessage और validity झंडों को पढ़ें। यह आपको विशिष्ट विफल बाधा देता है, जैसे typeMismatch या tooShort, बिना रेंडर किए गए पिक्सेल का निरीक्षण किए।
Q: क्या मुझे fill() का उपयोग करना चाहिए या वर्ण द्वारा वर्ण टाइप करना चाहिए?
fill() को प्राथमिकता दें। यह फोकस, beforeinput, और input को उत्सर्जित करता है, जो लगभग हर फ़ॉर्म सुनता है। केवल तब वर्ण-प्रति-वर्ण प्रविष्टि के लिए पहुँचें जब पृष्ठ व्यक्तिगत कुंजी स्ट्रोक पर प्रतिक्रिया देता है, जैसे कि प्रत्येक अक्षर पर क्वेरी करने वाली ऑटोकम्प्लीट — और परिणाम की जाँच करें, क्योंकि कुछ विजेट कुंजी स्ट्रोक के बीच फ़ील्ड को फिर से स्वरूपित करते हैं।
स्क्रैपलेस में, हम केवल सार्वजनिक रूप से उपलब्ध डेटा का उपयोग करते हैं, जबकि लागू कानूनों, विनियमों और वेबसाइट गोपनीयता नीतियों का सख्ती से अनुपालन करते हैं। इस ब्लॉग में सामग्री केवल प्रदर्शन उद्देश्यों के लिए है और इसमें कोई अवैध या उल्लंघन करने वाली गतिविधियों को शामिल नहीं किया गया है। हम इस ब्लॉग या तृतीय-पक्ष लिंक से जानकारी के उपयोग के लिए सभी देयता को कोई गारंटी नहीं देते हैं और सभी देयता का खुलासा करते हैं। किसी भी स्क्रैपिंग गतिविधियों में संलग्न होने से पहले, अपने कानूनी सलाहकार से परामर्श करें और लक्ष्य वेबसाइट की सेवा की शर्तों की समीक्षा करें या आवश्यक अनुमतियाँ प्राप्त करें।



