【问题标题】:Strip text from HTML document using Ruby使用 Ruby 从 HTML 文档中去除文本
【发布时间】:2010-12-02 14:50:03
【问题描述】:

有很多例子说明如何使用 Ruby 从文档中去除 HTML 标签,Hpricot 和 Nokogiri 有 inner_text 方法,可以轻松快速地删除所有 HTML。

我想做的是相反的,从 HTML 文档中删除所有文本,只留下标签及其属性。

我考虑循环通过将文档设置 inner_html 设置为 nil 但实际上您必须反向执行此操作,因为第一个元素(根)具有整个文档其余部分的 inner_html,所以理想情况下我必须从最里面的元素开始,将 inner_html 设置为 nil,同时向上移动通过祖先。

有没有人知道一个巧妙的小技巧可以有效地做到这一点?我在想也许正则表达式可能会做到这一点,但可能不如 HTML 标记器/解析器效率高。

【问题讨论】:

  • 您将不得不处理不良标记吗? (未转义的实体等)
  • 有可能 - 我正在处理的标记来自最终用户,因此不能依赖。

标签: html ruby nokogiri hpricot


【解决方案1】:

你可以扫描字符串来创建一个“tokens”数组,然后只选择那些是html标签的:

>> some_html
=> "<div>foo bar</div><p>I like <em>this</em> stuff <a href='http://foo.bar'> long time</a></p>"
>> some_html.scan(/<\/?[^>]+>|[\w\|`~!@#\$%^&*\(\)\-_\+=\[\]{}:;'",\.\/?]+|\s+/).select { |t| t =~ /<\/?[^>]+>/ }.join("")
=> "<div></div><p><em></em><a href='http://foo.bar'></a></p>"

==编辑==

或者更好的是,只需扫描 html 标签 ;)

>> some_html.scan(/<\/?[^>]+>/).join("")
=> "<div></div><p><em></em><a href='http://foo.bar'></a></p>"

【讨论】:

    【解决方案2】:

    要获取标签之外的所有内容,您可以像这样使用 nokogiri:

    doc.search('//text()').text
    

    当然,这会抓取 &lt;script&gt;&lt;style&gt; 标签的内容,因此您也可以删除列入黑名单的标签:

    blacklist = ['title', 'script', 'style']
    nodelist = doc.search('//text()')
    blacklist.each do |tag|
      nodelist -= doc.search('//' + tag + '/text()')
    end
    nodelist.text
    

    如果您愿意,也可以将其列入白名单,但这可能会更耗时:

    whitelist = ['p', 'span', 'strong', 'i', 'b']  #The list goes on and on...
    nodelist = Nokogiri::XML::NodeSet.new(doc)
    whitelist.each do |tag|
      nodelist += doc.search('//' + tag + '/text()')
    end
    nodelist.text
    

    您也可以只构建一个巨大的 XPath 表达式并进行一次搜索。老实说,我不知道哪种方式更快,或者是否有明显的差异。

    【讨论】:

      【解决方案3】:

      这也有效:

      doc = Nokogiri::HTML(your_html)
      doc.xpath("//text()").remove
      

      【讨论】:

      • 太棒了!在末尾扔一个.to_s 得到一个字符串,你就可以开始了!
      【解决方案4】:

      我刚想出这个,但@andre-r 的解决方案soo 好多了!

      #!/usr/bin/env ruby
      
      require 'nokogiri'
      
      def strip_text doc
        Nokogiri(doc).tap { |doc|
          doc.traverse do |node|
            node.content = nil if node.text?
          end
        }.to_s
      end
      
      require 'test/unit'
      require 'yaml'
      class TestHTMLStripping < Test::Unit::TestCase
        def test_that_all_text_gets_strippped_from_the_document
          dirty, clean = YAML.load DATA
          assert_equal clean, strip_text(dirty)
        end
      end
      __END__
      ---
      - |
        <!DOCTYPE html>
        <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
          <head>
              <meta http-equiv='Content-type'     content='text/html; charset=UTF-8' />
              <title>Test HTML Document</title>
              <meta http-equiv='content-language' content='en' />
          </head>
          <body>
              <h1>Test <abbr title='Hypertext Markup Language'>HTML</abbr> Document</h1>
              <div class='main'>
                  <p>
                      <strong>Test</strong> <abbr title='Hypertext Markup Language'>HTML</abbr> <em>Document</em>
                  </p>
              </div>
          </body>
        </html>
      - |
        <!DOCTYPE html>
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title></title>
        <meta http-equiv="content-language" content="en">
        </head>
        <body><h1><abbr title="Hypertext Markup Language"></abbr></h1><div class="main"><p><strong></strong><abbr title="Hypertext Markup Language"></abbr><em></em></p></div></body>
        </html>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-23
        • 2011-12-30
        • 2012-10-01
        • 2016-11-07
        • 1970-01-01
        相关资源
        最近更新 更多