javascript 传递Cheerio元素给傀儡使其被点击

lokaqttq  于 2022-12-21  发布在  Java
关注(0)|答案(2)|浏览(158)

我正在抓取一个网站,我正在使用Cheerio和Puppeteer。我需要用给定的文本点击某个按钮。下面是我的代码:

const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.website.com', {waitUntil: 'networkidle0'});
    const html = await page.content();

    const $ = cheerio.load(html);
    
    const items = [];
    $('.grid-table-container').each((index, element) => {
        items.push({
            element: $($('.grid-option-name', element)[0]).contents().not($('.grid-option-name', element).children()).text() },
            button: $('.grid-option-selectable>div', element)
        });
    });

    items.forEach(item => {
        if (item.element === 'Foo Bar') {
            await page.click(item.button);
        }
    });

下面是我试图刮的标记:

<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table">
    <div class="grid-item">
        <div class="grid-item-container">
            <div class="grid-table-container>
                <div class="grid-option-header">
                    <div class="grid-option-caption">
                        <div class="grid-option-name">
                            Foo Bar
                            <span>some other text</span>
                        </div>
                    </div>
                </div>
                <div class="grid-option-table">
                    <div class="grid-option">
                        <div class="grid-option-selectable">
                            <div></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="item-table"></div>
<div class="item-table"></div>

点击Cheerio元素不起作用。那么,有没有什么方法可以做到呢?

gudnpqoy

gudnpqoy1#

您可以将jquery添加到页面并在那里执行此操作:

await page.addScriptTag({path: "jquery.js"})
await page.evaluate(() => {
  // do jquery stuff here  
})
omhiaaxx

omhiaaxx2#

没有办法做到这一点。Puppeteer是一个与Cheerio完全不同的API。两者之间不相互通信,也不互操作。你唯一能做的就是在Puppeteer中快照一个HTML字符串,并将其传递给Cheerio。
Puppeteer在实时网站的浏览器上下文中工作,具有原生XPath和CSS功能--基本上,浏览器的所有功能都可供您使用。
另一方面,Cheerio是一个基于节点的HTML解析器,它模拟了浏览器环境的一小部分。它提供了Puppeteer功能的一小部分,所以在大多数情况下不要同时使用Cheerio和Puppeteer。
拍摄一张实时网站的快照,然后将字符串重新解析为Cheerio可以使用的树,这是令人困惑的,效率低下的,与使用摆在你面前的实际东西相比,没有什么明显的优势。
解决方案是坚持使用Puppeteer ElementHandle对象:

const puppeteer = require("puppeteer"); // ^19.0.0

const html = `
<div class="item-table">
  <div class="grid-item">
    <div class="grid-item-container">
      <div class="grid-table-container">
        <div class="grid-option-header">
          <div class="grid-option-caption">
            <div class="grid-option-name">
              Foo Bar
              <span>some other text</span>
            </div>
          </div>
        </div>
        <div class="grid-option-table">
          <div class="grid-option">
            <div class="grid-option-selectable">
              <div></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<script>
// for testing purposes
const el = document.querySelector(".grid-option-selectable > div");
el.addEventListener("click", e => e.target.textContent = "clicked");
el.style.height = el.style.width = "50px";
</script>
`;

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html);

  for (const el of await page.$$(".grid-item-container")) {
    const text = await el.$eval(
      ".grid-option-name",
      el => el.childNodes[0].textContent
    );
    const sel = ".grid-option-selectable > div";

    if (text.trim() === "Foo Bar") {
      const selectable = await el.$(sel);
      await selectable.click();
    }

    console.log(await el.$eval(sel, el => el.textContent)); // => clicked
  }
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

或者在浏览器中单击:

await page.$$eval(".grid-item-container", els => els.forEach(el => {
  const text = el.querySelector(".grid-option-name")
    .childNodes[0].textContent.trim();

  if (text.trim() === "Foo Bar") {
    document.querySelector(".grid-option-selectable > div").click();
  }
}));

您可能会考虑选择使用XPath或迭代childNodes来检查所有文本节点,而不是假设文本位于位置0,但是我将这些作为练习,以便集中讨论手头的要点。

相关问题