Я предполагаю, что будет много интервалов "Профиль рекрута", за которыми следуют таблицы, в которых заключены все детали. Следующий метод берет всю вашу 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
возвращает первый элемент, соответствующий выражению.