【问题标题】:Scraping Table with Nokogiri and need JSON output使用 Nokogiri 抓取表并需要 JSON 输出
【发布时间】:2013-03-08 16:46:15
【问题描述】:

所以,我有一个多行多列的表格。

<table>
  <tr>
    <th>Employee Name</th>
    <th>Reg Hours</th>
    <th>OT Hours</th>
  </tr>
  <tr>
    <td>Employee 1</td>
    <td>10</td>
    <td>20</td>
  </tr>
  <tr>
    <td>Employee 2</td>
    <td>5</td>
    <td>10</td>
  </tr>
</table>

还有一张桌子:

<table>
  <tr>
    <th>Employee Name</th>
    <th>Revenue</th>
  </tr>
    <td>Employee 2</td>
    <td>$10</td>
  </tr>
  <tr>
    <td>Employee 1</td>
    <td>$50</td>
  </tr>
</table>

请注意,表之间的员工顺序可能是随机的。

如何使用 nokogiri 创建一个 json 文件,其中包含每个员工作为一个对象,以及他们的总工时和收入?

目前,我只能通过一些 xpath 获取单个表格单元格。例如:

puts page.xpath(".//*[@id='UC255_tblSummary']/tbody/tr[2]/td[1]/text()").inner_text

编辑:

使用页面对象 gem 和来自@Dave_McNulla 的链接,我尝试了这段代码只是为了看看我得到了什么:

class MyPage
  include PageObject

  table(:report, :id => 'UC255_tblSummary')

  def get_some_information
    report_element[1][2].text
  end
end

puts get_some_information

但是没有返回任何东西。

数据:https://gist.github.com/anonymous/d8cc0524160d7d03d37b

有一个小时表的副本。第一个很好。需要的另一个表是附件收入表。 (我还需要激活表,但我会尝试从合并小时和附件收入表的代码中合并它。

【问题讨论】:

  • 你能修改 HTML 以包含表格元素的类吗?具体来说, 标签可以有一个“employee”类,每个 标签可以有一个类(例如“name”、“revenue”等)。这将帮助您匹配员工姓名,然后在另一个 HTML 文档中找到它,然后从两者构建 JSON,或者在构建对象之前将它们合并在一起。
  • HTML 不是我的。获取 xpath 节点不是问题……我想我更倾向于 Ruby 部分。我不确定如何迭代行并合并两个表之间的数据。
  • 您是否有理由要使用 Nokogiri 而不是使用 Watir?
  • Cheezy/Jeff Morgan 在页面对象中有一种方法可以从表格中获取信息:cheezyworld.com/2012/05/23/a-better-shovel
  • @JustinKo,Watir 可以做我需要做的事情吗?我在文档中找不到任何内容。

标签: ruby screen-scraping nokogiri watir page-object-gem


【解决方案1】:

我认为一般的做法是:

  1. 为每个以员工为键的表创建一个哈希
  2. 将两个表的结果合并在一起
  3. 转换为 JSON

为每个以员工为键的表创建一个哈希

这部分你可以在 Watir 或 Nokogiri 中完成。仅当 Watir 由于大表而导致性能不佳时,才有意义使用 Nokogiri。

女仆:

#I assume you would have a better way to identify the tables than by index
hours_table = browser.table(:index, 0)
wage_table = browser.table(:index, 1)

#Turn the tables into a hash
employee_hours = {}
hours_table.trs.drop(1).each do |tr| 
    tds = tr.tds
    employee_hours[ tds[0].text ] = {"Reg Hours" => tds[1].text, "OT Hours" => tds[2].text}     
end
#=> {"Employee 1"=>{"Reg Hours"=>"10", "OT Hours"=>"20"}, "Employee 2"=>{"Reg Hours"=>"5", "OT Hours"=>"10"}}

employee_wage = {}
wage_table.trs.drop(1).each do |tr| 
    tds = tr.tds
    employee_wage[ tds[0].text ] = {"Revenue" => tds[1].text}   
end
#=> {"Employee 2"=>{"Revenue"=>"$10"}, "Employee 1"=>{"Revenue"=>"$50"}}

Nokogiri:

page = Nokogiri::HTML.parse(browser.html)

hours_table = page.search('table')[0]
wage_table = page.search('table')[1]

employee_hours = {}
hours_table.search('tr').drop(1).each do |tr| 
    tds = tr.search('td')
    employee_hours[ tds[0].text ] = {"Reg Hours" => tds[1].text, "OT Hours" => tds[2].text}     
end
#=> {"Employee 1"=>{"Reg Hours"=>"10", "OT Hours"=>"20"}, "Employee 2"=>{"Reg Hours"=>"5", "OT Hours"=>"10"}}

employee_wage = {}
wage_table.search('tr').drop(1).each do |tr| 
    tds = tr.search('td')
    employee_wage[ tds[0].text ] = {"Revenue" => tds[1].text}   
end
#=> {"Employee 2"=>{"Revenue"=>"$10"}, "Employee 1"=>{"Revenue"=>"$50"}}

将两个表的结果合并在一起

您希望将两个哈希值合并在一起,这样对于特定员工,哈希值将包括他们的工作时间和收入。

employee = employee_hours.merge(employee_wage){ |key, old, new| new.merge(old) }
#=> {"Employee 1"=>{"Revenue"=>"$50", "Reg Hours"=>"10", "OT Hours"=>"20"}, "Employee 2"=>{"Revenue"=>"$10", "Reg Hours"=>"5", "OT Hours"=>"10"}}

转换为 JSON

基于此previous question,您可以将哈希转换为 json。

require 'json'
employee.to_json

【讨论】:

  • 感谢您的回复。我进行了以下更改: hours_table = browser.tr(:xpath, '//*[@id="tblReportItems"]/tbody/tr[1]') 因为看起来表格 ID 现在已经消失了。不过,现在从 water-webdriver 获取“未定义的方法‘哈希’错误”。
  • hashes 是为表定义的,而不是 trs。换句话说,您需要确保hours_table 仍然是一个表。根据您建议的更改,您应该可以执行hours_table = browser.table(:id =&gt; 'tblReportItems')
  • 我明白了……但该表 ID 是用于一个包罗万象的表。我需要的表在该表中(没有 ID)。尝试您的 nokogiri 示例,我收到“文本”的未定义方法错误。
  • 您是否更改了hours_tablewage_table 以指向正确的表?这两种解决方案都被硬编码到页面上的第一个/第二个表中。您需要更新它们以处理您的特定表格(因为我不知道您页面的 html 是什么样的)。
  • 我做到了;我需要的桌子分别是第五和第六。不过,我仍然收到“文本”的“无方法”错误。
猜你喜欢
相关资源
最近更新 更多
热门标签