Nokogiri CSS方法到2D数组

时间:2015-01-08 23:17:50

标签: ruby nokogiri

我正在尝试创建一个简单的网络抓取工具,但我遇到了一些麻烦。

网站的结构如下:

<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-01-18">Sun 01-18-15 09:10 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208362">CYCLONES</a></td>
    <td><a href="/facilities/22/teams/210190">TIGERS</a></td>
</tr>
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-01-25">Sun 01-25-15 06:40 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208345">LIONS</a></td>
    <td><a href="/facilities/22/teams/208362">CYCLONES</a></td>
</tr>
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-02-01">Sun 02-01-15 12:50 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208362">CYCLONES</a></td>
    <td><a href="/facilities/22/teams/210041">CLAY</a></td>
</tr>

我现在拥有的是:

games = page.css("td[class='gametime']").map{|game| game.parent.css("a").text}

这将返回一个包含三个元素的字符串数组(在本例中)。但我试图获得的是2D数组,例如:

games[0][0] #=> Sun 01-18-15 09:10 PM
games[0][1] #=> CYCLONES
games[0][2] #=> TIGERS

我不想要这个(我现在得到的):

games[0] #=> Sun 01-18-15 09:10 PMCYCLONESTIGERS

实现这一目标的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

你很亲密:

games = page.css("td.gametime").map { |i| i.parent.css("a").map { |j| j.text } }

对于每个td.gametime,转到其父级并抓取所有a标记,然后将其映射到其文本。这将为每个游戏提供三个值的数组,以及页面的数组数组。

答案 1 :(得分:0)

我认为text不会为你制作数组。我认为你需要嵌套map语句:

games = page.css("td[class='gametime']").map{|game| game.parent.css("a").map(&:text)}

答案 2 :(得分:0)

我会这样做:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-01-18">Sun 01-18-15 09:10 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208362">CYCLONES</a></td>
    <td><a href="/facilities/22/teams/210190">TIGERS</a></td>
</tr>
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-01-25">Sun 01-25-15 06:40 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208345">LIONS</a></td>
    <td><a href="/facilities/22/teams/208362">CYCLONES</a></td>
</tr>
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-02-01">Sun 02-01-15 12:50 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208362">CYCLONES</a></td>
    <td><a href="/facilities/22/teams/210041">CLAY</a></td>
</tr>
EOT

以下是代码:

games = doc.search('tr').map{ |tr| tr.search('td').map(&:text) }
# => [["Sun 01-18-15 09:10 PM", "CYCLONES", "TIGERS"],
#     ["Sun 01-25-15 06:40 PM", "LIONS", "CYCLONES"],
#     ["Sun 02-01-15 12:50 PM", "CYCLONES", "CLAY"]]
games[0][0] # => "Sun 01-18-15 09:10 PM"
games[0][1] # => "CYCLONES"
games[0][2] # => "TIGERS"

没有必要为此HTML抓取<td>标记内的内部标记。有时需要忽略其他文本,这会使其成为必要,但由于它很简单,因此代码可以很简单。 text节点的<td>将返回嵌入其中的文本节点。

我严重怀疑他们所服务的HTML是如此简单,没有更多细节,我无法给出更准确的答案。 (理所当然/有益于提供足够详细和准确的输入。)但一般的想法是找到包含所需行的表,然后向下钻取:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<table class="foo">
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-01-18">Sun 01-18-15 09:10 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208362">CYCLONES</a></td>
    <td><a href="/facilities/22/teams/210190">TIGERS</a></td>
</tr>
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-01-25">Sun 01-25-15 06:40 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208345">LIONS</a></td>
    <td><a href="/facilities/22/teams/208362">CYCLONES</a></td>
</tr>
<tr>
    <td class="gametime"><a href="/facilities/22/games?exact_date=15-02-01">Sun 02-01-15 12:50 PM</a></td>
    <td class="gamehome"><a href="/facilities/22/teams/208362">CYCLONES</a></td>
    <td><a href="/facilities/22/teams/210041">CLAY</a></td>
</tr>
</table>
<table class="bar">
</table>
EOT

修改后的代码:

games = doc.search('table.foo tr').map{ |tr| tr.search('td').map(&:text) }
# => [["Sun 01-18-15 09:10 PM", "CYCLONES", "TIGERS"],
#     ["Sun 01-25-15 06:40 PM", "LIONS", "CYCLONES"],
#     ["Sun 02-01-15 12:50 PM", "CYCLONES", "CLAY"]]
games[0][0] # => "Sun 01-18-15 09:10 PM"
games[0][1] # => "CYCLONES"
games[0][2] # => "TIGERS"