javascript 使用Puppeteer刮擦IFrame内部

liwlm1x9  于 2023-03-06  发布在  Java
关注(0)|答案(1)|浏览(114)

我正在尝试捕获网站内的信息,但iframe出现问题。
我需要访问站点https://www.saisp.br/online/produtos-publicos/,单击左侧菜单Paraíba do Sul Telemetric Network并捕获Rio Paraitinga - Passarela / São Luiz do Paraitinga线的值。
我下面的代码没有从第二个iframe中捕获信息。我该怎么做呢?

const puppeteer = require('puppeteer');

(async () => {
  // Launch a new browser instance
  const browser = await puppeteer.launch();

  // Create a new page instance
  const page = await browser.newPage();

  // Navigate to the specified webpage
  await page.goto('https://www.saisp.br/online/produtos-publicos/');

  await page.waitForTimeout(4000)

  const link = await page.$x('/html/body/app-home/div/nav/ul/li[12]/div/div[1]/a');
  await link[0].click();
  await page.waitForTimeout(2000)

  // Espera o iframe carregar e troca o contexto para ele
  // Selecione o iframe usando XPath
  const iframe = (await page.$x('/html/body/app-home/div/main/iframe'))[0];
  const frameContent = await iframe.contentFrame(); 
  await page.waitForTimeout(1000)
  await frameContent.waitForSelector('#tbTelemBody');

  const elemento = (await frameContent.$x('/html/body/div/table/tbody/tr/td[2]'))[0];
  const value = await frameContent.evaluate(el => el.textContent, elemento);

  console.log(value);

  await browser.close();
})();
fkaflof6

fkaflof61#

这实际上是一个相当复杂的页面,您的尝试是一个很好的尝试。
一般来说,avoid timeouts。为了速度和准确性,坚持使用事件驱动的代码。首选waitForSelectorwaitForXPathwaitForFunction
避免使用浏览器生成的路径,尽可能使用CSS选择器而不是XPath。
网站没有太多的元素属性标识,所以我们更倾向于使用文本来选择元素。关于Puppeteer中的文本选择技巧,请参见this thread
这里有一个方法:

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

const url = "<Your URL>";

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.goto(url, {waitUntil: "domcontentloaded"});
  const el = await page.waitForSelector("text/ba do Sul");
  await el.evaluate(el => el.click());
  const row = await page.waitForFunction(() =>
    [
      ...document
        .querySelector("iframe")
        .contentDocument.querySelectorAll("#tbDadosTelem tr"),
    ].find(e => e.textContent.includes("Luiz do Para"))
  );
  const rowData = await row.$$eval("td", els =>
    els
      .filter(e => !e.querySelector("td") && e.textContent.trim())
      .map(e => e.textContent.trim().replace(/\s+/g, " "))
  );
  console.log(rowData);
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

输出:

[
  'Rio Paraitinga - Passarela / São Luiz do Paraitinga',
  '0.6',
  '3.29'
]

相关问题