我正在尝试自学如何在 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 span
with中style="display:none;"
,然后再次出现在 another 中span
。我不确定如何仅提取不在元素内的名称style="display:none;
。 (我已经发现https://stackoverflow.com/q/6096327/789593和https://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