Метод Нокогири CSS в 2D массив

Я пытаюсь создать простой веб-скребок, но у меня возникли некоторые проблемы.

Структура сайта выглядит следующим образом:

<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}

Это возвращает массив строк с тремя элементами (в этом примере). Но я пытаюсь получить двумерный массив, где, например:

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 ответа

Решение

Вы были близки

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

Для каждого td.gametimeиди к родителю и хватай все a теги затем сопоставить их с их текстом. Это даст вам массив из трех значений для каждой игры и массив массивов для страницы.

Я не думаю text собирается сделать массив для вас. Я думаю, что вам нужно будет гнездиться map заявления:

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

Я бы сделал это так:

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"

Нет необходимости захватывать внутренние теги внутри <td> теги для этого HTML. Иногда есть дополнительный текст, который нужно игнорировать, что делает его необходимым, но, поскольку он прост, код может быть простым. 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"
Другие вопросы по тегам