【问题标题】:Retrieving JavaScript Rendered HTML with Puppeteer使用 Puppeteer 检索 JavaScript 渲染的 HTML
【发布时间】:2017-08-24 21:29:59
【问题描述】:

我正在尝试从this NCBI.gov page 中抓取 html。我需要包含#see-all URL 片段,这样我才能保证获得搜索页面,而不是从不正确的基因页面https://www.ncbi.nlm.nih.gov/gene/119016 中检索 HTML。

URL 片段不会传递给服务器,而是由页面客户端的 javascript 用于(在这种情况下)创建完全不同的 HTML,这是您在浏览器中访问页面时得到的和“查看页面源代码”,这是我要检索的 HTML。 R readLines() ignores url tags followed by #

我首先尝试使用 phantomJS,但它只是返回了此处描述的错误ReferenceError: Can't find variable: Map,这似乎是由于 phantomJS 不支持 NCBI 正在使用的某些功能,从而消除了解决此问题的途径。

我使用以下用 node.js 评估的 Javascript 在 Puppeteer 上取得了更大的成功:

const puppeteer = require('puppeteer');
(async() => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(
    'https://www.ncbi.nlm.nih.gov/gene/?term=AGAP8#see-all');
  var HTML = await page.content()
  const fs = require('fs');
  var ws = fs.createWriteStream(
    'TempInterfaceWithChrome.js'
  );
  ws.write(HTML);
  ws.end();
  var ws2 = fs.createWriteStream(
    'finishedFlag'
  );
  ws2.end();
  browser.close();
})();

然而,这返回了似乎是预渲染的 html。我如何(以编程方式)获取我在浏览器中获得的最终 html?

【问题讨论】:

    标签: javascript node.js web-scraping google-chrome-headless puppeteer


    【解决方案1】:

    您可以尝试更改此设置:

    await page.goto(
      'https://www.ncbi.nlm.nih.gov/gene/?term=AGAP8#see-all');
    

    进入这个:

      await page.goto(
        'https://www.ncbi.nlm.nih.gov/gene/?term=AGAP8#see-all', {waitUntil: 'networkidle'});
    

    或者,您可以创建一个函数listenFor() 来监听页​​面加载时的自定义事件:

    function listenFor(type) {
      return page.evaluateOnNewDocument(type => {
        document.addEventListener(type, e => {
          window.onCustomEvent({type, detail: e.detail});
        });
      }, type);
    }`
    
    await listenFor('custom-event-ready'); // Listen for "custom-event-ready" custom event on page load.
    

    乐:

    这也可能派上用场:

    await page.waitForSelector('h3'); // replace h3 with your selector
    

    【讨论】:

      【解决方案2】:

      等一下

      await page.waitForNavigation(5);
      

      之后

      let html = await page.content();
      

      【讨论】:

      • 这只会给你最初的 html 内容
      【解决方案3】:

      我成功使用以下内容获取页面加载后生成的 html 内容。

      const browser = await puppeteer.launch();
      try {
        const page = await browser.newPage();
        await page.goto(url);
        await page.waitFor(2000);
        let html_content = await page.evaluate(el => el.innerHTML, await page.$('.element-class-name'));
        console.log(html_content);
      } catch (err) {
        console.log(err);
      }
      

      希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        如果您想真正等待自定义事件,您可以这样做。

        const page = await browser.newPage();
        
        /**
          * Attach an event listener to page to capture a custom event on page load/navigation.
          * @param {string} type Event name.
          * @return {!Promise}
          */
        function addListener(type) {
          return page.evaluateOnNewDocument(type => {
            // here we are in the browser context
            document.addEventListener(type, e => {
              window.onCustomEvent({ type, detail: e.detail });
            });
          }, type);
        }
        
        const evt = await new Promise(async resolve => {
          // Define a window.onCustomEvent function on the page.
          await page.exposeFunction('onCustomEvent', e => {
            // here we are in the node context
            resolve(e); // resolve the outer Promise here so we can await it outside
          });
        
          await addListener('app-ready'); // setup listener for "app-ready" custom event on page load
          await page.goto('http://example.com');  // N.B! Do not use { waitUntil: 'networkidle0' } as that may cause a race condition
        });
        
        console.log(`${evt.type} fired`, evt.detail || '');
        

        https://github.com/GoogleChrome/puppeteer/blob/master/examples/custom-event.js 的示例为基础

        【讨论】:

          【解决方案5】:

          在我的情况下等待网络空闲是不够的,所以我使用了 dom 加载事件:

          await page.goto(url, {waitUntil: 'domcontentloaded', timeout: 60000} );
          const data = await page.content();
          

          【讨论】:

            【解决方案6】:

            确实需要innerHTML:

            fs.writeFileSync( "test.html", await (await page.$("html")).evaluate( (content => content.innerHTML ) ) );
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-11-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-01-12
              相关资源
              最近更新 更多