Как мне разобрать простую таблицу HTML с Nokogiri? - PullRequest
5 голосов
/ 04 июня 2011

Я хотел бы проанализировать HTML-страницу с Nokogiri. В части страницы есть таблица, которая не использует какой-либо конкретный идентификатор. Можно ли извлечь что-то вроде:

Today,3,455,34
Today,1,1300,3664
Today,10,100000,3444,
Yesterday,3454,5656,3
Yesterday,3545,1000,10
Yesterday,3411,36223,15

Из этого HTML:

<div id="__DailyStat__">
  <table>
    <tr class="blh"><th colspan="3">Today</th><th class="r" colspan="3">Yesterday</th></tr>
    <tr class="blh"><th>Qnty</th><th>Size</th><th>Length</th><th class="r">Length</th><th class="r">Size</th><th class="r">Qnty</th></tr>
    <tr class="blr">
      <td>3</td>
      <td>455</td>
      <td>34</td>
      <td class="r">3454</td>
      <td class="r">5656</td>
      <td class="r">3</td>
    </tr>

    <tr class="bla">
      <td>1</td>
      <td>1300</td>
      <td>3664</td>
      <td class="r">3545</td>
      <td class="r">1000</td>
      <td class="r">10</td>
    </tr>

    <tr class="blr">
      <td>10</td>
      <td>100000</td>
      <td>3444</td>
      <td class="r">3411</td>
      <td class="r">36223</td>
      <td class="r">15</td>
    </tr>
  </table>
</div>

1 Ответ

10 голосов
/ 04 июня 2011

В качестве быстрого и грязного первого прохода я бы сделал:

html = <<EOT
<div id="__DailyStat__">
  <table>
    <tr class="blh"><th colspan="3">Today</th><th class="r" colspan="3">Yesterday</th></tr>
    <tr class="blh"><th>Qnty</th><th>Size</th><th>Length</th><th class="r">Length</th><th class="r">Size</th><th class="r">Qnty</th></tr>
    <tr class="blr">
      <td>3</td>
      <td>455</td>
      <td>34</td>
      <td class="r">3454</td>
      <td class="r">5656</td>
      <td class="r">3</td>
    </tr>

    <tr class="bla">
      <td>1</td>
      <td>1300</td>
      <td>3664</td>
      <td class="r">3545</td>
      <td class="r">1000</td>
      <td class="r">10</td>
    </tr>

    <tr class="blr">
      <td>10</td>
      <td>100000</td>
      <td>3444</td>
      <td class="r">3411</td>
      <td class="r">36223</td>
      <td class="r">15</td>
    </tr>
  </table>
</div>
EOT

#    Today              Yesterday
#    Qnty Size   Length Length Size  Qnty
#    3    455    34     3454   5656  3
#    1    1300   3664   3545   1000  10
#    10   100000 3444   3411   36223 15


require 'nokogiri'

doc = Nokogiri::HTML(html)

Используйте CSS, чтобы найти начало таблицы и определить места для хранения данных, которые мы собираем:

table = doc.at('div#__DailyStat__ table')

today_data     = []
yesterday_data = []

Зацикливание строк в таблице, отклоняя заголовки:

table.search('tr').each do |tr|

  next if (tr['class'] == 'blh')

Инициализируйте массивы для захвата соответствующих данных из каждой строки, выборочно помещая данные в соответствующий массив:

  today_td_data     = [ 'Today'     ]
  yesterday_td_data = [ 'Yesterday' ]

  tr.search('td').each do |td|
    if (td['class'] == 'r')
      yesterday_td_data << td.text.to_i
    else
      today_td_data << td.text.to_i
    end
  end

  today_data     << today_td_data
  yesterday_data << yesterday_td_data

end

И вывод данных:

puts today_data.map{ |a| a.join(',') }
puts yesterday_data.map{ |a| a.join(',') }

> Today,3,455,34
> Today,1,1300,3664
> Today,10,100000,3444
> Yesterday,3454,5656,3
> Yesterday,3545,1000,10
> Yesterday,3411,36223,15

Просто чтобы помочь вам визуализировать происходящее, на выходе из цикла "tr" массивы today_data и yesterday_data являются массивами.массив-массив выглядит следующим образом:

[["Today", 3, 455, 34], ["Today", 1, 1300, 3664], ["Today", 10, 100000, 3444]]

В качестве альтернативы, вместо циклического перемещения по тегам "td" и определения класса тега, я мог бы получить содержимое "tr" и затем использовать scan чтобы взять числа и нарезать результирующий массив на массивы «сегодня» и «вчера»:

  tr_data = tr.text.scan(/\d+/).map{ |i| i.to_i }

  today_td_data     = [ 'Today',     *tr_data[0, 3] ]
  yesterday_td_data = [ 'Yesterday', *tr_data[3, 3] ]

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

И обратите внимание, что я не использовал XPATH.В Nokogiri очень выполнимо использовать XPath и выполнить это, но для простоты я предпочитаю CSS-аксессоры.XPath позволил бы получить доступ к содержимому отдельного тега «td», но он также начал бы выглядеть как строковый шум, чего мы хотим избежать при написании кода, потому что это влияет на обслуживание.Я мог бы также использовать CSS, чтобы развернуть правильные теги «td», такие как 'tr td.r', но я не думаю, что это улучшит код, это будет просто альтернативный способ сделать это.

...