使用JavaScript从HTML字符串中提取文本

69

我正在尝试使用一个JS函数获取HTML字符串的内部文本(该字符串作为参数传递)。以下是代码:

function extractContent(value) {
  var content_holder = "";

  for (var i = 0; i < value.length; i++) {
    if (value.charAt(i) === '>') {
      continue;
      while (value.charAt(i) != '<') {
        content_holder += value.charAt(i);
      }
    }

  }
  console.log(content_holder);
}

extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");

问题在于控制台没有打印任何内容(*content_holder*保持为空)。我认为问题是由 === 运算符引起的。


3
由于continue指令的存在,您的while循环永远不会被执行。 - Arnaud Christ
尝试使用“调试器”跟踪代码,你这样做了吗? - user663031
可能是JS:在没有jQuery的情况下从字符串中提取文本的重复问题。 - Rehan Haider
另外类似:https://dev59.com/wWkv5IYBdhLWcg3wdQhT - Akber Iqbal
这个回答解决了你的问题吗?通过JavaScript获取纯文本而不带HTML元素? - KyleMit
11个回答

127
创建一个元素,将 HTML 存储在其中,并获取其 textContent

function extractContent(s) {
  var span = document.createElement('span');
  span.innerHTML = s;
  return span.textContent || span.innerText;
};
    
alert(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>"));


这里有一个版本,可以让你在节点之间添加空格,不过你可能只想对块级元素使用这个功能:


function extractContent(s, space) {
  var span= document.createElement('span');
  span.innerHTML= s;
  if(space) {
    var children= span.querySelectorAll('*');
    for(var i = 0 ; i < children.length ; i++) {
      if(children[i].textContent)
        children[i].textContent+= ' ';
      else
        children[i].innerText+= ' ';
    }
  }
  return [span.textContent || span.innerText].toString().replace(/ +/g,' ');
};
    
console.log(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>.  Nice to <em>see</em><strong><em>you!</em></strong>"));

console.log(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>.  Nice to <em>see</em><strong><em>you!</em></strong>",true));


输出 HelloW3C - 真的是 OP 想要的吗?不是 Hello W3C 吗? - davidkonrad
1
不需要空格 :) 很抱歉没有提到! - Toshkuuu
2
添加了一个版本,可以在节点之间添加空格。 - Rick Hitchcock
1
警告:此处容易受到 XSS 攻击。只有在您了解并控制参数内容的情况下,才将其分配给 innerHTML。 - Toni
2
@Gangula,你应该使用DOMParser,这在我2015年发布时并不常见。 - Rick Hitchcock
显示剩余3条评论

77

一行(更准确地说,一个语句)版本:

function extractContent(html) {
    return new DOMParser()
        .parseFromString(html, "text/html")
        .documentElement.textContent;
}

1
很好的回答+1,但是你的回答和Rick Hitchcock的回答有什么区别? - Sharique Ansari
1
@shariqueansari,DOMParser是“实验性技术”,但很可能会被添加到规范中。它的HTML支持在IE10+中工作。我的原始答案适用于IE9+,但现在已更新以支持IE8。 - Rick Hitchcock
1
DOMParser现在得到广泛支持,请参见https://caniuse.com/#search=domparser。 - Optimae
2
本以为这可以在Node.js上运行,但实际上不行。最终使用了https://www.npmjs.com/package/html2plaintext。 - Flion
我们可以使用这种方法通过id提取一些内容,例如:document.getElementById吗? - Hamid Araghi

37

textContent是实现期望结果的非常好的技术,但有时我们不想加载DOM。因此,一个简单的解决方法是使用以下正则表达式:


let htmlString = "<p>Hello</p><a href='http://w3c.org'>W3C</a>"
let plainText = htmlString.replace(/<[^>]+>/g, '');

我知道这是一个非常老的评论,但您能否解释一下表达式/<[^>]+>/g的含义?我很难理解每个单独字符的意思。 - Kelly
@Kelly,你所提到的符号是正则表达式。它有点像用于解析文本的迷你编程语言。以下是一个链接,你可以在这里了解更多关于每个符号的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions - Kade
它的基本含义是查找并删除每个包含非 > 之间的内容的 <* 以及 *> 之间的。 - Kade
最有用的,正则表达式,是程序员中最好的工具/迷你语言之一。 - GD- Ganesh Deshmukh
不同的情况需要不同的技术,而这正是我处理Telegram机器人开发时的正确方法,因为它不需要像网页开发中那样使用innerHTML或其他类似的东西。 - hanism

8

使用以下正则表达式去除HTML标签并仅存储HTML中的纯文本内容

它将显示HelloW3c,只需检查即可。

var content_holder = value.replace(/<(?:.|\n)*?>/gm, '');

请给我一个理由好吗? - Rana Ahmer Yasin
2
https://dev59.com/X3I-5IYBdhLWcg3wq6do#1732454 - user663031
1
如果你要使用正则表达式,那么一个更简单的版本是 /<[\s\S]*?>/ 或者 /<[^]*?>/。你的 m 标志没有任何作用;它与 ^$ 的行为有关。 - user663031

2

针对Node.js

这将使用jsdom库,因为node.js没有浏览器中的DOM功能。

import * as jsdom from "jsdom";

const html = "<h1>Testing<h1>";
const text = new jsdom.JSDOM(html).window.document.textContent;

console.log(text);

2

尝试这个:

<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
function extractContent(value){
        var div = document.createElement('div')
        div.innerHTML=value;
        var text= div.textContent;            
        return text;
}
window.onload=function()
{
   alert(extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>"));
};
</script>
</body>
</html>


你测试过这个吗?它提取"W3C"失败了,就像它应该做的那样。 - user663031
请使用字符串“Hello,<p> Buggy <i> World </i> </ p>”尝试您的解决方案。 - user663031

0
你可以将它暂时写入一个定位在页面外的块级元素中,就像这样:

HTML:

<div id="tmp" style="position:absolute;top:-400px;left:-400px;">
</div>

JavaScript:

<script type="text/javascript">
function extractContent(value){
        var div=document.getElementById('tmp');
        div.innerHTML=value;
        console.log(div.children[0].innerHTML);//console out p
}

extractContent("<p>Hello</p><a href='http://w3c.org'>W3C</a>");
</script>

1
正确的方法,但你不需要在DOM中使用元素来完成这个操作。只需使用 var div = document.createElement('div') 创建一个元素,然后从那里继续进行即可。 - user663031
此外,如果存在嵌套的HTML元素,例如 <p>Hello<i>Bob</i></p><a>...</a>,则此方法会失败。 它将保留p元素内部的标记。 - user663031

0

使用jQuery,我们可以添加逗号分隔的标签。

var readableText = [];
$("p, h1, h2, h3, h4, h5, h6").each(function(){ 
     readableText.push( $(this).text().trim() );
})
console.log( readableText.join(' ') );

0
基于 Rick Hitchcock答案KevBot的答案,这是我找到的最佳实现方式:
function getTextLoop(element: HTMLElement | ChildNode) {
  const texts = [];
  Array.from(element.childNodes).forEach((node) => {
    if (node.nodeType === 3) {
      texts.push(node.textContent.trim());
    } else {
      texts.push(...getTextLoop(node));
    }
  });
  return texts;
}

function innerText(element: HTMLElement) {
  return getTextLoop(element).join(" ");
}

export function extractContent(s, space) {
  var span = document.createElement("span");
  span.innerHTML = s;
  if (space) {
    span.innerHTML = innerText(span);
  }
  return [span.textContent || span.innerText].toString().replace(/ +/g, " ");
}

例子:

extractContent("<div>foo<div>bar</div></div>", true); // foo bar

0
使用match()函数来提取HTML标签

const text = `<div>Hello World</div>`;
console.log(text.match(/<[^>]*?>/g));


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接