如何将HTML表格转换为CSV?

74

如何将HTML表格(<table>)的内容转换为CSV格式?是否有库或Linux程序可以实现此功能?这类似于在Internet Explorer中复制表格,并将其粘贴到Excel中。


23个回答

76

这种方法并不是一个真正的库或程序,但用于临时转换时,您可以:

  • 将表格的HTML放入名为something.xls的文本文件中
  • 使用电子表格打开该文件
  • 将其另存为CSV格式。

我知道这适用于Excel,而我相信我已经在OpenOffice电子表格上这样做过。

但您可能更喜欢Perl或Ruby脚本......


1
LibreOffice Calc可以做到这一点,但我发现它在读取大型(几MB)HTML表格文件时非常缓慢。因此,对于小文件或一次性使用,这是最简单的方法,但如果您有大量文件需要转换,则脚本是不错的选择。 - atomicules
在我的LibreOffice Calc 4.4.3.2中有效。 - David Bullock
这对于单元格内生成多行的表格无效。 - Lime
2
相关:在您的网络浏览器中选择表格数据并复制。打开一个仅处理纯文本的编辑器,例如Notepad.exe或BBEdit.app,并粘贴。将文档保存为*.csv*格式。它可能是以制表符分隔的,因此您可以在电子表格应用程序中打开它并导出为格式正确的CSV文件。 - Mat Gessel
如果你发现Excel无法打开包含HTML表格的文件,因为它太大了,考虑将HTML拆分成多个表格,逐个打开每个表格,并在能够打开它们后将它们合并到单个电子表格中。我的例子是:一个包含53列、17421行的表格,作为一个HTML表格存储在一个文件中,大小为58.8 MB。将表格手动拆分成5个单独的表格文件,打开并复制到一个单独的.xlsx文件中,大小为3.4 MB。 - David Thompson
显示剩余2条评论

33

抱歉打扰了这个古老的主题,但我最近想要做到这一点,但我想要一个完全可移植的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获取了页面源代码,但您也可以轻松地从其他地方获取表格源代码。

以下是解释:

使用cURL获取URL的内容,将stderr转储为null(没有进度条)。

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'  

删除表格和行标签

| 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'

请注意,如果表格单元格中包含逗号,则可能需要先对其进行转义或使用其他分隔符。

希望这能对某人有所帮助!


1
很酷的想法,但对于许多HTML文件不起作用。我的文件中数据在表格内独立一行(即<td>\ncell value\n</td>),而这个脚本最终会剥离掉那些数据,因为它会删除每一行中没有表格标签的内容。 - Hayden Schiff
很酷的东西。即使数据字段中有一些新行,它也对我起作用了。做得好! - VK Kashyap
1
在进行了一些微小的调整后,对我非常有效,真正为我节省了数小时的时间! - user1747036
@DRendar,我喜欢你的回答,但是我不能在http://www.dsebd.org/market_summary.php这个链接中使用它。 - alhelal

26

这是一个使用nokogiri的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

对于我的基本测试用例有效。


谢谢,这对于一个32M的文件非常有效,其中包含从数据库转储到php表中的220k行数据。(显然对于大多数电子表格来说不是一个选项!) - mm2001
这就是我如此热爱 Ruby 的原因。 - vincentleest

13

补充这些答案(因为我最近也在尝试类似的事情) - 如果谷歌电子表格是您选择的电子表格程序,只需执行以下两个步骤。

1. 删除围绕表格开/闭标签的html文件中的所有内容,并将其另存为另一个html文件。

2. 直接将该html文件导入到谷歌电子表格中,您将美观地导入信息(顶级提示:如果在表格中使用了内联样式,它们也会被导入!)

这为我节省了大量时间,并避免了不同格式之间的繁琐转换。


谢谢。是的,Google在最终导入之前进行了许多巧妙的清理工作。它运作得很好。请尝试使用 https://docs.google.com/spreadsheets/u/0/。 - Rahul

13

这是我写的一个短小的Python程序,用来完成这个任务。它只花了几分钟时间编写,所以可能还可以改进。不确定它如何处理嵌套表格(可能会做一些不好的事情)或多个表格(可能它们只会一个接一个地出现)。它不处理 colspanrowspan

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

1
谢谢,这很有用!不过我使用了逗号“,”而不是制表符“\t”。 - botismarius
谢谢@botismarius。我添加了指定分隔符作为参数的选项。 - Yuval

6
假设您已经设计了一个包含 table 的HTML页面,我建议使用以下解决方案。对我来说非常有效:
假设您已经设计了一个包含 table 的HTML页面,我建议使用以下解决方案。对我来说非常有效:
$(document).ready(() => {
  $("#buttonExport").click(e => {
    // Getting values of current time for generating the file name
    const dateTime = new Date();
    const day      = dateTime.getDate();
    const month    = dateTime.getMonth() + 1;
    const year     = dateTime.getFullYear();
    const hour     = dateTime.getHours();
    const minute   = dateTime.getMinutes();
    const postfix  = `${day}.${month}.${year}_${hour}.${minute}`;

    // Creating a temporary HTML link element (they support setting file names)
    const downloadElement = document.createElement('a');

    // Getting data from our `div` that contains the HTML table
    const dataType  = 'data:application/vnd.ms-excel';
    const tableDiv  = document.getElementById('divData');
    const tableHTML = tableDiv.outerHTML.replace(/ /g, '%20');

    // Setting the download source
    downloadElement.href = `${dataType},${tableHTML}`;

    // Setting the file name
    downloadElement.download = `exported_table_${postfix}.xls`;

    // Trigger the download
    downloadElement.click();

    // Just in case, prevent default behaviour
    e.preventDefault();
  });
});

来源: http://www.kubilayerdogan.net/?p=218

你可以在这里编辑文件格式为.csv:

downloadElement.download = `exported_table_${postfix}.csv`;

这在IE中可以工作吗?当我点击导出按钮时,什么也没有发生。 - Arcadian

6

我不确定是否有现成的库来完成这个任务,但如果你愿意亲自动手写一些 Perl 代码,使用 Text::CSVHTML::Parser 库应该可以实现。


5

5

4

基于audiodude的回答,但是通过使用内置的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文件。但我只能想到通过迭代每个单元格并构建临时数组来完成每个单元格内容的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接