Обход HTML без CSS-класса с использованием Nokogiri? - PullRequest
2 голосов
/ 31 января 2012

У меня есть следующий HTML:

<table width="100%" border="0" cellpadding="6" cellspacing="1">
  <tbody>
    <tr>
      <td bgcolor="#ffd204" width="40%" nowrap=""><b>Tracking Number:</b></td>
      <td bgcolor="#ffffff" width="60%" nowrap="">C123456789012345</td>
    </tr>
    <!-- ...there could be additional table rows here... -->
    <tr>
      <td bgcolor="#ffd204" width="40%" nowrap=""><b>Deliver To:</b></td>
      <td bgcolor="#ffffff" width="60%" nowrap="">ANYWHERE, NY</td>
    </tr>
  </tbody>
</table>

Скажем, например, мне нужно получить данные ANYWHERE, NY.Как бы я это сделал, используя Nokogiri?Или есть что-то лучше для обхода такого рода вещей, где нет селекторов CSS для поиска?

Ответы [ 2 ]

8 голосов
/ 31 января 2012

Поскольку у нас нет класса CSS, атрибута id или другой семантической разметки, мы вместо этого ищем что-то, что, вероятно, не изменится в этом документе, чтобы привязать наш поиск.В этом случае я подозреваю, что метка «Deliver To:» всегда будет стоять перед желаемым тд.Итак:

require 'nokogiri'

html = # Fetch either from http via open-uri's open() or from file via IO.read()
doc = Nokogiri.HTML(html) 
delivery = doc.at_xpath '//td[preceding-sibling::td[b="Deliver To:"]]/text()'    
p delivery.content
#=> "ANYWHERE, NY"

Это выражение XPath говорит:

  • // - на любом уровне,
  • td - найдите мне элемент с именем td
  • […] - но только если…
    • preceding-sibling:: - у него есть предшествующий брат
    • td - это элемент с именем td
    • […] - но только если…
      • b - у него есть дочерний элемент с именем b
      • ="Deliver To:" - текстовое содержимое которого равно этой строке
  • /text() - и затем найдите мне дочерний текстовый узел (узлы) этого td.

Поскольку мы использовали at_xpath вместо xpath, Nokogiri возвращает первый соответствующий узел, который он может найти - который в данном случае оказывается единственным дочерним текстовым узлом этого тд - вместо массива узлов.

В случае, если <td> может иметь разметку, такую ​​как <td…>ANYWHERE,<br>NY</td>, вы можете изменить выражение, чтобы пропустить завершающий /text() (так, чтобы вы выбрали только сам <td>), а затем использовать метод text дляпринести комвон там отображается текст.

0 голосов
/ 31 января 2012

Учитывая, что вы не возражаете против некоторой предварительной обработки, вы можете сделать:

lookup = {}
c = Nokogiri::HTML(open("http://..."))
c.search("tr").each do |tr|
  cells = tr.search("td")
  lookup[cells.first.text.gsub(':', '')] = cells.last.text
end

puts lookup["Tracking Number"]

Я не тестировал этот код, поэтому могут возникнуть некоторые синтаксические проблемы.

...