Используйте Nokogiri, чтобы извлечь первые 2 ячейки таблицы во всех строках таблицы - PullRequest
1 голос
/ 13 февраля 2012

У меня есть таблица, и я хочу использовать Nokogiri для извлечения содержимого первых двух ячеек в каждой строке таблицы. В настоящее время я сталкиваюсь с некоторыми трудностями и хочу получить помощь от вас. Это то, что я получаю сейчас. Кто-нибудь может мне помочь? Спасибо.

irb(main):001:0> require 'nokogiri'
=> true
irb(main):002:0>
irb(main):003:0* @doc = Nokogiri::HTML::DocumentFragment.parse <<-EOHTML
irb(main):004:0" <body>
irb(main):005:0" <div class="c">
irb(main):006:0" <table>
irb(main):007:0"     <tr>
irb(main):008:0"         <td>test</td><td>test</td><td>test</td><td>test</td>
irb(main):009:0"     </tr>
irb(main):010:0"     <tr class="even">
irb(main):011:0"         <td>test</td><td>test</td><td>test</td><td>test</td>
irb(main):012:0"     </tr>
irb(main):013:0"     <tr>
irb(main):014:0"         <td>test</td><td>test</td><td>test</td><td>test</td>
irb(main):015:0"     </tr>
irb(main):016:0"     <tr class="even">
irb(main):017:0"         <td>test</td><td>test</td><td>test</td><td>test</td>
irb(main):018:0"     </tr>
irb(main):019:0" </table>
irb(main):020:0" </div>
irb(main):021:0" </body>
irb(main):022:0" EOHTML
irb(main):026:0> @doc.css("div.c > table").search("table/tr/td")
=> ...
irb(main):026:0> @doc.css("div.c > table").search("table/tr/td[position()>2]")
Nokogiri::CSS::SyntaxError: unexpected '>' after '#<Nokogiri::CSS::Node:0x2b7bc20>'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/css/parser_extras.rb:87:in `on_error'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/1.9.1/racc/parser.rb:99:in `_racc_do_parse_c'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/1.9.1/racc/parser.rb:99:in `do_parse'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/css/parser_extras.rb:62:in `parse'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/css/parser_extras.rb:79:in `xpath_for'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/css.rb:23:in `xpath_for'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:111:in `block (2 levels) in
css'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:109:in `map'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:109:in `block in css'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:239:in `block in each'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:238:in `upto'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:238:in `each'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:105:in `css'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:83:in `block in search'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:80:in `each'
        from C:/RailsInstaller/Ruby1.9.2/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.0-x86-mingw32/lib/nokogiri/xml/node_set.rb:80:in `search'
        from (irb):27
        from C:/RailsInstaller/Ruby1.9.2/bin/irb:12:in `<main>'irb(main):028:0>

Ответы [ 3 ]

3 голосов
/ 14 февраля 2012

Поскольку вы сказали в комментарии, что хотите сохранить логические отношения ячеек в одной строке:

@doc.css('div.c > table > tr').each do |tr|
  td1, td2 = tr.xpath('./td') # Find only direct child items
  # td1 is the first <td>, td2 the second
end

Если вы хотите эффективно извлечь весь текст сразу:

data = @doc.css('tr').map do |row|
  # Find the text for all td, get the first two, then join with ' - '
  row.xpath('./td').map(&:text)[0,2].join(' - ')
end

puts data
#=> a1 - b1
#=> a2 - b2
#=> a3 - b3
#=> a4 - b4

Приведенный выше вывод получен из немного более интересных тестовых данных, чем все "тесты".

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

Используйте запрос XPath:

@doc.xpath('//table/tr/td[1] | //table/tr/td[2]')

Это вернет первый и второй узлы td в узле tr, в котором узел table является родительским.

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

Я бы предложил использовать парсер SAX

class ShowtimeDaily < Nokogiri::XML::SAX::Document
  attr_reader :td_count
  def start_element name, attrs =[]
  case name
  when 'tr'
    @td_count = 0
  when 'td'
    @td_count +=1
  end

 def characters string
   # string containts the content you'd be requiring
   puts "content of row number #{@td_count}: #{string}" if @td_count < 3
 end

В коде, который я написал, скорее всего, будут ошибки, поскольку я его не проверял. Надеюсь, это поможет решить вашу проблему.

...