web-dev-qa-db-fra.com

Comment puis-je convertir un tableau HTML au format CSV?

Comment convertir le contenu d'un tableau HTML (<table>) au format CSV? Existe-t-il une bibliothèque ou un programme linux qui fait cela? Cette procédure est similaire à la copie de tableaux dans Internet Explorer et à leur collage dans Excel.

40
asdfasdf

Cette méthode n'est pas vraiment une bibliothèque OR un programme, mais vous pouvez utiliser des conversions ad hoc. 

  • mettre le code HTML d'une table dans un fichier text appelé quelque chose.xls
  • ouvrez-le avec un tableur
  • enregistrez-le au format CSV.

Je sais que cela fonctionne avec Excel et je pense l'avoir fait avec le tableur OpenOffice.

Mais vous préféreriez probablement un script Perl ou Ruby ...

40
pavium

Désolé de ressusciter un ancien fil de discussion, mais je voulais récemment le faire, mais je voulais un script bash 100% portable pour le faire. Alors, voici ma solution en utilisant seulement grep et sed.

La base ci-dessous a été détruite très rapidement et pourrait donc être rendue beaucoup plus élégante, mais je commence tout juste à utiliser sed/awk, etc.

curl "http://www.webpagewithtableinit.com/" 2>/dev/null | grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH' | sed 's/^[\ \t]*//g' | tr -d '\n' | sed 's/<\/TR[^>]*>/\n/Ig'  | sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' | sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' | sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig'

Comme vous pouvez le constater, la source de la page utilise curl, mais vous pouvez tout aussi facilement insérer la source de la table à partir d’autres sources.

Voici l'explication:

Obtenez le contenu de l'URL à l'aide de cURL, dump stderr to null (aucun indicateur de progression)

curl "http://www.webpagewithtableinit.com/" 2>/dev/null 

.

Je ne veux que des éléments de table (ne renvoie que des lignes avec les balises TABLE, TR, TH, TD)

| grep -i -e '</\?TABLE\|</\?TD\|</\?TR\|</\?TH'

.

Supprimez les espaces au début de la ligne.

| sed 's/^[\ \t]*//g' 

.

Supprimer les nouvelles lignes

| tr -d '\n\r' 

.

Remplacer </TR> par newline

| sed 's/<\/TR[^>]*>/\n/Ig'  

.

Supprimer les balises TABLE et TR

| sed 's/<\/\?\(TABLE\|TR\)[^>]*>//Ig' 

.

Supprimer ^<TD>, ^<TH>, </TD>$, </TH>$

| sed 's/^<T[DH][^>]*>\|<\/\?T[DH][^>]*>$//Ig' 

.

Remplacer </TD><TD> par une virgule

| sed 's/<\/T[DH][^>]*><T[DH][^>]*>/,/Ig'

.

Notez que si l'une des cellules du tableau contient des virgules, vous devrez peut-être les échapper en premier ou utiliser un délimiteur différent.

J'espère que cela aide quelqu'un!

19
DRendar

Voici un script Ruby qui utilise nokogiri - http://nokogiri.rubyforge.org/nokogiri/

require 'nokogiri'

doc = Nokogiri::HTML(table_string)

doc.xpath('//table//tr').each do |row|
  row.xpath('td').each do |cell|
    print '"', cell.text.gsub("\n", ' ').gsub('"', '\"').gsub(/(\s){2,}/m, '\1'), "\", "
  end
  print "\n"
end

Travaillé pour mon cas de test de base.

16
audiodude

Voici un court programme Python que j'ai écrit pour effectuer cette tâche. Cela a été écrit en quelques minutes, donc ça peut probablement être amélioré. Vous ne savez pas comment il gérera les tables imbriquées (probablement les mauvaises choses) ou plusieurs tables (elles n'apparaîtront probablement que l'une après l'autre) Il ne gère pas colspan ou rowspan. Enjoy.

from HTMLParser import HTMLParser
import sys
import re


class HTMLTableParser(HTMLParser):
    def __init__(self, row_delim="\n", cell_delim="\t"):
        HTMLParser.__init__(self)
        self.despace_re = re.compile(r'\s+')
        self.data_interrupt = False
        self.first_row = True
        self.first_cell = True
        self.in_cell = False
        self.row_delim = row_delim
        self.cell_delim = cell_delim

    def handle_starttag(self, tag, attrs):
        self.data_interrupt = True
        if tag == "table":
            self.first_row = True
            self.first_cell = True
        Elif tag == "tr":
            if not self.first_row:
                sys.stdout.write(self.row_delim)
            self.first_row = False
            self.first_cell = True
            self.data_interrupt = False
        Elif tag == "td" or tag == "th":
            if not self.first_cell:
                sys.stdout.write(self.cell_delim)
            self.first_cell = False
            self.data_interrupt = False
            self.in_cell = True

    def handle_endtag(self, tag):
        self.data_interrupt = True
        if tag == "td" or tag == "th":
            self.in_cell = False

    def handle_data(self, data):
        if self.in_cell:
            #if self.data_interrupt:
            #   sys.stdout.write(" ")
            sys.stdout.write(self.despace_re.sub(' ', data).strip())
            self.data_interrupt = False


parser = HTMLTableParser() 
parser.feed(sys.stdin.read()) 
8
Yuval

Je ne sais pas s'il existe une bibliothèque préconfigurée pour cela, mais si vous êtes prêt à vous salir les mains avec un peu de Perl, vous pourriez probablement faire quelque chose avec Text::CSV et HTML::Parser .

6
Chris Simmons

Avec Perl, vous pouvez utiliser le module HTML::TableExtract pour extraire les données de la table puis utiliser Text::CSV_XS pour créer un fichier CSV ou Spreadsheet::WriteExcel pour créer un fichier Excel.

5
jmcnamara

En supposant que vous ayez conçu une page html contenant un tableau, je recommanderais cette solution. Travaillé comme un charme pour moi.

$(document).ready(function() {
$("#btnExport").click(function(e) {
    //getting values of current time for generating the file name
    var dt = new Date();
    var day = dt.getDate();
    var month = dt.getMonth() + 1;
    var year = dt.getFullYear();
    var hour = dt.getHours();
    var mins = dt.getMinutes();
    var postfix = day + "." + month + "." + year + "_" + hour + "." + mins;
    //creating a temporary HTML link element (they support setting file names)
    var a = document.createElement('a');
    //getting data from our div that contains the HTML table
    var data_type = 'data:application/vnd.ms-Excel';
    var table_div = document.getElementById('dvData');
    var table_html = table_div.outerHTML.replace(/ /g, '%20');
    a.href = data_type + ', ' + table_html;
    //setting the file name
    a.download = 'exported_table_' + postfix + '.xls';
    //triggering the function
    a.click();
    //just in case, prevent default behaviour
    e.preventDefault();
});
});

Courtesy: http://www.kubilayerdogan.net/?p=218

Vous pouvez modifier le format de fichier au format .csv ici a.download = 'table_exportée_' + suffixe + '.csv';

5
Bhagirath

Juste pour ajouter à ces réponses (comme je viens de tenter une chose similaire) - si feuilles de calcul Google est votre programme de feuille de calcul de choix. Faites simplement ces deux choses.

1. Supprimez tout le contenu de votre fichier html autour du Balises d'ouverture/fermeture de table et réenregistrez-le sous un autre fichier html.

2. Importez ce fichier html directement dans des feuilles de calcul Google pour une superbe importation de vos informations (Astuce: si vous avez utilisé des styles en ligne dans votre tableau, ils seront également importés!)

M'a fait gagner beaucoup de temps et comprendre différentes conversions. 

4
toms.work

Voici une solution simple sans aucune bibliothèque externe:

http://www.codexworld.com/export-html-table-data-to-csv-using-javascript/

Cela fonctionne pour moi sans aucun problème

3
Met Kiani

Basé sur la réponse d'audiodude , mais simplifiée en utilisant la bibliothèque CSV intégrée

require 'nokogiri'
require 'csv'

doc = Nokogiri::HTML(table_string)
csv = CSV.open("output.csv", 'w')

doc.xpath('//table//tr').each do |row|
    tarray = [] #temporary array
    row.xpath('td').each do |cell|
        tarray << cell.text #Build array of that row of data.
    end
    csv << tarray #Write that row out to csv file
end

csv.close

Je me suis demandé s'il y avait un moyen de prendre le Nokogiri NodeSet (row.xpath('td')) et de l'écrire sous forme de tableau dans le fichier CSV en une seule étape. Mais je ne pouvais le faire qu'en parcourant chaque cellule et en construisant un tableau temporaire du contenu de chaque cellule.

3
atomicules

Voici un exemple utilisant pQuery et Spreadsheet :: WriteExcel :

use strict;
use warnings;

use Spreadsheet::WriteExcel;
use pQuery;

my $workbook = Spreadsheet::WriteExcel->new( 'data.xls' );
my $sheet    = $workbook->add_worksheet;
my $row = 0;

pQuery( 'http://www.blahblah.site' )->find( 'tr' )->each( sub{
    my $col = 0;
    pQuery( $_ )->find( 'td' )->each( sub{
        $sheet->write( $row, $col++, $_->innerHTML );
    });
    $row++;
});

$workbook->close;

L'exemple extrait simplement toutes les balises tr trouvées dans un fichier Excel. Vous pouvez facilement l’adapter pour choisir table ou même déclencher un nouveau fichier Excel par balise table.

Autres points à considérer:

  • Vous pouvez choisir les balises td pour créer un ou plusieurs en-têtes Excel.
  • Et vous pourriez avoir des problèmes avec RowSpan et Colspan. 

Pour savoir si rowspan ou colspan est utilisé, vous pouvez:

pQuery( $data )->find( 'td' )->each( sub{ 
    my $number_of_cols_spanned = $_->getAttribute( 'colspan' );
});
2
draegtun
2
Gene T

OpenOffice.org peut afficher les tableaux HTML. Utilisez simplement la commande open du fichier HTML ou sélectionnez et copiez le tableau dans votre navigateur, puis Coller spécial dans OpenOffice.org. Il vous demandera le type de fichier, dont HTML. Sélectionnez ça et le tour est joué!

1
Happy Gilmore

C’est un très vieux sujet, mais il se peut que quelqu'un comme moi se heurte dessus . J'ai ajouté quelques ajouts pour que le script audiodude lise le fichier HTML à partir du fichier et l’ajoute au code un autre paramètre qui contrôle l’impression des lignes d’en-tête.

le script devrait être exécuté comme ça

Ruby <script_name> <file_name> [<print_headers>]

le code est:

require 'nokogiri'

print_header_lines = ARGV[1]

File.open(ARGV[0]) do |f|

  table_string=f
  doc = Nokogiri::HTML(table_string)

  doc.xpath('//table//tr').each do |row|
    if print_header_lines
      row.xpath('th').each do |cell|
        print '"', cell.text.gsub("\n", ' ').gsub('"', '\"').gsub(/(\s){2,}/m, '\1'), "\", "
      end
    end
    row.xpath('td').each do |cell|
      print '"', cell.text.gsub("\n", ' ').gsub('"', '\"').gsub(/(\s){2,}/m, '\1'), "\", "
    end
    print "\n"
  end
end
1
Tata

Ceci est basé sur la réponse des atomicules mais plus succincte et traite également les cellules th (en-tête) ainsi que les cellules td. J'ai également ajouté la méthode strip pour supprimer les espaces blancs supplémentaires.

CSV.open("output.csv", 'w') do |csv|
  doc.xpath('//table//tr').each do |row|
    csv << row.xpath('th|td').map {|cell| cell.text.strip}
  end
end

Envelopper le code dans le bloc CSV garantit que le fichier sera fermé correctement.


Si vous voulez juste le texte et n'avez pas besoin de l'écrire dans un fichier, vous pouvez utiliser ceci:

doc.xpath('//table//tr').inject('') do |result, row|
  result << row.xpath('th|td').map {|cell| cell.text.strip}.to_csv
end
0
Josh