如何提取并打印 HTML 文件的特定部分?

如何提取并打印 HTML 文件的特定部分?

我有一份如下的文件:

<html>
<head>
<title>Hello</title>
</head>
<body>
This is a page
</body>
</html>

<html>我需要列出和之间的内容</html>,然后列出不包含<....></....>部分的整个文件。我该怎么做?

答案1

这个答案是基于对问题的字面理解。任何人在搜索如何在终端中以方便、人性化的方式查看 HTML 文件时遇到此问题的人都应该查看如何从命令行预览 HTML 文档?那是不是这个答案中详述的方法有什么作用。


有时,即使 HTML 文件中没有标记的开头或结尾,也会出现<或字符。如果您必须处理此类问题(或者更一般地说,如果您需要解决方案强大且适用于任意 HTML 文档),那么>那么您应该使用一个可以实际解析 HTML 的实用程序。

但是,如果您只是为了自己的方便而生成输出并且会注意到是否出现问题(如果您没有注意到,也不会发生任何可怕的事情),那么您可以使用几种文本处理技术中的任何一种来完成您要做的事情。

使用 Unix 系统实用程序处理文本的最常见方法是将输入视为一系列行。由于换行符在 HTML 中没有特殊意义,因此我避免使用这种方法,并且此答案中给出的方法甚至适用于跨行拆分的标签。但是,我强调这些仍然是近似解决方案。

<html>提取标签之间的文本

这个 Python 3 单行命令(从你的 shell 运行它)打印index.html在第一次出现之后<html>但在第一次出现之前出现的所有文本</html>

python3 -c 'import pathlib; s=pathlib.Path("index.html").read_text(); e="<html>"; print(s[s.find(e)+len(e):s.find("</html>")])'

如果你愿意,你可以将其取消高尔夫并将其增强为可重复使用的脚本:

#!/usr/bin/env python3

from sys import argv
from pathlib import Path

start = '<html>'
end = '</html>'

for path in argv[1:]:
    text = Path(path).read_text()
    print(text[text.find(start) + len(start) : text.find(end)])

如果将脚本保存为print-inside-html,则可以将其标记为可执行文件,如下所示:

chmod +x print-inside-html

你可以index.html像这样运行它:

./print-inside-html index.html

如果愿意的话,你可以同时在多个文件上运行它:

./print-inside-html index.html foo.html coolstuff/index.html

然而,你可能会注意到如果开始和结束标签之间有前导和尾随空格,则会打印出来。如果您不想要这个,那么您可以使用该strip函数将其删除。这是一个修改后的单行代码:

python3 -c 'import pathlib; s=pathlib.Path("index.html").read_text(); e="<html>"; print(s[s.find(e)+len(e):s.find("</html>")].strip())'

并且,不打高尔夫:

#!/usr/bin/env python3

from sys import argv
from pathlib import Path

start = '<html>'
end = '</html>'

for path in argv[1:]:
    text = Path(path).read_text()
    print(text[text.find(start) + len(start) : text.find(end)].strip())

然而,以上两种方式都不能适应大小写变体标签名称(例如,HTML而不是html)或标签名称后的空格. 这个进一步修改的单行代码使用常用表达以适应两者:

python3 -c 'import re,pathlib; s=pathlib.Path("index.html").read_text(); print(s[re.search(r"(?i)<html\s*>",s).end():re.search(r"(?i)</html\s*>",s).start()].strip())'

未打高尔夫:

#!/usr/bin/env python3

import re
from sys import argv
from pathlib import Path

start = re.compile(r'(?i)<html\s*>')
end = re.compile(r'(?i)</html\s*>')

for path in argv[1:]:
    text = Path(path).read_text()
    print(text[start.search(text).end() : end.search(text).start()].strip())

(?i)使正则表达式不区分大小写,并\s*占用标签名称和结束符之间的任何空格>。请参阅本指南这个问题了解该代码中使用的功能的信息。

删除看起来像标签的文本

如果您愿意将以<或开头</,后跟非空白字符(也不是/<>),后跟除 之外的任意数量的字符>,后跟 的任何内容>视为标签,那么这将打印index.html删除标签的内容:

python3 -c 'import re,pathlib; print(re.sub(r"</?[^\s/<>][^>]*>", "", pathlib.Path("index.html").read_text()))'

这并不是在解析 HTML 代码,并且实际规则对于标签的构成,定义更加微妙。显然,这在任何要求 HTML 始终正确解析的应用程序中都行不通。例如,不是在网络浏览器中使用它或代码清理器(确实,不要在任何应用程序或通用实用程序中使用它。)

这是一个更易于管理的单行代码(比上面用于提取<html></html>标签之间的文本的代码更易于管理)。但如果你想将它作为一个格式良好的脚本:

#!/usr/bin/env python3

import re
from sys import argv
from pathlib import Path

pattern = re.compile(r'</?[^\s/<>][^>]*>')

for path in argv[1:]:
    text = Path(path).read_text()
    print(pattern.sub('', text))

如果你把它放在一个名为的文件中remove-tagish-stuff,那么这些命令会将其标记为可执行文件并在一个文件上运行它,然后同时在另外几个文件上运行它:

chmod +x remove-tagish-stuff
./remove-tagish-stuff index.html
./remove-tagish-stuff foo.html bar/baz.html

这不会修改文件;与上面的其他代码一样,它只是输出删除了某些部分的内容。

当您在大多数 HTML(包括问题中显示的示例 HTML)上运行此代码时,您会看到许多空白行。您可能希望这样做,因为大多数文档在所有内容拼凑在一起时会变得非常难以阅读。但是,如果您想将重复的空白行变成一行并删除开头和结尾的空格,那么您可以改用这个:

python3 -c 'import re,pathlib; s=re.sub(r"</?[^\s/<>][^>]*>","",pathlib.Path("index.html").read_text()); print(re.sub("\n{3,}","\n\n",s).strip())'

下面是一个脚本,您可以将文件名作为命令行参数传递(与前面的脚本一样):

#!/usr/bin/env python3

import re
from sys import argv
from pathlib import Path

tag = re.compile(r'</?[^\s/<>][^>]*>')
excess = re.compile('\n{3,}')

for path in argv[1:]:
    text = Path(path).read_text()
    detagged = tag.sub('', text)
    print(excess.sub('\n\n', detagged).strip())

如果你要使用其中任何一个,我建议使用最簡單那些可以做你想做的事情。同样,可以进一步“改进”和复杂化代码以涵盖更多情况 ——例如<>在标签属性中发生 —— 但我在这里避免这样做。如果你需要做任何事情,比如准确解析任意 HTML 文档的结构,那么你应该不是使用正则表达式。

既然上面显示的命令和脚本只应该在完全不严重的情况下使用,我为什么要展示这个呢?这与我尝试grep在网页文件夹中查找单词的原因相同。它很脆弱,远非万无一失(grep -FR tallest .无法匹配She's the tall<em>est</em>!),但只要记住它的局限性,它有时还是很方便的。

相关内容