Puppeteer仅在headless模式下报错:Cannot read properties of undefined (reading 'getProperty')
Puppeteer无头模式(headless: true)抓取失败的解决办法
问题场景
调试Puppeteer配置时,设置puppeteer.launch({ headless: false });无报错,但切换到理想的headless: true模式时,数据抓取失败,报错信息如下:
Logging into user... Logged in! Fetching username... TypeError: Cannot read properties of undefined (reading 'getProperty') at D:\boody\Programming\blxscrape\src\index.ts:40:27 at Generator.next (<anonymous>) at fulfilled (D:\boody\Programming\blxscrape\src\index.ts:5:58) at processTicksAndRejections (node:internal/process/task_queues:95:5)
涉及的核心代码片段:
// username await console.log('Fetching username...'); const [el]: any = await page.$x('/html/body/div[3]/main/div[2]/div[2]/div/div[1]/div/div[2]/div[2]/div[1]/div[2]'); let txt: any = await el.getProperty('textContent'); const usernameTxt: string = await txt.jsonValue(); // desc await console.log('Fetching description...'); const [el2]: any = await page.$x('/html/body/div[3]/main/div[2]/div[2]/div/div[3]/div/div[1]/div[1]/div[2]/div/pre/span'); const descTxt: string = await page.evaluate((el2: any) => el2.textContent, el2); // profile picture await console.log('Fetching profile picture...'); const [el3]: any = await page.$x('/html/body/div[3]/main/div[2]/div[2]/div/div[1]/div/div[2]/div[1]/span/thumbnail-2d/span/img'); const src: any = await el3.getProperty('src'); const pfpUrl: string = await src.jsonValue(); const data: object = {usernameTxt, descTxt, pfpUrl}; console.log(data); browser.close(); } scrape('https://www.roblox.com/users/64004875/profile', process.env.USER, process.env.PASS);
解决办法
1. 增加元素加载等待逻辑
无头模式下页面渲染、资源加载速度和有头模式存在差异,直接获取元素可能遇到元素未加载完成的情况。在每个元素获取前,添加waitForXPath等待元素出现:
// 等待用户名元素加载 await page.waitForXPath('/html/body/div[3]/main/div[2]/div[2]/div/div[1]/div/div[2]/div[2]/div[1]/div[2]'); const [el]: any = await page.$x('/html/body/div[3]/main/div[2]/div[2]/div/div[1]/div/div[2]/div[2]/div[1]/div[2]'); // 等待描述元素加载 await page.waitForXPath('/html/body/div[3]/main/div[2]/div[2]/div/div[3]/div/div[1]/div[1]/div[2]/div/pre/span'); const [el2]: any = await page.$x('/html/body/div[3]/main/div[2]/div[2]/div/div[3]/div/div[1]/div[1]/div[2]/div/pre/span'); // 等待头像元素加载 await page.waitForXPath('/html/body/div[3]/main/div[2]/div[2]/div/div[1]/div/div[2]/div[1]/span/thumbnail-2d/span/img'); const [el3]: any = await page.$x('/html/body/div[3]/main/div[2]/div[2]/div/div[1]/div/div[2]/div[1]/span/thumbnail-2d/span/img');
2. 配置无头浏览器模拟正常环境
部分网站会检测无头浏览器特征,导致页面渲染异常或拦截请求。调整launch配置,让无头浏览器更接近正常浏览器:
puppeteer.launch({ headless: true, args: [ '--window-size=1920,1080', '--disable-blink-features=AutomationControlled', '--no-sandbox', '--disable-setuid-sandbox' ], defaultViewport: { width: 1920, height: 1080 }, userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' });
3. 增加元素存在性判断
在调用getProperty或evaluate前,先判断元素是否存在,避免因元素未找到导致的报错:
// 用户名处理 if (el) { let txt: any = await el.getProperty('textContent'); const usernameTxt: string = await txt.jsonValue(); } else { console.error('未找到用户名元素'); } // 描述处理 if (el2) { const descTxt: string = await page.evaluate((el2: any) => el2.textContent, el2); } else { console.error('未找到描述元素'); } // 头像处理 if (el3) { const src: any = await el3.getProperty('src'); const pfpUrl: string = await src.jsonValue(); } else { console.error('未找到头像元素'); }
4. 登录后增加等待逻辑
登录完成后,页面可能仍在跳转或加载状态,不要立刻执行抓取操作。可以等待页面导航完成,或等待某个登录后才会出现的元素:
// 登录操作完成后,等待页面导航 await page.waitForNavigation({ waitUntil: 'networkidle2' }); // 或者等待某个标志性元素 await page.waitForSelector('某个登录后显示的选择器');
内容的提问来源于stack exchange,提问作者Boody
相关产品推荐
相关产品推荐

