努力使用 grep、sed、awk 来过滤 html

努力使用 grep、sed、awk 来过滤 html

我正在尝试自学如何在 cygwin 安装上使用 Linux 工具。我决定编一个项目来尝试自学 shell 脚本的基础知识,同时完成一些个人教育。我最初的项目是保存每个获奖者的 html 页面萨哈罗夫奖到一个文件夹中,并编写一个脚本来处理所有 html 文本文件并以连字符格式返回姓名、年份、出生和死亡以及原籍国。由于日期格式存在某些不一致(1918 年 7 月 18 日与 1938 年 1 月 23 日),以及无法处理死者与没有死亡日期的活人,也无法弄清楚如何告诉计算机如何识别国家/地区名称而无需手动列出就我自己而言,我基本上已经放弃了这个项目。

现在,我只是尝试从 html 表中返回每个收件人的年份、姓名和原籍国家/地区萨哈罗夫奖维基百科页面。

因此,给出以下示例 html:

<tr>
<td>1988</td>
<td><span style="display:none;">Mandela, Nelson</span><span class="vcard"><span class="fn"><a href="/wiki/Nelson_Mandela" title="Nelson Mandela">Nelson Mandela</a></span></span></td>
<td><a href="/wiki/South_Africa" title="South Africa">South Africa</a></td>
<td>Anti-apartheid activist and later President of South Africa</td>
<td><sup id="cite_ref-twentyyears_5-0" class="reference"><a href="#cite_note-twentyyears-5"><span>[</span>5<span>]</span></a></sup></td>
</tr>
<tr>
<td>1988</td>
<td><span style="display:none;">Marchenko, Anatoly</span><span class="vcard"><span class="fn"><a href="/wiki/Anatoly_Marchenko" title="Anatoly Marchenko">Anatoly Marchenko</a></span></span> (posthumously)</td>
<td><a href="/wiki/Soviet_Union" title="Soviet Union">Soviet Union</a></td>
<td>Soviet dissident, author and humans rights activist</td>
<td><sup id="cite_ref-twentyyears_5-1" class="reference"><a href="#cite_note-twentyyears-5"><span>[</span>5<span>]</span></a></sup></td>
</tr>

仅返回每个收件人的年份、姓名和原籍国的最佳方式是什么?现在我正在考虑编写一个 awk 脚本来返回与 /<*>/ 不匹配的所有内容,但这并不是我想要的。有人可以给我一些关于如何具体挑选名称、年份和国家/地区的指示或想法吗?或者至少有一些书比我自己想出的问题更好、更容易管理?当我开始时,这一切听起来都没什么不合理的……

答案1

正如已经提到的正则表达式不适合解析 html。与另一个类似解析答案您可以制作如下所示的 Ruby 语句来为您完成此操作。请注意,它需要野科切您可以将其安装为 gem ( sudo gem install nokogiri)。

ruby -rnokogiri -e 'Nokogiri::HTML(readlines.join).css("tr").each { |tr| tr.xpath(".//td").take(3).each { |td| puts td.content } }' sample.html

它读取给定的文件(在本例中为sample.html),获取所有tr元素,并为每个此类元素打印前三个td元素的内容。

对于您的示例,它将输出:

1988年
纳尔逊·曼德拉纳尔逊·曼德拉
南非
1988年
阿纳托利·马尔琴科阿纳托利·马尔琴科(死后)
苏联

问题是包含两次名称的行,例如(格式化为更易于阅读)

<td>
  <span style="display:none;">Mandela, Nelson</span>
  <span class="vcard"><span class="fn">
      <a href="/wiki/Nelson_Mandela" title="Nelson Mandela">Nelson Mandela</a>
    </span>
  </span>
</td>

其中名称首先出现在 a spanwith中style="display:none;",然后再次出现在 another 中span。我不确定如何仅提取不在元素内的名称style="display:none;。 (我已经发现https://stackoverflow.com/q/6096327/789593https://stackoverflow.com/q/11602077/789593但他们没有描述正确的技术。也许有人可以通过以下方式提出解决方案http://nokogiri.org/Nokogiri/XML/Node.html?)

答案2

我创建了可以在此处使用的 node.js 包:贡巴。它有点像 awk、sed 的替代品。

所以在你的例子中它将像这样工作:

cat file.html | gumba "stripTags()"

其输出:

1988
Mandela, NelsonNelson Mandela
South Africa
Anti-apartheid activist and later President of South Africa
[5]


1988
Marchenko, AnatolyAnatoly Marchenko (posthumously)
Soviet Union
Soviet dissident, author and humans rights activist
[5]

虽然在这里我认为最好不要使用 oneliners,而是用您知道的任何语言实际编写脚本。

答案3

sed -rn '
    /<tr>/ {
        n
        s#<td>([^<]*)</td>#\1#
        h
        n
        s#<td><span[^>]*>([^<]*)</span>.*#\1#
        H
        n
        s#<td><a href=[^>]*>([^<]*)</a>.*#\1#
        H
        x;p
    }
' file

1988
Mandela, Nelson
South Africa
1988
Marchenko, Anatoly
Soviet Union

相关内容