Puppeteer无法访问Canvas函数,Chrome DevTools却可行,求排查
Fixing Puppeteer's Inability to Access React Internal Instance on Canvas
Key Issues in Your Original Code
- Context Mismatch: Puppeteer runs in Node.js, while the DOM and React's internal properties live in the browser's JavaScript context.
page.$returns anElementHandle(a reference to the DOM element), not the actual element—you can't iterate over its properties directly in Node.js. - Invalid Callback Usage:
page.$does not accept a callback function as its second argument. This is why your "Found the canvas" log never appears—this code never executes.
Corrected Approach
To access the canvas's properties (including React's internal instance), you need to run your inspection code inside the browser's context using page.evaluate(). Here's the fixed code:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ executablePath: "/usr/bin/google-chrome", headless: true, userDataDir: '/tmp' }); const page = await browser.newPage(); // Capture browser console logs in Node.js terminal page.on('console', msg => console.log('Browser Log:', msg.text())); // Set user agent and viewport await page.setUserAgent("Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36"); await page.setViewport({ width: 412, height: 915 }); await page.goto('https://www.nytimes.com/puzzles/letter-boxed'); try { // Click start button await page.waitForSelector("button.pz-moment__button.primary"); const startButton = await page.$("button.pz-moment__button.primary"); await startButton.click(); await delay(3000); // Wait for canvas to load await page.waitForSelector("#pz-game-root > div > div > div.lb-square-container > canvas"); // Run inspection code in browser context const reactInstanceData = await page.evaluate(() => { const canvas = document.querySelector("#pz-game-root > div > div > div.lb-square-container > canvas"); let reactPropName = ''; let reactInstance = null; for (const prop in canvas) { if (prop.includes("__reactInternalInstance")) { console.log(`React Internal Prop Name: ${prop}`); reactPropName = prop; reactInstance = canvas[prop]; break; } } // Return serializable data (full React instance can't be sent due to circular references) return { reactPropName: reactPropName, instanceKeys: reactInstance ? Object.keys(reactInstance) : [] }; }); console.log("React Instance Details:", reactInstanceData); } catch (error) { console.log("Failure occurred"); console.log(error); } await browser.close(); })(); function delay(time) { return new Promise(resolve => setTimeout(resolve, time)); }
Important Notes
page.evaluate()executes code directly in the browser, allowing you to interact with the DOM element just like in DevTools.- React's internal instance objects often have circular references, so we can't return the entire object to Node.js. Extract specific data you need inside
page.evaluate()if necessary. - The
page.on('console')listener lets you see logs from the browser's console in your Node.js terminal.
Additional Troubleshooting Tip
If the React instance still isn't found, use page.waitForFunction() to wait until the property exists:
await page.waitForFunction(() => { const canvas = document.querySelector("#pz-game-root > div > div > div.lb-square-container > canvas"); if (!canvas) return false; for (const prop in canvas) { if (prop.includes("__reactInternalInstance")) return true; } return false; });
内容的提问来源于stack exchange,提问作者Marc
相关产品推荐
相关产品推荐

