多个选择器上的操纵符waitForSelector

Jon*_*son 2 screen-scraping puppeteer

我让Puppeteer使用查找表单控制网站,该表单可以返回结果或“未找到记录”消息。我如何知道退货了?waitForSelector似乎一次只等待一个,而waitForNavigation似乎不起作用,因为它是使用Ajax返回的。我正在使用try catch,但是正确正确并降低所有速度都很困难。

try {
    await page.waitForSelector(SELECTOR1,{timeout:1000}); 
}
catch(err) { 
    await page.waitForSelector(SELECTOR2);
}
Run Code Online (Sandbox Code Playgroud)

Alf*_*bel 9

Promise.race()像我在下面的代码片段中所做的那样使用怎么样,不要忘记方法中的{ visible: true }选项page.waitForSelector()

public async enterUsername(username:string) : Promise<void> {
    const un = await Promise.race([
        this.page.waitForSelector(selector_1, { timeout: 4000, visible: true })
        .catch(),
        this.page.waitForSelector(selector_2, { timeout: 4000, visible: true })
        .catch(),
    ]);

    await un.focus();
    await un.type(username);
}
Run Code Online (Sandbox Code Playgroud)

  • 进一步扩展为: let res = wait Promise.race ( [ frame.waitForSelector( ".selector1 ).then( ()=&gt; { return 1 } ).catch(), frame.waitForSelector( ".selector0" ).then ( ()=&gt; { return 0 } ).catch() ]); 您还可以知道触发了哪个选择器。 (4认同)
  • 这是一个绝妙的解决方案。事实上,如果promise.all(或allSettled)是“AND”逻辑的自然解决方案,那么promise.race应该被视为“OR”逻辑的自然解决方案。 (3认同)

And*_*yba 8

在 puppeteer 中,您可以简单地使用用逗号分隔的多个选择器,如下所示:

const foundElement = await page.waitForSelector('.class_1, .class_2');
Run Code Online (Sandbox Code Playgroud)

返回的元素将是页面中找到的第一个元素的 elementHandle。

接下来,如果您想知道找到了哪个元素,您可以获取类名称,如下所示:

const className = await page.evaluate(el => el.className, foundElement);
Run Code Online (Sandbox Code Playgroud)

在您的情况下,类似于此的代码应该可以工作:

const foundElement = await page.waitForSelector([SELECTOR1,SELECTOR2].join(','));
const responseMsg = await page.evaluate(el => el.innerText, foundElement);
if (responseMsg == "No records found"){ // Your code here }
Run Code Online (Sandbox Code Playgroud)


Md.*_*her 7

使任何元素存在

您可以一起使用querySelectorAllwaitFor解决此问题。将所有选择器都使用逗号将返回与任何选择器匹配的所有节点。

await page.waitFor(() => 
  document.querySelectorAll('Selector1, Selector2, Selector3').length
);
Run Code Online (Sandbox Code Playgroud)

现在,仅true当存在某些元素时才返回,而不会返回哪个选择器与哪些元素匹配。


Jon*_*son 7

使用 Md. Abu Taher 的建议,我最终得到了这个:

// One of these SELECTORs should appear, we don't know which
await page.waitForFunction((sel) => { 
    return document.querySelectorAll(sel).length;
},{timeout:10000},SELECTOR1 + ", " + SELECTOR2); 

// Now see which one appeared:
try {
    await page.waitForSelector(SELECTOR1,{timeout:10});
}
catch(err) {
    //check for "not found" 
    let ErrMsg = await page.evaluate((sel) => {
        let element = document.querySelector(sel);
        return element? element.innerHTML: null;
    },SELECTOR2);
    if(ErrMsg){
        //SELECTOR2 found
    }else{
        //Neither found, try adjusting timeouts until you never get this...
    }
};
//SELECTOR1 found
Run Code Online (Sandbox Code Playgroud)


Gab*_*rin 5

我有一个类似的问题,并选择了这个简单的解决方案:

helpers.waitForAnySelector = (page, selectors) => new Promise((resolve, reject) => {
  let hasFound = false
  selectors.forEach(selector => {
    page.waitFor(selector)
      .then(() => {
        if (!hasFound) {
          hasFound = true
          resolve(selector)
        }
      })
      .catch((error) => {
        // console.log('Error while looking up selector ' + selector, error.message)
      })
  })
})
Run Code Online (Sandbox Code Playgroud)

然后使用它:

const selector = await helpers.waitForAnySelector(page, [
  '#inputSmsCode', 
  '#buttonLogOut'
])

if (selector === '#inputSmsCode') {
  // We need to enter the 2FA sms code. 
} else if (selector === '#buttonLogOut') {
  // We successfully logged in
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*ack 5

另一种简单的解决方案是从更 CSS 的角度来解决这个问题。 waitForSelector似乎遵循CSS 选择器列表规则。所以基本上你可以通过使用逗号来选择多个 CSS 元素。

try {    
    await page.waitForSelector('.selector1, .selector2',{timeout:1000})
} catch (error) {
    // handle error
}
Run Code Online (Sandbox Code Playgroud)