Подтвердить что ты не робот

Как преобразовать таблицу HTML в CSV?

Как преобразовать содержимое таблицы HTML (<table>) в формат CSV? Есть ли библиотека или программа linux, которая делает это? Это похоже на таблицы копирования в Internet Explorer и вставка их в Excel.

4b9b3361

Ответ 1

Этот метод на самом деле не является библиотекой или программой, но для ad hoc-конверсий вы можете

  • поместите HTML для таблицы в текстовый файл something.xls
  • откройте его с помощью таблицы.
  • сохранить его как CSV.

Я знаю, что это работает с Excel, и я считаю, что сделал это с помощью электронной таблицы OpenOffice.

Но вы, вероятно, предпочли бы Perl или Ruby script...

Ответ 2

Извините за возрождение древней темы, но я недавно хотел сделать это, но я хотел использовать 100% портативный bash script. Итак, здесь мое решение использует только grep и sed.

Ниже было сделано очень быстро, и поэтому его можно было сделать намного элегантнее, но я просто начал работать с sed/awk и т.д.

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'

Как вы можете видеть, у меня есть источник страницы, использующий завиток, но вы можете так же легко загружать в источник таблицы из другого места.

Вот объяснение:

Получить содержимое URL-адреса с помощью cURL, dump stderr до нуля (без индикатора выполнения)

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

.

Мне нужны только элементы таблицы (возвращают только строки с тегами TABLE, TR, TH, TD)

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

.

Удалите пробел в начале строки.

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

.

Удалить символы новой строки

| tr -d '\n\r' 

.

Замените </TR> на новую строку

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

.

Удалить теги TABLE и TR

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

.

Удалите ^<TD>, ^<TH>, </TD>$, </TH>$

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

.

Замените </TD><TD> запятой

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

.

Обратите внимание, что если какая-либо из ячеек таблицы содержит запятые, вам может потребоваться сначала их избежать или использовать другой разделитель.

Надеюсь, это поможет кому-то!

Ответ 3

Здесь ruby ​​ script, который использует 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

Работала для моего основного теста.

Ответ 4

Вот короткая программа Python, которую я написал для выполнения этой задачи. Это было написано через пару минут, поэтому, возможно, это будет лучше. Не уверен, как он будет обрабатывать вложенные таблицы (возможно, это будет плохой материал) или несколько таблиц (вероятно, они просто появятся один за другим). Он не обрабатывает colspan или rowspan. Наслаждайтесь.

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()) 

Ответ 5

Я не уверен, есть ли для этого предварительно подготовленная библиотека, но если вы хотите, чтобы ваши руки были грязными с небольшим Perl, вы могли бы что-то сделать с Text::CSV и HTML::Parser.

Ответ 6

С помощью Perl вы можете использовать модуль HTML::TableExtract для извлечения данных из таблицы, а затем используйте Text::CSV_XS для создания файла CSV или Spreadsheet::WriteExcel для создания файла Excel.

Ответ 7

Предполагая, что u've спроектировал html-страницу, содержащую таблицу, я бы рекомендовал это решение. Работала как прелесть для меня.

$(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();
});
});

Предоставлено: http://www.kubilayerdogan.net/?p=218

Вы можете отредактировать формат файла .csv здесь   a.download = 'exported_table_' + postfix + '.csv';

Ответ 8

Просто добавлю к этим ответам (так как я недавно пытался сделать подобное) - если электронные таблицы Google - ваша программа для работы с электронными таблицами по выбору. Просто выполните эти две вещи.

1. Разделите все содержимое html файла вокруг таблиц открытия/закрытия таблиц и сохраните его как другой файл html.

2. Импортируйте этот html файл непосредственно в электронные таблицы google и вы получите красивую импортную информацию (верхний совет: если вы использовали встроенные стили в своей таблице, они также будут импортированы!)

Сэкономил мне много времени и вычислил разные конверсии.

Ответ 10

Исходя из audiodude answer, но упрощенного с помощью встроенной библиотеки CSV

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

Я действительно задавался вопросом, есть ли способ взять Nokogiri NodeSet (row.xpath('td')) и записать его как массив в файл csv за один шаг. Но я мог только вычислить это, итерации по каждой ячейке и создание временного массива каждого содержимого ячейки.

Ответ 12

Это очень старая нить, но может быть кто-то вроде меня. Я сделал некоторые дополнения для audiodude script, чтобы прочитать html из файла, вместо этого добавив его в код, и еще один параметр, который контролирует печать строк заголовка.

script должен выполняться как

ruby <script_name> <file_name> [<print_headers>]

код:

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

Ответ 13

Вот пример, используя pQuery и Таблица:: 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;

В примере просто извлекаются все теги tr, которые он находит в файле excel. Вы можете легко адаптировать его, чтобы выбрать конкретную таблицу или даже запустить новый файл excel для каждого тега таблицы.

Дальнейшие действия:

  • Вы можете захотеть получить теги td для создания заголовков excel.
  • И у вас могут быть проблемы с rowspan и colspan.

Чтобы узнать, используются ли rowspan или colspan, вы можете:

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

Ответ 14

OpenOffice.org может просматривать таблицы HTML. Просто используйте команду open в файле HTML или выберите и скопируйте таблицу в своем браузере, а затем вставьте вкладку Special в OpenOffice.org. Он запросит вас для типа файла, одним из которых должен быть HTML. Выберите это и вуаля!

Ответ 15

Это основано на ответе atomicules, но более сжато, а также обрабатывает ячейки th (header), а также ячейки td. Я также добавил метод strip, чтобы избавиться от лишних пробелов.

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

Обтекание кода внутри блока CSV гарантирует, что файл будет закрыт должным образом.


Если вы просто хотите текст и не нужно записывать его в файл, вы можете использовать это:

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

Ответ 16

Здесь обновленная версия ответа Yuvai, которая правильно обрабатывает поля, требующие цитирования (то есть поля, содержащие запятые в данных, двойные кавычки или несколько строк)

#!/usr/bin/env python3
from html.parser import HTMLParser
import sys
import re

class HTMLTableParser(HTMLParser):
    def __init__(self, row_delim="\n", cell_delim=","):
        HTMLParser.__init__(self)
        self.despace_re = re.compile("\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
        self.quote_buffer = False
        self.buffer = None

    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
        elif tag == "br":
            self.quote_buffer = True
            self.buffer += self.row_delim

    def handle_endtag(self, tag):
        self.data_interrupt = True
        if tag == "td" or tag == "th":
            self.in_cell = False
        if self.buffer != None:
            # Quote if needed...
            if self.quote_buffer or self.cell_delim in self.buffer or "\"" in self.buffer:
                # Need to quote! First, replace all double-quotes with quad-quotes
                self.buffer = self.buffer.replace("\"", "\"\"")
                self.buffer = "\"{0}\"".format(self.buffer)
            sys.stdout.write(self.buffer)
            self.quote_buffer = False
            self.buffer = None

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

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

Одним из улучшений этого сценария может быть добавление поддержки для указания другого разделителя строк (или автоматического расчета для платформы-правильного) и другого разделителя столбцов.