如何使用shell将HTML转换为表格

如何使用shell将HTML转换为表格

我有数百个 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

您正尝试逐个提取单元格,这将使您更难以重建表格。

使用简单bashpup仅:

#!/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部分,它只会打印缩进的结果。

相关内容