使用Puppeteer+ghost-cursor开发Roblox注册机器人遇下拉框点击错误求助
Roblox注册机器人下拉框点击错误问题求助
我正在开发一款基于Puppeteer和ghost-cursor的Roblox账号注册机器人,目前已实现自动生成并填写用户名的功能,但在点击生日月份下拉框选择具体月份时触发了错误。以下是我的代码及报错信息,恳请帮助解决:
代码
const puppeteer = require("puppeteer"); const { createCursor } = require("ghost-cursor"); genalt(); async function genalt() { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); const cursor = createCursor(page); await page.goto("https://www.roblox.com"); setTimeout(async() => { await page.evaluate(() => { function altName() { let oh = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let ohString = ""; for (var i = 0; i < 6; i++) { ohString += oh.charAt(Math.floor(Math.random() * oh.length)); } return `MysticGen_${ohString}`; } document.querySelector('input[name="signupUsername"]').value = `${altName()}`; }); setTimeout(() => { cursor.click('select[name="birthdayMonth"]'); setTimeout(() => { cursor.click('option[value="Jan"]'); }, 1000) }, 1000) }, 1000) }
报错信息
Falling back to JS scroll method ProtocolError: Protocol error (DOM.scrollIntoViewIfNeeded): Node does not have a layout object at D:\Downloads\Stuff\Code\Roblox Alt Gen\node_modules\puppeteer\lib\cjs\puppeteer\common\Connection.js:329:24 at new Promise (<anonymous>) at CDPSessionImpl.send (D:\Downloads\Stuff\Code\Roblox Alt Gen\node_modules\puppeteer\lib\cjs\puppeteer\common\Connection.js:325:16) at Object.<anonymous> (D:\Downloads\Stuff\Code\Roblox Alt Gen\node_modules\ghost-cursor\lib\spoof.js:463:75) at step (D:\Downloads\Stuff\Code\Roblox Alt Gen\node_modules\ghost-cursor\lib\spoof.js:44:23) at Object.next (D:\Downloads\Stuff\Code\Roblox Alt Gen\node_modules\ghost-cursor\lib\spoof.js:25:53) at fulfilled (D:\Downloads\Stuff\Code\Roblox Alt Gen\node_modules\ghost-cursor\lib\spoof.js:16:58) at processTicksAndRejections (node:internal/process/task_queues:96:5) { originalMessage: 'Node does not have a layout object' }
问题分析与解决方案
错误原因
- 嵌套setTimeout时序不可靠:多层setTimeout无法确保元素在操作时已完全渲染可见,属于不可控的异步流程。
- ghost-cursor操作不可见元素:下拉框未展开时,内部的
option元素处于不可见状态,没有布局对象,ghost-cursor尝试点击会触发报错。 - 未等待元素加载完成:没有明确等待目标元素出现就执行操作,可能元素还未完成渲染。
修改后的代码
const puppeteer = require("puppeteer"); const { createCursor } = require("ghost-cursor"); genalt(); async function genalt() { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); const cursor = createCursor(page); // 等待页面加载完成,确保所有资源都已加载 await page.goto("https://www.roblox.com", { waitUntil: "networkidle2" }); // 等待用户名输入框可见,模拟真实点击+输入流程 const usernameInput = await page.waitForSelector('input[name="signupUsername"]', { visible: true }); const altName = await page.evaluate(() => { let oh = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let ohString = ""; for (let i = 0; i < 6; i++) { ohString += oh.charAt(Math.floor(Math.random() * oh.length)); } return `MysticGen_${ohString}`; }); await cursor.click(usernameInput); await page.keyboard.type(altName); // 处理生日月份下拉框:用page.select直接选择,避免操作不可见的option const monthSelect = await page.waitForSelector('select[name="birthdayMonth"]', { visible: true }); await cursor.click(monthSelect); // 可选:模拟点击下拉框,贴近真人交互 await page.select('select[name="birthdayMonth"]', "Jan"); }
关键改进点
- 用
page.goto的waitUntil: "networkidle2"确保页面完全加载完成。 - 用
page.waitForSelector等待元素可见,避免操作未渲染的元素。 - 替换嵌套
setTimeout为async/await,让流程顺序可控。 - 用
page.select直接选择下拉框选项,绕过操作不可见option的问题,彻底解决报错。 - 模拟真实输入流程:点击输入框→输入用户名,比直接赋值
value更贴近真人操作,降低被反爬检测的风险。
内容的提问来源于stack exchange,提问作者mystic
相关产品推荐
相关产品推荐

