Как я могу использовать Nokogiri и Ruby для очистки значений из HTML с вложенными таблицами? - PullRequest
5 голосов
/ 14 мая 2011

Я пытаюсь извлечь имя, идентификатор, телефон, электронную почту, пол, этническую принадлежность, DOB, класс, майор, школу и средний балл со страницы, которую я анализирую с Nokogiri.

Я пробовал несколько разных путей xpath, но все, что я пробую, захватывает гораздо больше, чем я хочу:

<span class="subTitle"><b>Recruit Profile</b></span>
<br><table border="0" width="100%"><tr>
<td>
      <table bgcolor="#afafaf" border="0" cellpadding="0" width="100%">
<tr>
<td>
      <table bgcolor="#cccccc" border="0" cellpadding="2" cellspacing="2" width="100%">
<tr>
<td bgcolor="#dddddd"><b>Name</b></td>
          <td bgcolor="#dddddd">Some Person</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>EDU ID</b></td>
          <td bgcolor="#dddddd">A12345678</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Phone</b></td>
          <td bgcolor="#dddddd">123-456-7890</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Address</b></td>
          <td bgcolor="#dddddd">1234 Somewhere Dr.<br>City ST, 12345</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Email</b></td>
          <td bgcolor="#dddddd">someone@email.com</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Gender</b></td>
          <td bgcolor="#dddddd">Female</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Ethnicity</b></td>
          <td bgcolor="#dddddd">Unknown</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Date of Birth</b></td>
          <td bgcolor="#dddddd">Jan 1st, 1901</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Class</b></td>
          <td bgcolor="#dddddd">Sophomore</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>Major</b></td>
          <td bgcolor="#dddddd">Biology</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>School</b></td>
          <td bgcolor="#dddddd">University of Somewhere</td>
        </tr>
<tr>
<td bgcolor="#dddddd"><b>GPA</b></td>
          <td bgcolor="#dddddd">0.00</td>
        </tr>
<tr>
<td bgcolor="#dddddd" valign="top"><b>Availability</b></td>
          <td bgcolor="#dddddd">
      <table border="0" cellspacing="0" cellpadding="0">
<tr>

1 Ответ

5 голосов
/ 14 мая 2011

Я предполагаю, что будет много интервалов "Профиль рекрута", за которыми следуют таблицы, в которых заключены все детали. Следующий метод берет всю вашу HTML-страницу, находит только эти промежутки, и для каждого из них он находит следующую таблицу, а затем находит нужные вам поля в любом месте ниже этой таблицы:

require 'nokogiri'

# Pass in or set the array of labels you want to use
# Returns an array of hashes mapping these labels to the values
def recruits_details(html,fields=%W[Name #{"EDU ID"} Phone Email Gender])
  doc = Nokogiri::HTML(html)
  recruit_labels = doc.xpath('//span[b[text()="Recruit Profile"]]')
  recruit_labels.map do |recruit_label|
    recruit_table = recruit_label.at_xpath('following-sibling::table')
    Hash[ fields.map do |field_label|
      label_td = recruit_table.at_xpath(".//td[b[text()='#{field_label}']]")
      [field_label, label_td.at_xpath('following-sibling::td/text()').text ]
    end ]
  end
end

require 'pp'
pp recruits_details(html_string)
#=> [{"Name"=>"Some Person",
#=>   "EDU ID"=>"A12345678",
#=>   "Phone"=>"123-456-7890",
#=>   "Email"=>"someone@email.com",
#=>   "Gender"=>"Female"}]

Выражение XPath вроде .//foo[bar[text()="jim"]] означает:

  • Найти элемент 'foo' в любом месте под текущим узлом
  • ... но только если он имеет дочерний элемент 'bar'
  • ... но только если этот элемент 'bar' имеет текст "jim" в качестве содержимого

Выражение XPath наподобие following-sibling::... означает Найти любые элементы, являющиеся братьями и сестрами после текущего узла, которые соответствуют выражению ...

Выражение XPath .../text() выбирает Текстовый узел ; метод text используется для извлечения значения (фактической строки) этого текстового узла.

Метод Nokogiri xpath возвращает массив всех элементов, соответствующих выражению, а метод at_xpath возвращает первый элемент, соответствующий выражению.

...