获取段落的文本,删除所有标记(及其内容)

时间:2011-09-06 14:30:36

标签: ruby nokogiri

如何只获取其中包含其他标记的节点<p>的文本:

<p>hello my website is <a href="www.website.com">click here</a> <b>test</b></p>

我只想要“hello my website is

这就是我的尝试:

begin
  node = html_doc.css('p')
  node.each do |node|
    node.children.remove
  end
  return (node.nil?) ? ''  : node.text
rescue
  return ''
end

3 个答案:

答案 0 :(得分:1)

更新2 :好的,您正在删除node.children.remove的所有子项,包括文本节点,建议的解决方案可能如下所示:

# 1. select all <p> nodes
doc.css('p').
  # 2. map children, and flatten
  map { |node| node.children }.flatten.
  # 3. select text nodes only
  select { |node| node.text? }.
  # 4. get text and join
  map { |node| node.text }.join(' ').strip

此示例返回“hello my website is”,但请注意doc.css('p') als在<p>标记内找到<p>个标记。

更新:抱歉,误读了您的问题,您只想“问好我的网站”,请参阅上面的解决方案,原始答案:

不是直接使用nokogiri,但清洁宝石可能是一个选项:https://github.com/rgrove/sanitize/

Sanitize.clean(html, {}) # => " hello my website is click here test "

仅供参考,它在内部使用了nokogiri。

答案 1 :(得分:1)

您的测试用例中没有包含任何与标记交错的有趣文本。

  • 如果您想将<p>Hello <b>World</b>!</p>转换为"Hello !",那么移除孩子就是一种方法。更简单(并且破坏性更小)就是找到所有文本节点并加入它们:

    require 'nokogiri'
    html = Nokogiri::HTML('<p>Hello <b>World</b>!</p>')
    
    # Find the first paragraph (in this case the only one)
    para = html.at('p') 
    
    # Find all the text nodes that are children (not descendants),
    # change them from nodes into the strings of text they contain,
    # and then smush the results together into one big string.
    p para.search('text()').map(&:text).join 
    #=> "Hello !"
    
  • 如果您想将<p>Hello <b>World</b>!</p>变为"Hello "(无感叹号),您可以这样做:

    p para.children.first.text # if you know that text is the first child
    p para.at('text()').text   # if you want to find the first text node
    

正如@Iwe所示,如果您愿意,可以使用String#strip方法从结果中删除前导/尾随空格。

答案 2 :(得分:0)

有一种不同的方式可以解决这个问题。而不是去除删除节点,删除这些节点包含的文本:

require 'nokogiri'

doc = Nokogiri::HTML('<p>hello my website is <a href="www.website.com">click here</a> <b>test</b></p>')
text = doc.search('p').map{ |p|
  p_text = p.text
  a_text = p.at('a').text
  p_text[a_text] = ''
  p_text
}

puts text

>>hello my website is  test

这是一个简单的示例,但我们的想法是找到<p>标记,然后在其中扫描包含您不想要的文本的标记。对于每个不需要的标签,抓住他们的文本并从周围的文本中删除它。

在示例代码中,您在a_text分配中有一个不受欢迎的节点列表,循环遍历它们,并迭代删除文本,如下所示:

text = doc.search('p').map{ |p|
  p_text = p.text
  %w[a].each do |bad_nodes|
    bad_nodes_text = p.at(bad_nodes).text
    p_text[bad_nodes_text] = ''
  end
  p_text
}

您返回text,这是<p>个节点的调整文本内容数组。