我有数百个 HTML 文件,这些文件的内容相对简单,并且保持一致的格式。
我需要将它们转换为表,我可以使用 shell 脚本来执行此操作吗?
HTML 源代码
<html>
<head>
<title>Demo</title>
</head>
<body>
<h1>Page Title</h1>
<div class="row">
<p class="text-1">Text 1</p>
<p class="text-2">Text 2</p>
<p class="text-3">Text 3</p>
<p class="text-4">Text 4</p>
<p class="text-5">Text 5</p>
<p class="text-6">Text 6</p>
</div>
<div class="row">
<p class="text-1">Text 1</p>
<p class="text-2">Text 2</p>
<p class="text-3">Text 3</p>
<p class="text-4">Text 4</p>
<p class="text-5">Text 5</p>
<p class="text-6">Text 6</p>
</div>
<div class="row">
<p class="text-1">Text 1</p>
<p class="text-2">Text 2</p>
<p class="text-3">Text 3</p>
<p class="text-4">Text 4</p>
<p class="text-5">Text 5</p>
<p class="text-6">Text 6</p>
</div>
</body>
</html>
转换表源代码
<table>
<caption>Page Title</caption>
<thead>
<tr>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
</tr>
</thead>
<tbody>
<tr>
<td>Text 1</td>
<td>Text 2</td>
<td>Text 3</td>
<td>Text 4</td>
<td>Text 5</td>
<td>Text 6</td>
</tr>
<tr>
<td>Text 1</td>
<td>Text 2</td>
<td>Text 3</td>
<td>Text 4</td>
<td>Text 5</td>
<td>Text 6</td>
</tr>
<tr>
<td>Text 1</td>
<td>Text 2</td>
<td>Text 3</td>
<td>Text 4</td>
<td>Text 5</td>
<td>Text 6</td>
</tr>
</tbody>
</table>
这就是思维导图。
在提出问题之前,我尝试在网上查找信息,发现可以使用以下命令提取HTML内容小狗工具,其使用方法如下。
# Extracting page titles
cat demo.html | pup 'body > h1 text{}'
# Extracting paragraph text
cat demo.html | pup 'body > div.row > p.text-1 text{}'
cat demo.html | pup 'body > div.row > p.text-2 text{}'
cat demo.html | pup 'body > div.row > p.text-3 text{}'
cat demo.html | pup 'body > div.row > p.text-4 text{}'
cat demo.html | pup 'body > div.row > p.text-5 text{}'
cat demo.html | pup 'body > div.row > p.text-6 text{}'
接下来我遇到了困难,我不知道如何将其制作成shell脚本。它涉及 shell 循环,我花了几天时间试图弄清楚,但没有成功。
你们都可以帮助我吗?先感谢您!
更新
这就是我尝试做的事情。它有几个问题。
- 它只能处理一个
<div class="row">...</div>
数据,这是我遇到的最棘手的问题(问题如下所示)。这就涉及到shell循环问题了。 - 它一次只能转换一个 HTML 文件,理想情况下可以批量处理数百个 HTML 文件(导出到另一个目录并保存,文件名保持一致)。
#!/usr/bin/env bash
# Extracts HTML content
page_title=$(cat demo.html | pup 'body > h1 text{}')
paragraph_text_a=$(cat demo.html | pup 'body > div.row > p.text-1 text{}')
paragraph_text_b=$(cat demo.html | pup 'body > div.row > p.text-2 text{}')
paragraph_text_c=$(cat demo.html | pup 'body > div.row > p.text-3 text{}')
paragraph_text_d=$(cat demo.html | pup 'body > div.row > p.text-4 text{}')
paragraph_text_e=$(cat demo.html | pup 'body > div.row > p.text-5 text{}')
paragraph_text_f=$(cat demo.html | pup 'body > div.row > p.text-6 text{}')
# Print the contents in a predetermined format
cat << EOF
<table>
<caption>$page_title</caption>
<thead>
<tr>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
</tr>
</thead>
<tbody>
<tr>
<td>$paragraph_text_a</td>
<td>$paragraph_text_b</td>
<td>$paragraph_text_c</td>
<td>$paragraph_text_d</td>
<td>$paragraph_text_e</td>
<td>$paragraph_text_f</td>
</tr>
</tbody>
</table>
EOF
答案1
以下应该或多或少可以做到这一点,请记住我:
- 只是写了一下,没有测试。编辑:现在我确实测试了它,修复了一些错误,它似乎有效。
- 我忽略边缘情况(多个
<h1>
,<tbody>
在表字段内等等,...)
将其放入“scriptname.pl”中,更改第 2 行和第 3 行的文件名并运行perl scriptname.pl
#!/usr/bin/perl
open my $ifh, "inputfilename.html";
open my $ofh, ">outputfilename.html";
while(<$ifh>) {
if(/<h1>(.*)<\/h1>/) {
my $header = << "END";
<table>
<caption>$1</caption>
<thead>
<tr>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
<th>Hard Code</th>
</tr>
</thead>
<tbody>
END
print $ofh $header;
} elsif(/<div class="row">/) {
print $ofh "<tr>\n";
} elsif(/<\/div>/) {
print $ofh "</tr>\n";
} elsif(/<p class=".*?">(.*)<\/p>/) {
print $ofh "<td>$1</td>\n";
} elsif(/<\/body>/) {
print $ofh "</tbody>\n</table>\n</body>\n";
} else {
print $ofh $_;
}
}
close $ofh;
close $ifh;
答案2
您正尝试逐个提取单元格,这将使您更难以重建表格。
使用简单bash
且pup
仅:
#!/bin/bash
count=$(grep '<div ' demo.html | wc -l)
page_title=$(cat demo.html | pup 'body h1 text{}')
tbody() {
for ((i=1;i<count+1;++i)); do
IFS=, row=$(cat demo.html | pup "body div.row:nth-of-type($i) text{}" | grep '\S' | paste -s -d, -)
printf "\t\t<tr>\n"
printf '\t\t\t<td>%s</td>\n' $row
printf "\t\t</tr>\n"
done
}
cat <<EOF
<table>
<caption>$page_title</caption>
<thead>
<tr>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
</tr>
</thead>
<tbody>
`tbody`
</tbody>
</table>
EOF
输出
<table>
<caption>Page Title</caption>
<thead>
<tr>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
<th>Hard Coded</th>
</tr>
</thead>
<tbody>
<tr>
<td>Text 1</td>
<td>Text 2</td>
<td>Text 3</td>
<td>Text 4</td>
<td>Text 5</td>
<td>Text 6</td>
</tr>
<tr>
<td>Text 1</td>
<td>Text 2</td>
<td>Text 3</td>
<td>Text 4</td>
<td>Text 5</td>
<td>Text 6</td>
</tr>
<tr>
<td>Text 1</td>
<td>Text 2</td>
<td>Text 3</td>
<td>Text 4</td>
<td>Text 5</td>
<td>Text 6</td>
</tr>
</tbody>
</table>
解释
这个想法是通过迭代直到最后一行来逐行提取数据。此代码片段将为您提供行数:
grep '<div ' demo.html | wc -l
然后通过用作nth-of-type(n)
选择器,您可以抓取整行而不是列。您需要将其传递给以grep '\S'
消除空行。然后通过传递给paste -s -d, -
, 将产生逗号分隔的结果。
IFS=, row=$(cat demo.html | pup "body div.row:nth-of-type($i) text{}" | grep '\S' | paste -s -d, -)
将printf '\t\t\t<td>%s</td>\n' $row
扩展为printf '\t\t\t<td>%s</td>\n' 'Text 1' 'Text 2' ...
并将每个参数包装为<td>...</td>
您可以完全删除该\t
部分,它只会打印缩进的结果。