it-swarm.com.ru

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

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

40
asdfasdf

Этот метод на самом деле не является библиотекой OR программы, но для специальных преобразований вы можете 

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

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

Но вы, вероятно, предпочли бы сценарий Perl или Ruby ...

40
pavium

Извините за возрождение древнего потока, но недавно я хотел это сделать, но я хотел, чтобы это сделал 100% переносимый скрипт bash. Итак, вот мое решение с использованием только 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'

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

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

Получить содержимое URL с помощью cURL, сбросить 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'

,.

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

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

19
DRendar

Вот скрипт на Ruby, в котором используется нокогири - 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

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

16
audiodude

Вот небольшая программа на 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()) 
8
Yuval

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

6
Chris Simmons

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

5
jmcnamara

Предполагая, что вы разработали 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';

5
Bhagirath

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

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

2. Импортируйте этот html-файл непосредственно в электронные таблицы Google, и ваша информация будет прекрасно импортирована (Главный совет: если вы использовали встроенные стили в своей таблице, они также будут импортированы!)

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

4
toms.work

Вот простое решение без какой-либо внешней библиотеки:

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

У меня работает без проблем

3
Met Kiani

Основано на ответ аудио-датчика , но упрощено с помощью встроенной библиотеки 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

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

3
atomicules

Вот пример использования pQuery и 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;

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

Дальнейшие вещи для рассмотрения:

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

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

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

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

1
Happy Gilmore

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

скрипт должен быть запущен так

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
1
Tata

Это основано на ответе atomicules но более кратко и также обрабатывает ячейки th (заголовок) и ячейки 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
0
Josh