如何使用Nokogiri正确修复未关闭的HTML标记

时间:2015-09-15 17:40:00

标签: ruby nokogiri

我很难获得网站生成的HTML。 HTML包含一些未关闭的标记。

例如:

<div>
  <li>
    <div>
      <div>
        test
      </div>

  <li>
     <div>
       test 
     </div>

解析HTML:

html = Nokogiri::HTML(open('origin.html'))

结果:

Nokogiri object

或者,在HTML中:

  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">

    <html><body>
      <div>

        <li>
          <div>
            <div>
              test
            </div>

        <li>
          <div>
            test 
          </div>

    </li>
    </div>
    </li>
    </div>
    </body>
    </html>

我相信正确的事情会是:

  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
   <body>
    <div>
      <li>
        <div>
          <div>
            test
          </div>
        </div>
      </li>

      <li>
        <div>
           test 
        </div>
      </li>
    </div>
  </body>
</html>

知道如何解决这个问题吗?换到另一个宝石?在解析之前使用正则表达式来更改HTML?

3 个答案:

答案 0 :(得分:4)

您可以查看使用NokogumboGoogles’ Gumbo HTML5 parser附加到Nokogiri。然后,在解析格式错误的HTML时,将使用HTML5纠错算法,而不是默认解析我的Nokogiri和libxml,并且将导致解析的HTML更接近您希望从浏览器中看到的内容。

这是一个示例irb会话,展示了它如何处理您的示例HTML并生成您所追求的结果。请注意,方法名称为HTML5,并且仍在Nokogiri模块上调用。

>> require 'nokogumbo'
=> true
>> s = <<EOT
<div>
  <li>
    <div>
      <div>
        test
      </div>

  <li>
     <div>
       test
     </div>
EOT
=> "<div>\n  <li>\n    <div>\n      <div>\n        test\n      </div>\n\n  <li>\n     <div>\n       test \n     </div>\n"
>> puts Nokogiri.HTML5(s).to_html
<html>
<head></head>
<body><div>
  <li>
    <div>
      <div>
        test
      </div>

  </div>
</li>
<li>
     <div>
       test
     </div>
</li>
</div></body>
</html>
=> nil

答案 1 :(得分:0)

您认为您的<li>不应该嵌套?让我们试着理解为什么Nokogiri以这种方式解析它:

<div>
  <li>
    <div>  <!-- unclosed div -->
      <div>
        test
      </div>    
      <li>
        <div>
           test 
        </div>

首先,您的HTML无效,因为(除了缺少结束标记)没有<ul><ol>标记,因此Nokogiri会从第一个<li>标记开始立即猜测。< / p>

接下来,让我们看一下有关结束标记省略的规范:<li> may omit结束标记,但<div> may not omit

嵌套<li> - 标签的方式,Nokogiri试图找到第二个<div>的结束标记(参见上面代码清单中的HTML注释)并选择较小的邪恶,尽管没有嵌套<ul>标记。

答案 2 :(得分:0)

如何修复未终止/未关闭的标签取决于您的目标。 @Matt的建议是合理的,但是如果原始HTML在病理上是错误的,它仍会导致错误的HTML,并且,此时你必须介入并在让任何其他解析器尝试制作之前进行修复感觉。

是否需要使用正则表达式或简单的字符串操作或提取特定行并将其解析为片段取决于具体情况。为了能够在严重破坏的HTML上多次使用解析器,并且每次都是一个不同的过程,我必须做一些非常丑陋的事情。