Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何使用Nokogiri解析普通HTML表?_Ruby_Xpath_Html Parsing_Nokogiri - Fatal编程技术网

Ruby 如何使用Nokogiri解析普通HTML表?

Ruby 如何使用Nokogiri解析普通HTML表?,ruby,xpath,html-parsing,nokogiri,Ruby,Xpath,Html Parsing,Nokogiri,我想用Nokogiri解析一个HTML页面。页面的一部分中有一个表未使用任何特定ID。是否可以提取以下内容: 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 cla

我想用Nokogiri解析一个HTML页面。页面的一部分中有一个表未使用任何特定ID。是否可以提取以下内容:

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>

今天昨天
QnTySizeLength长度尺寸QnTy
3.
455
34
3454
5656
3.
1.
1300
3664
3545
1000
10
10
100000
3444
3411
36223
15

作为快速而肮脏的第一步,我会:

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)
循环表中的行,拒绝标题:

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
为了帮助您可视化正在发生的事情,在“tr”循环的出口处,
today\u data
today\u data
数组是数组的数组,看起来像:

[["Today", 3, 455, 34], ["Today", 1, 1300, 3664], ["Today", 10, 100000, 3444]]
或者,我可以先抓取“tr”的内容,然后使用
scan
抓取数字,并将结果数组分为“今天”和“昨天”数组,而不是在“td”标记上循环并感应标记的类:

在现实世界的开发中,就像在工作中一样,我会用它来代替我第一次写的东西,因为它很简洁


请注意,我没有使用XPath。在Nokogiri中使用XPath并实现这一点非常可行,但为了简单起见,我更喜欢CSS访问器。XPath将允许访问单个“td”标记内容,但它也将开始看起来像行噪声,这是我们在编写代码时要避免的,因为它会影响维护。我也可以使用CSS向下搜索到正确的“td”标记,如
'tr td.r'
,但我认为这不会改进代码,这只是一种替代方法。

谢谢@the tin man。它工作正常,只是我不得不将doc.at更改为doc.css,因为我遇到了一些错误。我只有一些小问题,我会设法解决。我没有足够的声誉来投票,所以振作起来:)
at
可以同时使用CSS和XPath,但只返回第一次出现的节点,因此您可能有多个
table
标记
css
search
的别名,它返回一个节点集,也就是一个节点数组,因此您必须索引到结果中,或者对结果进行迭代
at_css
是特定于css的等价于
at
@JraNil的,另外,仅供参考,该代码适用于示例HTML,因此示例中一定缺少某些内容。如果您生成一个准确的样本,我们可以提供更好的答案。是的,原始网页似乎有一些问题。当我用openuri或wget调用它时,它没有响应。我正在尝试做一个代理,并使用Mechanize调用该页面。
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
[["Today", 3, 455, 34], ["Today", 1, 1300, 3664], ["Today", 10, 100000, 3444]]
  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] ]