Как искать "текст", а затем пересекать DOM из найденного node?

У меня есть веб-страница, с которой мне нужно очистить некоторые данные. Проблема в том, что каждая страница может иметь или не иметь конкретных данных, или она может иметь дополнительные данные выше или ниже этого в DOM, и нет идентификаторов CSS, о которых можно говорить.

Обычно я мог использовать либо идентификаторы CSS, либо XPath для доступа к node, который я ищу. У меня нет такого варианта в этом случае. То, что я пытаюсь сделать, это поиск текста "метки", а затем захват данных в следующем <TD> node:

<tr> 
    <td><b>Name:</b></td> 
    <td>Joe Smith <small><a href="/Joe"><img src="/joe.png"></a></small></td> 
</tr>

В приведенном выше HTML я бы поискал:

doc.search("[text()*='Name:']")

чтобы получить node непосредственно перед данными, которые мне нужны, но я не уверен, как перемещаться оттуда.

Ответы

Ответ 1

next_element - это, вероятно, тот метод, который вы ищете.

require 'nokogiri'

data = File.read "html.htm"

doc  = Nokogiri::HTML data

els  = doc.search "[text()*='Name:']"
el   = els.first

puts "Found element:"
puts el
puts

puts "Parent element:"
puts el.parent
puts

puts "Parent next_element():"
puts el.parent.next_element

# Output:
#
# Found element:
# <b>Name:</b>
#
# Parent element:
# <td> 
#     <b>Name:</b>
# </td>
#
# Parent next_element():
# <td>Joe Smith <small><a href="/Joe"><img src="/joe.png"></a></small>
# </td>

Обратите внимание, что поскольку текст находится внутри тегов <b></b>, вы должны подняться на уровень (до найденного элемента parent <td>), прежде чем сможете перейти к следующему брату. Если структура HTML нестабильна, вам нужно будет найти первого родителя, который является <td>, и оттуда оттуда.

Ответ 2

require 'nokogiri'

html = '
<html>
  <body>
    <p>foo</p>
    this text
    <p>bar</p>
  </body>
</html>
'

doc = Nokogiri::HTML(html)
doc.at('p:contains("foo")').next_sibling.text.strip
=> "this text"

Ответ 3

Вы можете выполнить весь поиск в одном выражении с помощью синтаксиса xpath parent/following_sibling:

>> require 'nokogiri' 
=> true   
>> html = <<HTML
<tr> 
    <td><b>Name:</b></td> 
    <td>Joe Smith <small><a href="/Joe"><img src="/joe.png"></a></small></td> 
</tr>
HTML
>> doc = Nokogiri::HTML(html)

>> doc.at_xpath("//*[text()='Name:']/../following-sibling::*").to_s
=> "<td>Joe Smith <small><a href=\"/Joe\"><img src=\"/joe.png\"></a></small>\n</td>"