Как мне разобрать таблицу на значимые куски? - PullRequest
0 голосов
/ 12 февраля 2012

Мне нужно извлечь таблицу данных по коллекции страниц. Я уже могу просматривать страницы просто отлично.

Как извлечь данные таблицы? Я использую Ruby и Nokogiri, но я предполагаю, что это довольно общая проблема.

Я подчеркнул нужные точки данных в каждой строке в на следующем изображении .

Пример HTML-кода: http://pastebin.com/YYFPbFLC

Как бы я мог разобрать эту таблицу в хеш через Нокогири в значимые куски?

xpath таблицы:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table

Таблица содержит переменное количество строк данных и форматирование строк. Я только хочу собрать строки со значимыми данными, но я не вижу возможности различить это с помощью XPath, за исключением того, что во втором столбце будет надежно указано «keyword». Каждая из этих строк имеет XPath:

1st meaningful row is: /html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]
...
Last meaningful row: /html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[N]

Первый значимый столбец, который должен соответствовать текстовому содержанию в «ключевом слове»:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td[2]

Последний столбец этой первой строки данных будет:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td[6]

Каждая строка является записью и имеет метку времени с этим столбцом / td - время в метке времени; Год, месяц и день находятся в своих переменных и могут быть добавлены для полной отметки времени:

/html/body/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr/td[2]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td[5]

1 Ответ

6 голосов
/ 13 февраля 2012

Первое правило XPath: никогда не используйте автоматически сгенерированный XPath из Firebug или другого инструмента браузера.Это создает хрупкий XPath, который рассматривает все элементы страницы как одинаково важные и необходимые, даже те части, которые вам не нужны.Например, если в верхней части страницы появилось уведомление, и оно оказалось в таблице, оно может сойти с вашего разбора.

Вместо этого подумайте, как человек может его идентифицировать.В этом случае вы хотите «первую таблицу под заголовком со словом« сегодня »в ней».Вот XPath для этого:

//table[preceding-sibling::h2[contains(text(), "today")]][1]

Это говорит о том, что возьмите таблицы, которые имеют предшествующие h2 (другими словами, следующие за h2), где h2 содержит слово «сегодня».».Затем возьмите первую такую ​​таблицу.

Затем вам нужно определить интересующие вас строки. Обратите внимание, что некоторые строки являются просто разделителями, содержащими один td, поэтому вы хотите убедиться, что разбираете только строкикоторые имеют несколько тегов td.В XPath это:

//tr[td[2]]

Тогда вы просто захватываете содержимое всех столбцов.В первом вы можете удалить все до слов «величины», чтобы получить только значение.Собираем все вместе:

doc = Nokogiri::HTML.parse(html)

events = []

doc.xpath('//table[preceding-sibling::h2[contains(text(), "today")]][1]//tr[td[2]]').each do |row|
  cols = row.search('td/text()').map(&:to_s)
  events << {
    :magnitude   => cols[0].gsub(/^.*of magnitude /,''),
    :temp_area   => cols[1],
    :time_start  => cols[2],
    :time_middle => cols[3],
    :time_end    => cols[4]
  }
end

Вывод:

[
 {:magnitude=>"F1.7",
  :temp_area=>"0",
  :time_start=>"01:11:00",
  :time_middle=>"01:24:00",
  :time_end=>"01:32:00"},
 {:magnitude=>"F3.1",
  :temp_area=>"0",
  :time_start=>"04:01:00",
  :time_middle=>"04:10:00",
  :time_end=>"04:26:00"},
 {:magnitude=>"F3.5",
  :temp_area=>"134F55",
  :time_start=>"06:24:00",
  :time_middle=>"06:42:00",
  :time_end=>"06:53:00"},
 {:magnitude=>"F1.4",
  :temp_area=>"0",
  :time_start=>"11:58:00",
  :time_middle=>"12:06:00",
  :time_end=>"12:16:00"},
 {:magnitude=>"F1.0",
  :temp_area=>"0",
  :time_start=>"13:02:00",
  :time_middle=>"13:05:00",
  :time_end=>"13:09:00"},
 {:magnitude=>"D53.7",
  :temp_area=>"134F55",
  :time_start=>"17:37:00",
  :time_middle=>"18:37:00",
  :time_end=>"18:56:00"}
]
...