【问题标题】:Getting all the text content from a HTML string in NodeJS从 NodeJS 中的 HTML 字符串中获取所有文本内容
【发布时间】:2020-06-16 02:29:17
【问题描述】:

我只需要从 HTML 字符串中获取文本内容,并用空格或换行符分隔不同元素的文本内容。

例如,HTML 字符串可能是:

<ul>
  <li>First</li>
  <li>Second</li>
</ul>

我想要什么:

First Second

First
Second

我尝试通过首先将整个字符串包装在 div 中,然后使用第三方库获取 textContent 来获取文本内容。但是,我特别需要的不同元素的文本内容之间没有空格或换行符(即我得到FirstSecond,这不是我想要的)。

我现在想到的唯一解决方案是创建一个 DOM 树,然后应用递归来获取包含文本的节点,然后将该元素的文本附加到带有空格的字符串中。 还有比这更干净、更整洁、更简单的解决方案吗?

【问题讨论】:

  • 你可以使用包cheerio来做这些事情,它是为抓取/导航/选择HTML内容而构建的。

标签: javascript html node.js parsing


【解决方案1】:

使用 DOM,您可以使用 document.Node.textContent。但是,NodeJs 没有 textContent(因为它没有对 DOM 的本机访问),因此您应该使用外部包。您可以使用 npm 安装 requestcheeriocheerio,由Jon Church 建议,可能是最容易使用的网络抓取工具(也有更复杂的工具,如jsdom) 有了cheeriorequest 的力量,你就可以写了

const request = require("request");
const cheerio = require("cheerio");
const fs = require("fs");

//taken from https://stackoverflow.com/a/19709846/10713877
function is_absolute(url)
{
    var r = new RegExp('^(?:[a-z]+:)?//', 'i');
    return r.test(url);
}

function is_local(url)
{
    var r = new RegExp('^(?:file:)?//', 'i');
    return (r.test(url) || !is_absolute(url));
}

function send_request(URL)
    {
        if(is_local(URL))
        {
            if(URL.slice(0,7)==="file://")
                url_tmp = URL.slice(7,URL.length);
            else
                url_tmp = URL;

           //taken from https://stackoverflow.com/a/20665078/10713877
           const $ = cheerio.load(fs.readFileSync(url_tmp));
           //Do something
           console.log($.text())
        }
        else
        {
            var options = {
                url: URL,
                headers: {
                  'User-Agent': 'Your-User-Agent'
                }
              };

            request(options, function(error, response, html) {
                //no error
                if(!error && response.statusCode == 200)
                {
                    console.log("Success");

                    const $ = cheerio.load(html);


                    return Promise.resolve().then(()=> {
                        //Do something
                        console.log($.text())
                    });
                }
                else
                {
                    console.log(`Failure: ${error}`);
                }
            });
        }
    }

让我解释一下代码。您将 URL 传递给 send_request 函数。它检查 URL 字符串是否是本地文件的路径(相对路径或以 file:// 开头的路径)。如果是本地文件,则继续使用cheerio 模块,否则,它必须使用request 模块向网站发送请求,然后使用cheerio 模块。正则表达式用于is_absoluteis_local。您可以使用cheerio 提供的text() 方法获取文本。在 cmets //Do something 下,您可以对文本做任何您想做的事情。 有些网站会让您知道'Your-User-Agent',将您的用户代理复制粘贴到该字段。

以下几行将起作用

//your local file
send_request("/absolute/path/to/your/local/index.html"); 
send_request("/relative/path/to/your/local/index.html"); 
send_request("file:///absolute/path/to/your/local/index.html"); 
//website
send_request("https://stackoverflow.com/"); 

编辑:我使用的是 linux 系统。

【讨论】:

  • 这很有帮助,但这里的内容比回答问题所需的内容要多得多。如果您想让这个答案更有用,我建议您删除有关在节点中使用 fs/request 的所有内容,并回答如何将 html 字符串转换为节点的内部文本。
【解决方案2】:

好的,你可以试试这个例子,这可能对你有帮助

我用JSDom模块

https://www.npmjs.com/package/jsdom

const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
console.log(dom.window.document.querySelector("p").textContent); 

顺便说一句,帮助了我

这段代码可以帮助我思考:)

【讨论】:

    【解决方案3】:

    您可以尝试使用正则表达式摆脱 html 标记,对于您的示例,请尝试以下操作:

    let str = `<ul>
    <li>First</li>
    <li>Second</li>
    </ul>`
    
    console.log(str)
    
    let regex = '<\/?!?(li|ul)[^>]*>'
    
    var re = new RegExp(regex, 'g');
    
    str = str.replace(re, '');
    console.log(str)
    

    【讨论】:

      猜你喜欢
      • 2011-12-08
      • 2019-11-16
      • 1970-01-01
      • 2011-12-01
      • 2013-07-03
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 2012-05-15
      相关资源
      最近更新 更多