【发布时间】:2010-11-27 01:09:12
【问题描述】:
如何将 HTML 表格 (<table>) 的内容转换为 CSV 格式?是否有执行此操作的库或 linux 程序?这类似于在 Internet Explorer 中复制表格,然后将它们粘贴到 Excel 中。
【问题讨论】:
标签: html csv html-table
如何将 HTML 表格 (<table>) 的内容转换为 CSV 格式?是否有执行此操作的库或 linux 程序?这类似于在 Internet Explorer 中复制表格,然后将它们粘贴到 Excel 中。
【问题讨论】:
标签: html csv html-table
这是我仅使用 tr 和 sed 的方法:
< table.txt tr -d '\n' | #delete newlines
sed 's/<tr[^>]*>/\n/g' | #convert tr tags into newlines to break data into table rows
sed 's/<[^>]*td>/,/g' | #convert closing td tags into commas
sed 's/<[^>]*>//g' #delete all other html tags
示例输入(来自试图使用 MsoNormal 呈现 HTML 表格的 Outlook 电子邮件):
<table class=3D"MsoNormalTable" border=3D"0" cellspacing=3D"0" cellpadding=3D"0" width=3D"420" style=3D"width:315.0pt;border-collapse:collapse">
<tbody>
<tr style=3D"height:15.0pt">
<td width=3D"107" nowrap=3D"" style=3D"width:80.0pt;padding:0in 0in 0in 0in;height:15.0pt">
</td>
<td width=3D"107" nowrap=3D"" valign=3D"bottom" style=3D"width:80.0pt;padding:0in 0in 0in 0in;height:15.0pt">
</td>
<td width=3D"64" nowrap=3D"" valign=3D"bottom" style=3D"width:48.0pt;padding:0in 0in 0in 0in;height:15.0pt">
</td>
<td width=3D"79" nowrap=3D"" valign=3D"bottom" style=3D"width:59.0pt;padding:0in 0in 0in 0in;height:15.0pt">
</td>
<td width=3D"64" nowrap=3D"" valign=3D"bottom" style=3D"width:48.0pt;padding:0in 0in 0in 0in;height:15.0pt">
</td>
</tr>
<tr style=3D"height:6.75pt">
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:6.75pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:6.75pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:6.75pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:6.75pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:6.75pt"></td>
</tr>
<tr style=3D"height:15.0pt">
<td nowrap=3D"" valign=3D"bottom" style=3D"border:solid windowtext 1.0pt;padding:0in 0in 0in 0in;height:15.0pt">
<p class=3D"MsoNormal" align=3D"center" style=3D"text-align:center"><b><span style=3D"color:black">ID</span></b><b><span style=3D"color:black"><o:p></o:p></span></b></p>
</td>
<td nowrap=3D"" valign=3D"bottom" style=3D"border:solid windowtext 1.0pt;border-left:none;padding:0in 0in 0in 0in;height:15.0pt">
<p class=3D"MsoNormal" align=3D"center" style=3D"text-align:center"><b><span style=3D"color:black">Price<o:p></o:p></span></b></p>
</td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
</tr>
<tr style=3D"height:15.0pt">
<td nowrap=3D"" valign=3D"bottom" style=3D"border:solid windowtext 1.0pt;border-top:none;padding:0in 0in 0in 0in;height:15.0pt">
<p class=3D"MsoNormal" align=3D"center" style=3D"text-align:center"><span style=3D"color:black">064159Q</span><span style=3D"color:black"><o:p></o:p></span></p>
</td>
<td nowrap=3D"" valign=3D"bottom" style=3D"border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0in 0in 0in 0in;height:15.0pt">
<p class=3D"MsoNormal" align=3D"center" style=3D"text-align:center"><span style=3D"color:black">121.85<o:p></o:p></span></p>
</td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
</tr>
<tr style=3D"height:15.0pt">
<td nowrap=3D"" valign=3D"bottom" style=3D"border:solid windowtext 1.0pt;border-top:none;padding:0in 0in 0in 0in;height:15.0pt">
<p class=3D"MsoNormal" align=3D"center" style=3D"text-align:center"><span style=3D"color:black">2420128</span><span style=3D"color:black"><o:p></o:p></span></p>
</td>
<td nowrap=3D"" valign=3D"bottom" style=3D"border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0in 0in 0in 0in;height:15.0pt">
<p class=3D"MsoNormal" align=3D"center" style=3D"text-align:center"><span style=3D"color:black">10.00<o:p></o:p></span></p>
</td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
<td nowrap=3D"" valign=3D"bottom" style=3D"padding:0in 0in 0in 0in;height:15.0pt"></td>
</tr>
</tbody>
</table>
样本输出:
,,,,,
,,,,,
ID,Price,,,,
064159Q,121.85,,,,
2420128,10.00,,,,
有关该方法的讨论,请参阅 Non-greedy regex matching in sed。
【讨论】:
根据您的需要,您可以简单地:
var table ='';var selector='#customers';
document.querySelectorAll(`${selector} tr th`).forEach(h=>table+=`${h.innerText.trim()};`);table=table.trim();table+='\r\n';
document.querySelectorAll(`${selector} tr`).forEach(tr=>{tr.querySelectorAll('td').forEach(td=>table+=`${td.innerText.trim()};`);table+='\r\n';});
更改“选择器”以定位您的表格,执行“表格”后将拥有您的 csv 内容
此外,您还可以:
var a = document.createElement('a');a.href=`data:text/csv;base64,${btoa(table)}`;a.download="table.csv";a.click();
下载“表格”的内容
【讨论】:
CSV和nokogiri输出到.csv。基于@audiodude's answer,但做了以下修改:
CSV 的内置库将Array 转换为CSV 行。.csv 文件,而不是仅仅打印到STDOUT。th) 和表体 (td)。# Convert HTML table to CSV format.
require "nokogiri"
html_file_path = ""
html_string = File.read( html_file_path )
doc = Nokogiri::HTML( html_string )
CSV.open( Rails.root.join( Time.zone.now.to_s( :file ) + ".csv" ), "wb" ) do |csv|
doc.xpath( "//table//tr" ).each do |row|
csv << row.xpath( "th|td" ).collect( &:text ).collect( &:strip )
end
end
【讨论】:
假设您设计了一个包含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`;
【讨论】:
这是Yuvai's answer 的更新版本,它可以正确处理需要引用的字段(即数据中包含逗号、双引号或跨多行的字段)
#!/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())
此脚本的一项改进可能是添加对指定不同行分隔符(或自动计算平台正确的分隔符)和不同列分隔符的支持。
【讨论】:
这里是一个没有任何外部库的简单解决方案:
https://www.codexworld.com/export-html-table-data-to-csv-using-javascript/
它对我有用,没有任何问题
【讨论】:
这是一个使用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 甚至触发每个 table 标记的新 excel 文件。
需要考虑的其他事项:
要查看是否使用了 rowspan 或 colspan,您可以:
pQuery( $data )->find( 'td' )->each( sub{
my $number_of_cols_spanned = $_->getAttribute( 'colspan' );
});
【讨论】:
只是为了补充这些答案(因为我最近一直在尝试类似的事情) - 如果 Google 电子表格 是您选择的电子表格程序。只需做这两件事。
1. 将 表格开始/结束标签 周围的所有内容从 html 文件中剥离出来,并将其重新保存为另一个 html 文件。
2. 将该 html 文件直接导入到谷歌电子表格中,您的信息将被精美地导入 (重要提示:如果您在表格中使用内联样式,它们将被导入为好吧!)
为我节省了大量时间并找出不同的转化。
【讨论】:
这是我为完成这项任务而编写的一个简短的 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())
【讨论】:
这基于atomicules' answer,但更简洁,还处理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
【讨论】:
很抱歉复活了一个古老的线程,但我最近想这样做,但我想要一个 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 获得了页面源,但您也可以轻松地从其他地方输入表格源。
解释如下:
使用 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'
.
删除 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'
.
请注意,如果任何表格单元格包含逗号,您可能需要先对其进行转义,或使用不同的分隔符。
希望这对某人有所帮助!
【讨论】:
<td>\ncell value\n</td>),这个脚本最终删除了这些数据,因为它删除了每一行没有表标签的行。
这是一个非常古老的线程,但可能像我这样的人会碰到它。 我为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
【讨论】:
使用 Perl,您可以使用 HTML::TableExtract 模块从表中提取数据,然后使用 Text::CSV_XS 创建 CSV 文件或使用 Spreadsheet::WriteExcel 创建 Excel 文件。
【讨论】:
基于audiodude's 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 节点集 (row.xpath('td')) 并一步将其作为数组写入 csv 文件。但我只能通过遍历每个单元格并构建每个单元格内容的临时数组来解决这个问题。
【讨论】:
OpenOffice.org 可以查看 HTML 表格。只需在 HTML 文件上使用打开命令,或在浏览器中选择并复制表格,然后在 OpenOffice.org 中选择性粘贴。它将向您查询文件类型,其中之一应该是 HTML。选择它,瞧!
【讨论】:
我不确定是否有为此准备的库,但如果您愿意使用一点 Perl,您可以使用 Text::CSV 和 HTML::Parser 做一些事情。
【讨论】:
这是一个使用 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
为我的基本测试用例工作。
【讨论】:
这个方法不是真正的库或程序,但您可以进行临时转换
我知道这适用于 Excel,并且我相信我已经使用 OpenOffice 电子表格做到了。
但您可能更喜欢 Perl 或 Ruby 脚本...
【讨论】: