Como rápida y sucia primera pasada que haría:
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)
Uso de CSS para encontrar el inicio de la tabla, y definir algunos lugares para almacenar los datos que estamos capturando:
table = doc.at('div#__DailyStat__ table')
today_data = []
yesterday_data = []
bucle sobre las filas de la tabla, el rechazo de los encabezados:
table.search('tr').each do |tr|
next if (tr['class'] == 'blh')
arrays Inicializar para capturar los datos pertinentes de cada fila, empujar selectivamente los datos en la matriz apropiada:
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
Y salida de los datos:
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
sólo para ayudar a visualizar lo que está pasando, a la salida del circuito de "tr", el today_data
y yesterday_data
matrices son matrices de-matrices buscando como:
[["Today", 3, 455, 34], ["Today", 1, 1300, 3664], ["Today", 10, 100000, 3444]]
Como alternativa, en lugar de un bucle a través de los tags "TD" y la detección de la clase para la etiqueta, podría haber agarrado el contenido de la "tr" y luego se usa para agarrar scan
los números y en rodajas la matriz resultante en "hoy" y "arrays" de ayer:
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] ]
en el desarrollo del mundo real, como en el trabajo, que haría uso que en lugar de lo que primero escribió porque es sucinto.
Y tenga en cuenta que no utilicé XPath. Es muy factible en Nokogiri usar XPath y lograr esto, pero para simplificar prefiero los accesadores de CSS. XPath habría permitido acceder a contenidos individuales de etiquetas "td", pero también comenzaría a parecerse a ruido de línea, lo cual es algo que queremos evitar al escribir código, ya que afecta el mantenimiento. También podría haber usado CSS para obtener las etiquetas "td" correctas, como 'tr td.r'
, pero no creo que mejore el código, sino que sería una forma alternativa de hacerlo.
Gracias @ the-tin-man. Funcionó correctamente, solo tengo que cambiar doc.at a doc.css por algún error. Solo tengo un pequeño problema, que intentaré resolver. No tengo suficiente reputación para votar, así que anímate :) – JraNil
'at' funciona tanto con CSS como con XPath, pero solo devuelve la primera aparición del nodo, por lo que puedes tener varias etiquetas' table'. 'css' es un alias de' search' que devuelve un NodeSet, o una matriz de nodos, por lo que debe indexar los resultados o iterar sobre ellos. 'at_css' es el equivalente específico de CSS a' at'. –
@JraNil, También, como un FYI, el código funciona con su HTML de muestra, por lo que debe haber algo que falta en la muestra. Si genera una muestra precisa, podemos proporcionar mejores respuestas. –