roo - ¿Analizar archivos XLS y XLSX(MS Excel) con Ruby?
ruby excel (10)
Acabo de encontrar a roo , eso podría hacer el trabajo, funciona para mis requisitos, leyendo una hoja de cálculo básica.
¿Hay gemas capaces de analizar archivos XLS y XLSX? He encontrado Spreadsheet y ParseExcel, pero ambos no entienden el formato XLSX :( ¿Alguna idea?
Gracias.
Estoy usando Creek que usa nokogiri. Es rápido. Usé 8.3 segundos en una mesa 21x11250 xlsx en mi Macbook Air. Lo tengo para trabajar en ruby 1.9.3+. El formato de salida para cada fila es un hash de fila y nombre de columna para el contenido de la celda: {"A1" => "una celda", "B1" => "otra celda"} El hash no garantiza que las claves estarán en el orden original de la columna. https://github.com/pythonicrubyist/creek
dullard es otra muy buena que usa nokogiri. Es súper rápido Usé 6.7 segundos en una mesa 21x11250 xlsx en mi Macbook Air. Lo tengo para trabajar en ruby 2.0.0+. El formato de salida para cada fila es una matriz: ["una celda", "otra celda"] https://github.com/thirtyseven/dullard
simple_xlsx_reader que se ha mencionado es genial, un poco lento. Usé 91 segundos en una mesa 21x11250 xlsx en mi Macbook Air. Lo tengo para trabajar en ruby 1.9.3+. El formato de salida para cada fila es una matriz: ["una celda", "otra celda"] https://github.com/woahdae/simple_xlsx_reader
Otra interesante es oxcelix. Utiliza el analizador SAX de ox que supuestamente es más rápido que el analizador DOM y SAX de ambos nokogiri. Supuestamente produce una Matriz. No pude arreglarlo. Además, hubo algunos problemas de dependencia con rubyzip. No lo recomendaría
En conclusión, si usa una versión de rubí inferior a 2.0.0, use Creek. Si usa ruby 2.0.0+, use el término "aburrido" porque es más rápido y conserva el orden de columnas de la tabla.
He trabajado mucho con Spreadsheet y rubyXL en las últimas dos semanas y debo decir que ambas son excelentes herramientas. Sin embargo, un área que ambos sufren es la falta de ejemplos sobre cómo implementar realmente algo útil. Actualmente estoy construyendo un rastreador y usando rubyXL para analizar archivos xlsx y hojas de cálculo para todo lo que sea xls. Espero que el siguiente código pueda servir como un ejemplo útil y mostrar cuán efectivas pueden ser estas herramientas.
require ''find''
require ''rubyXL''
count = 0
Find.find(''/Users/Anconia/crawler/'') do |file| # begin iteration of each file of a specified directory
if file =~ //b.xlsx$/b/ # check if file is xlsx format
workbook = RubyXL::Parser.parse(file).worksheets # creates an object containing all worksheets of an excel workbook
workbook.each do |worksheet| # begin iteration over each worksheet
data = worksheet.extract_data.to_s # extract data of a given worksheet - must be converted to a string in order to match a regex
if data =~ /regex/
puts file
count += 1
end
end
end
end
puts "#{count} files were found"
require ''find''
require ''spreadsheet''
Spreadsheet.client_encoding = ''UTF-8''
count = 0
Find.find(''/Users/Anconia/crawler/'') do |file| # begin iteration of each file of a specified directory
if file =~ //b.xls$/b/ # check if a given file is xls format
workbook = Spreadsheet.open(file).worksheets # creates an object containing all worksheets of an excel workbook
workbook.each do |worksheet| # begin iteration over each worksheet
worksheet.each do |row| # begin iteration over each row of a worksheet
if row.to_s =~ /regex/ # rows must be converted to strings in order to match the regex
puts file
count += 1
end
end
end
end
end
puts "#{count} files were found"
La biblioteca RemoteTable utiliza roo internamente. Facilita la lectura de hojas de cálculo de diferentes formatos (XLS, XLSX, CSV, etc. posiblemente remotas, posiblemente almacenadas dentro de un zip, gz, etc.):
require ''remote_table''
r = RemoteTable.new ''http://www.fueleconomy.gov/FEG/epadata/02data.zip'', :filename => ''guide_jan28.xls''
r.each do |row|
puts row.inspect
end
Salida:
{"Class"=>"TWO SEATERS", "Manufacturer"=>"ACURA", "carline name"=>"NSX", "displ"=>"3.0", "cyl"=>"6.0", "trans"=>"Auto(S4)", "drv"=>"R", "bidx"=>"60.0", "cty"=>"17.0", "hwy"=>"24.0", "cmb"=>"20.0", "ucty"=>"19.1342", "uhwy"=>"30.2", "ucmb"=>"22.9121", "fl"=>"P", "G"=>"", "T"=>"", "S"=>"", "2pv"=>"", "2lv"=>"", "4pv"=>"", "4lv"=>"", "hpv"=>"", "hlv"=>"", "fcost"=>"1238.0", "eng dscr"=>"DOHC-VTEC", "trans dscr"=>"2MODE", "vpc"=>"4.0", "cls"=>"1.0"}
{"Class"=>"TWO SEATERS", "Manufacturer"=>"ACURA", "carline name"=>"NSX", "displ"=>"3.2", "cyl"=>"6.0", "trans"=>"Manual(M6)", "drv"=>"R", "bidx"=>"65.0", "cty"=>"17.0", "hwy"=>"24.0", "cmb"=>"19.0", "ucty"=>"18.7", "uhwy"=>"30.4", "ucmb"=>"22.6171", "fl"=>"P", "G"=>"", "T"=>"", "S"=>"", "2pv"=>"", "2lv"=>"", "4pv"=>"", "4lv"=>"", "hpv"=>"", "hlv"=>"", "fcost"=>"1302.0", "eng dscr"=>"DOHC-VTEC", "trans dscr"=>"", "vpc"=>"4.0", "cls"=>"1.0"}
{"Class"=>"TWO SEATERS", "Manufacturer"=>"ASTON MARTIN", "carline name"=>"ASTON MARTIN VANQUISH", "displ"=>"5.9", "cyl"=>"12.0", "trans"=>"Auto(S6)", "drv"=>"R", "bidx"=>"1.0", "cty"=>"12.0", "hwy"=>"19.0", "cmb"=>"14.0", "ucty"=>"13.55", "uhwy"=>"24.7", "ucmb"=>"17.015", "fl"=>"P", "G"=>"G", "T"=>"", "S"=>"", "2pv"=>"", "2lv"=>"", "4pv"=>"", "4lv"=>"", "hpv"=>"", "hlv"=>"", "fcost"=>"1651.0", "eng dscr"=>"GUZZLER", "trans dscr"=>"CLKUP", "vpc"=>"4.0", "cls"=>"1.0"}
La gema rubyXL analiza los archivos XLSX maravillosamente.
La gema roo funciona muy bien para Excel (.xls y .xlsx) y está siendo desarrollada activamente.
Estoy de acuerdo en que la sintaxis no es buena ni de color rubí. Pero eso se puede lograr fácilmente con algo como:
class Spreadsheet
def initialize(file_path)
@xls = Roo::Spreadsheet.open(file_path)
end
def each_sheet
@xls.sheets.each do |sheet|
@xls.default_sheet = sheet
yield sheet
end
end
def each_row
0.upto(@xls.last_row) do |index|
yield @xls.row(index)
end
end
def each_column
0.upto(@xls.last_column) do |index|
yield @xls.column(index)
end
end
end
La mayoría de los ejemplos en línea, incluido el sitio web del autor para la gema de hoja de cálculo, demuestran que se lee todo el contenido de un archivo de Excel en la memoria RAM. Eso está bien si tu hoja de cálculo es pequeña.
xls = Spreadsheet.open(file_path)
Para cualquier persona que trabaje con archivos muy grandes, una mejor manera es leer en secuencia el contenido del archivo. La gema de hoja de cálculo lo admite, aunque no está bien documentada en este momento (alrededor del 3/2015).
Spreadsheet.open(file_path).worksheets.first.rows do |row|
# do something with the array of CSV data
end
No pude encontrar un analizador xlsx satisfactorio. RubyXL no da fecha a la conversión de tipos, Roo intentó encasillar un número como una fecha, y ambos son un desastre tanto en la API como en el código.
Entonces, escribí rubygems.org/gems/simple_xlsx_reader . Sin embargo, tendrías que usar algo más para xls, así que tal vez no sea la respuesta completa que estás buscando.
Recientemente necesité analizar algunos archivos de Excel con Ruby. La abundancia de bibliotecas y opciones resultó ser confusa, así que escribí una publicación en el blog sobre eso.
Aquí hay una tabla de diferentes bibliotecas de Ruby y lo que admiten:
Si le importa el rendimiento, aquí es cómo se comparan las bibliotecas xlsx
:
Tengo un código de muestra para leer archivos xlsx con cada biblioteca compatible here
Estos son algunos ejemplos para leer archivos xlsx
con algunas bibliotecas diferentes:
rubyXL
require ''rubyXL''
workbook = RubyXL::Parser.parse ''./sample_excel_files/xlsx_500_rows.xlsx''
worksheets = workbook.worksheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.sheet_name}"
num_rows = 0
worksheet.each do |row|
row_cells = row.cells.map{ |cell| cell.value }
num_rows += 1
end
puts "Read #{num_rows} rows"
end
roo
require ''roo''
workbook = Roo::Spreadsheet.open ''./sample_excel_files/xlsx_500_rows.xlsx''
worksheets = workbook.sheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet}"
num_rows = 0
workbook.sheet(worksheet).each_row_streaming do |row|
row_cells = row.map { |cell| cell.value }
num_rows += 1
end
puts "Read #{num_rows} rows"
end
Arroyo
require ''creek''
workbook = Creek::Book.new ''./sample_excel_files/xlsx_500_rows.xlsx''
worksheets = workbook.sheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.name}"
num_rows = 0
worksheet.rows.each do |row|
row_cells = row.values
num_rows += 1
end
puts "Read #{num_rows} rows"
end
simple_xlsx_reader
require ''simple_xlsx_reader''
workbook = SimpleXlsxReader.open ''./sample_excel_files/xlsx_500000_rows.xlsx''
worksheets = workbook.sheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.name}"
num_rows = 0
worksheet.rows.each do |row|
row_cells = row
num_rows += 1
end
puts "Read #{num_rows} rows"
end
Aquí hay un ejemplo de xls
leer un archivo xls
heredado usando la biblioteca de spreadsheet
:
hoja de cálculo
require ''spreadsheet''
# Note: spreadsheet only supports .xls files (not .xlsx)
workbook = Spreadsheet.open ''./sample_excel_files/xls_500_rows.xls''
worksheets = workbook.worksheets
puts "Found #{worksheets.count} worksheets"
worksheets.each do |worksheet|
puts "Reading: #{worksheet.name}"
num_rows = 0
worksheet.rows.each do |row|
row_cells = row.to_a.map{ |v| v.methods.include?(:value) ? v.value : v }
num_rows += 1
end
puts "Read #{num_rows} rows"
end
Si busca bibliotecas más modernas, consulte la Hoja de cálculo: http://spreadsheet.rubyforge.org/GUIDE_txt.html . No puedo decir si es compatible con archivos XLSX, pero considerando que está desarrollado activamente, supongo que sí (no estoy en Windows ni en Office, así que no puedo probar).
En este punto, parece que roo es una buena opción nuevamente. Es compatible con XLSX, permite (algunas) iteraciones simplemente usando times
con acceso a la celda. Lo admito, aunque no es bonito.
Además, RubyXL ahora puede darle una especie de iteración usando su método extract_data
, que le proporciona una matriz de datos en 2d, que se puede repetir fácilmente.
Alternativamente, si está tratando de trabajar con archivos XLSX en Windows, puede usar la biblioteca Win32OLE de Ruby que le permite interactuar con objetos OLE, como los proporcionados por Word y Excel. Sin embargo , como @PanagiotisKanavos se menciona en los comentarios, esto tiene algunos inconvenientes principales:
- Excel debe estar instalado
- Se inicia una nueva instancia de Excel para cada documento
- La memoria y el consumo de otros recursos es mucho más de lo necesario para una simple manipulación de documentos XLSX.
Pero si elige usarlo, puede optar por no mostrar Excel, cargar su archivo XLSX y acceder a través de él. No estoy seguro de si es compatible con la iteración, sin embargo, no creo que sea demasiado difícil construir en torno a los métodos proporcionados, ya que es la API Microsoft OLE completa para Excel. Aquí está la documentación: http://support.microsoft.com/kb/222101 Aquí está la gema: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/win32ole/rdoc/WIN32OLE.html
De nuevo, las opciones no se ven mucho mejor, pero me temo que no hay mucho más. es difícil analizar un formato de archivo que es una caja negra. Y esos pocos que lograron romperlo no lo hicieron visiblemente. Google Docs es de código cerrado, y LibreOffice tiene miles de líneas de harry C ++.