Нокогири: Разбор неправильных "<" - PullRequest
3 голосов
/ 16 июля 2010

Я пытаюсь использовать 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>

Однако я думаю, что знак "<" в "<1 г" вызывает проблемы с Нокогири. Кто-нибудь знает какие-нибудь обходные пути? Есть ли способ, которым я могу избежать знака "<"? Или, может быть, есть функция, которую я могу вызвать, чтобы получить простой HTML-сегмент? </p>

Ответы [ 2 ]

4 голосов
/ 26 января 2011

В качестве быстрого исправления я придумал этот метод, используя регулярное выражение для определения незамкнутых тегов:

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

Он работаетхорошо для меня, я ценю любые отзывы и улучшения

2 голосов
/ 17 июля 2010

«Меньше» (<) <a href="http://www.w3schools.com/HTML/html_entities.asp" rel="nofollow noreferrer"> не является допустимым 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:

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>
...