簡體   English   中英

為什么即使我添加了選擇器,puppeteer 也不能從 iframe 中抓取元素

[英]why can't puppeteer scrape an element from a iframe even if I add the selector

我使用 puppeteer 編寫了一個小型網絡抓取工具,但我似乎無法正確提取我想要的信息。 你能幫我找出錯誤嗎?

背景:我想抓取一個網站,該網站表明該城市允許房東為休息控制的公寓(例如黃金地段)增加多少保費。

到目前為止我所做的(下面的代碼):我能夠瀏覽網站,訪問 iframe,編寫一些輸入,單擊按鈕並獲得結果匯總表。 我想提取前兩行的日期和歐元值並將其保存到 json 中。 最終,我想對一堆地址執行此操作(仍然需要檢查我如何輕松地執行此操作),然后匯總此信息(與上一期間的溢價差異等)。

問題:我可以隔離我想要的相關信息的選擇器,但使用 frame.$$eval 或 frame.$ 什么也沒有提供(但沒有錯誤地運行)。 所以我使用了超時的 waitForSelector 並且 frame.evaluate 拋出了一個錯誤。 這一切都非常奇怪。 我的下一個方法是抓取整個表單/摘要 - 這有效! 當我將對象打印到控制台時,我有一個長字符串,其中包含頁面上的所有內容,包括我的信息。 但是,這是高度非結構化的,我無法弄清楚如何使用它來隔離我的信息。 另外,我無法將其保存到json文件中(僅保存了一部分文本)。

const puppeteer = require("puppeteer");
const chalk = require("chalk");
const fs = require('fs');
const error = chalk.bold.red;
const success = chalk.keyword("green");

(async () => {
  try {
    // open the headless browser
      var browser = await puppeteer.launch({slowMo: 250});

    // open a new page
      var page = await browser.newPage();

    // enter url in page
      await page.goto(`https://mein.wien.gv.at/Meine-Amtswege/richtwert?subpage=/lagezuschlag/`, {waitUntil: 'networkidle2'});
   // continue without newsletter
      await page.click('#dss-modal-firstvisit-form > button.btn.btn-block.btn-light');
   // let everyhting load
      await page.waitFor(5000)
      console.log('waiting for iframe with form to be ready.');
      //wait until selector is available
      await page.waitForSelector('iframe');
      console.log('iframe is ready. Loading iframe content');
      //choose the relevant iframe
      const elementHandle = await page.$(
          'iframe[src="/richtwertfrontend/lagezuschlag/"]',
      );
      //go into frame in order to input info
      const frame = await elementHandle.contentFrame();
      //enter address
      console.log('filling form in iframe');
      await frame.type('#input_adresse', 'Gumpendorfer Straße 12, 1060 Wien', { delay: 1000 });

      //choose first option from dropdown
      console.log('Choosing from dropdown');
      await frame.click('#react-autowhatever-1--item-0');

      console.log('pressing button');
      //press button to search
      await frame.click('#next-button');

      // scraping data
      console.log('scraping')
      const optionsResult = await frame.$$eval('#summary', (options) => {
          const result = options.map(option => option.textContent);
          return result;
            });

    console.log(optionsResult);

   await browser.close();

          fs.writeFile("data.json", JSON.stringify(optionsResult), 'utf8', function(err) {
            if(err) {
                return console.log(error(err));
            }
            console.log(success("The data has been scraped and saved successfully! View it at './data.json'"));
        });

    console.log(success("Browser Closed"));
  } catch (err) {
      // Catch and display errors
      console.log(error(err));
      await browser.close();
      console.log(error("Browser Closed"));
    }


})();

我發布了完整的代碼以供完成,重要的是從第 45 行開始的“抓取”部分。

我已經仔細閱讀了 SO 並閱讀了許多不同的線程,但還沒有找到解決方案。 我希望一切都清楚,我將不勝感激!

PS 我對 JS/node.js/puppeteer 很陌生,如果有一些不准確的地方,我很抱歉,我還不知道語言的來龍去脈。

一些考慮。

  1. await frame.type('#input_adresse', 'Gumpendorfer Straße 12, 1060 Wien', { delay: 1000 }); — 1000 似乎太長了,也許 100 甚至 50 就足夠了。

  2. textContent更喜歡innerText以獲得更具可讀性的內容。

  3. 這是您如何獲得更多結構化數據、包含行和單元格的多維數組:

      // scraping data
      console.log('scraping')
      await frame.waitForSelector('#summary > div > div > br ~ div');
      const optionsResult = await frame.evaluate(() => {
        const rows = [...document.querySelectorAll('#summary > div > div > br ~ div')];
        const cells = rows.map(
          row => [...row.querySelectorAll('div')]
                   .map(cell => cell.innerText)
        );
        return cells;
      });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM