Nokogiri:解析不规则“<”

时间:2010-07-16 19:53:17

标签: ruby-on-rails xml nokogiri mechanize

我正在尝试使用nokogiri来解析以下段

<tr>
 <th>Total Weight</th>
 <td>< 1 g</td>
 <td style="text-align: right">0 %</td>

</tr>             
<tr><td class="skinny_black_bar" colspan="3"></td></tr>

然而,我认为“&lt;”登录“&lt; 1 g”导致Nokogiri问题。有谁知道任何变通方法?有没有办法逃脱“&lt;”标志?或者也许我可以调用一个函数来获取普通的html片段?

2 个答案:

答案 0 :(得分:4)

作为一个快速修复,我想出了这个方法,使用reqular表达式来识别未闭合的标签:

def fix_irregular_html(html)
  regexp = /<([^<>]*)(<|$)/

  #we need to do this multiple time as regex are overlapping
  while (fixed_html = html.gsub(regexp, "&lt;\\1\\2")) && fixed_html != html
    html = fixed_html
  end

  fixed_html
end

查看完整代码,包括此处的测试:   https://gist.github.com/796571

对我来说效果很好,我感谢任何反馈和改进

答案 1 :(得分:2)

“小于”(&lt;)isn't legal HTML,但浏览器有很多代码用于确定HTML的含义而不仅仅是显示错误。这就是为什么您的无效HTML示例会以您希望的方式显示在浏览器中。

所以诀窍是确保Nokogiri做同样的工作来弥补糟糕的HTML。确保将文件解析为HTML而不是XML:

f = File.open("table.html")
doc = Nokogiri::HTML(f)

这样可以很好地解析您的文件,但会丢弃< 1 g文本。看看如何解析前两个TD元素的内容:

doc.xpath('(//td)[1]/text()').to_s
=> "\n "

doc.xpath('(//td)[2]/text()').to_s
=> "0 %"

Nokogiri抛弃了你的无效文本,但不断解析周围的结构。你甚至可以看到Nokogiri的错误信息:

doc.errors
=> [#<Nokogiri::XML::SyntaxError: htmlParseStartTag: invalid element name>]
doc.errors[0].line
=> 3

是的,第3行很糟糕。

因此,似乎Nokogiri对解析无效HTML的支持程度与浏览器不同。我建议使用其他一些库来预处理您的文件。我尝试在您的示例文件上运行TagSoup并修改<,将其更改为&lt;,如下所示:

% java -jar tagsoup-1.1.3.jar foo.html | xmllint --format -
src: foo.html
<?xml version="1.0" standalone="yes"?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
    <table>
      <tbody>
        <tr>
          <th colspan="1" rowspan="1">Total Weight</th>
          <td colspan="1" rowspan="1">&lt;1 g</td>
          <td colspan="1" rowspan="1" style="text-align: right">0 %</td>
        </tr>
        <tr>
          <td colspan="3" rowspan="1" class="skinny_black_bar"/>
        </tr>
      </tbody>
    </table>
  </body>
</html>