我正在使用’puppeteer’为NodeJS测试一个特定的网站.它似乎在大多数情况下工作正常,但有些地方报道:
Error: Node is either not visible or not an HTMLElement
有什么不同?
两个链接都在屏幕外.
任何帮助,赞赏,
干杯,:)
示例代码
const puppeteer = require('puppeteer'); const initialPage = 'https://statsregnskapet.dfo.no/departementer'; const selectors = [ 'div[id$="-bVMpYP"] article a','div[id$="-KcazEUq"] article a' ]; (async () => { let selector,handles,handle; const width=1024,height=1600; const browser = await puppeteer.launch({ headless: false,defaultViewport: { width,height } }); const page = await browser.newPage(); await page.setViewport({ width,height}); page.setUserAgent('UA-TEST'); // Load first page let stat = await page.goto(initialPage,{ waitUntil: 'domcontentloaded'}); // Click on selector 1 - works ok selector = selectors[0]; await page.waitForSelector(selector); handles = await page.$$(selector); handle = handles[12] console.log('Clicking on: ',await page.evaluate(el => el.href,handle)); await handle.click(); // OK // Click that selector 2 - fails selector = selectors[1]; await page.waitForSelector(selector); handles = await page.$$(selector); handle = handles[12] console.log('Clicking on: ',handle)); await handle.click(); // Error: Node is either not visible or not an HTMLElement })();
我试图模仿真实用户点击网站的行为,这就是我使用.click()而不是.goto()的原因,因为a标签有onclick事件.
解决方法
首先,传递给
puppeteer.launch()
的defaultViewport对象没有键,只有值.
您需要将其更改为:
'defaultViewport' : { 'width' : width,'height' : height }
对于传递给page.setViewport()
的对象也是如此.
您需要将此行代码更改为:
await page.setViewport( { 'width' : width,'height' : height } );
三,函数page.setUserAgent()
返回promise
,所以你需要await
这个函数:
await page.setUserAgent( 'UA-TEST' );
此外,你忘了在handle = handles [12]之后添加一个分号.
你应该改为:
handle = handles[12];
此外,您不是在点击第一个链接后等待导航完成(page.waitForNavigation()
).
await page.waitForNavigation();
我注意到第二页有时会挂起导航,因此您可能会发现增加默认导航超时(page.setDefaultNavigationTimeout()
)很有用:
page.setDefaultNavigationTimeout( 90000 );
再一次,你忘了在handle = handles [12]之后添加一个分号,所以这需要改为:
handle = handles[12];
请务必注意,您正在使用错误的选择器来处理您单击的第二个链接.
您的原始选择器试图选择仅对xs超小屏幕(手机)可见的元素.
您需要收集一组对您指定的视口可见的链接.
因此,您需要将第二个选择器更改为:
div[id$="-KcazEUq"] article .dfo-widget-sm a
您还应该在点击第二个链接后等待导航完成:
await page.waitForNavigation();
最后,您可能还想在完成程序后关闭浏览器(browser.close()
):
await browser.close();
Note: You might also want to look into 07008.
这是最终的解决方案:
'use strict'; const puppeteer = require( 'puppeteer' ); const initialPage = 'https://statsregnskapet.dfo.no/departementer'; const selectors = [ 'div[id$="-bVMpYP"] article a','div[id$="-KcazEUq"] article .dfo-widget-sm a' ]; ( async () => { let selector; let handles; let handle; const width = 1024; const height = 1600; const browser = await puppeteer.launch( { 'defaultViewport' : { 'width' : width,'height' : height } }); const page = await browser.newPage(); page.setDefaultNavigationTimeout( 90000 ); await page.setViewport( { 'width' : width,'height' : height } ); await page.setUserAgent( 'UA-TEST' ); // Load first page let stat = await page.goto( initialPage,{ 'waitUntil' : 'domcontentloaded' } ); // Click on selector 1 - works ok selector = selectors[0]; await page.waitForSelector( selector ); handles = await page.$$( selector ); handle = handles[12]; console.log( 'Clicking on: ',await page.evaluate( el => el.href,handle ) ); await handle.click(); // OK await page.waitForNavigation(); // Click that selector 2 - fails selector = selectors[1]; await page.waitForSelector( selector ); handles = await page.$$( selector ); handle = handles[12]; console.log( 'Clicking on: ',handle ) ); await handle.click(); await page.waitForNavigation(); await browser.close(); })();