【问题标题】:Unable to extract the text of a simple selector using Cheerio无法使用 Cheerio 提取简单选择器的文本
【发布时间】:2023-02-06 00:40:07
【问题描述】:

我正在尝试使用 cheerio(请参阅下面的代码 sn-p)从其页面 (https://chrome.google.com/webstore/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh) 中提取与 Chrome 扩展程序描述相对应的文本,但无济于事。 如您所见,我尝试了 3 种不同的简易选择器,但它们都产生了一个空字符串。

var request = require('request');
var cheerio = require('cheerio');

request('https://chrome.google.com/webstore/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh',
     function (error, response, html) {
         if (!error && response.statusCode == 200) {
                     var $ = cheerio.load(html);
                     console.log ( $('div.C-b-p-j-D.Ka-Ia-j.C-b-p-j-D-gi').text() )
                     console.log( $("div[itemprop='description']").text())
                     console.log ( $("div.C-b-p-j-Pb").text() )
         }});

不过,第一个选择器在 DevTools 控制台中完美运行:

任何提示将不胜感激。

【问题讨论】:

    标签: javascript cheerio


    【解决方案1】:

    有趣的问题。数据在静态响应中,因此 Cheerio 应该能够找到它。您可以看到它适用于 JSDOM:

    const {JSDOM} = require("jsdom"); // 20.0.0
    
    const url = "https://chrome.google.com/webstore/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh";
    JSDOM.fromURL(url).then(({window: {document}}) => {
      const selector = ".C-b-p-j-D.Ka-Ia-j.C-b-p-j-D-gi";
      console.log(document.querySelector(selector).textContent);
    });
    

    使用 Python/BeautifulSoup:

    import requests
    from bs4 import BeautifulSoup
    
    url = "https://chrome.google.com/webstore/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh"
    response = requests.get(url)
    response.raise_for_status()
    soup = BeautifulSoup(response.text, "lxml")
    
    print(soup.select_one('meta[property="og:description"]')["content"])
    print("-" * 50)
    print(soup.select_one("[itemprop='description']").text)
    print("-" * 50)
    print(soup.select_one('.C-b-p-j-D.Ka-Ia-j.C-b-p-j-D-gi').text)
    

    将问题最小化后,归结为:

    const {load} = require("cheerio"); // 1.0.0-rc.12
    
    const html = `<!DOCTYPE html>
    <html>
    <body>
      <noscript>
        <p>foo</p>
      </noscript>
    </body>
    </html>`;
    
    console.dir(load(html)("p").text()); // => ''
    console.dir(load(html, {scriptingEnabled: false})("p").text()); // => 'foo'
    console.dir(load(html, {xml: true})("p").text()); // => 'foo'
    

    您可以看到 &lt;noscript&gt; 标签是罪魁祸首。添加两个选项之一,scriptingEnabled: falsexml: true(或弃用的xmlMode)允许 Cheerio 解析 &lt;noscript&gt; 的内容。详情请见Cheerio issue #1105

    乍一看,我不清楚哪个更可取,但是this comment 表示xmlMode 有副作用,可能导致页面无法解析,所以我暂时选择scriptingEnabled

    回到你的代码。我使用了 fetch,它在最近的 Node 版本中是原生的,但这是一个外观上的变化。您可以使用任何请求库。

    const cheerio = require("cheerio"); // 1.0.0-rc.12
    
    const url = "https://chrome.google.com/webstore/detail/earth-view-from-google-ea/bhloflhklmhfpedakmangadcdofhnnoh";
    
    fetch(url)
      .then(response => {
        if (!response.ok) {
          throw Error(response.status);
        }
    
        return response.text();
      })
      .then(html => {
        const $ = cheerio.load(html, {scriptingEnabled: false});
        console.log($("div.C-b-p-j-D.Ka-Ia-j.C-b-p-j-D-gi").text());
        console.log($('div[itemprop="description"]').text());
        console.log($("div.C-b-p-j-Pb").text());
      });
    

    顺便说一句,一些数据在标头中的标记中可用:

    <meta property="og:description" content="Experience a beautiful image from Google Earth every time you open a new tab.">
    

    由于这不在 &lt;noscript&gt; 中,您可以在没有特殊选项的情况下选择它:

    const $ = cheerio.load(html); // nothing special
    console.log($('meta[property="og:description"]').attr("content"));
    

    【讨论】:

    • 哇!感谢您的详细解释和公开的不同选择。我从这个答案中学到了很多东西。
    猜你喜欢
    • 1970-01-01
    • 2013-06-27
    • 2021-09-25
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多