我已经看到 grep 在很多答案中被抛来抛去,但从未全神贯注。
现在我正在尝试从 Internet 获取本地保存页面的 HTML 标记内的内容,但我遇到了困难。我可以使用 grep 来识别我想要的输出,但不可能将其分隔为可用。
这是我的 test.sh 文件内容:
a=$(awk '/<div class="power-bar-text">/,/<\/div>/' 'Acid Fast.html')
b=$(echo $a | grep -PzTo [0-9\.]+)
echo $a
echo $b
此终端输出结果:
test.sh: line 4: warning: command substitution: ignored null byte in input
<div class="power-bar-text"> 9 </div> <div class="power-bar-text"> 8 </div> <div class="power-bar-text"> 11.25 </div> <div class="power-bar-text"> 10 </div> <div class="power-bar-text"> 6 </div> <div class="power-bar-text"> 5 </div> <div class="power-bar-text"> 2 (1s) </div> <div class="power-bar-text"> 3 </div> <div class="power-bar-text"> 2.50 </div>
9811.2510652132.50
这是先前的迭代,具有更好的人类可读性:
$ awk '/<div class="power-bar-text">/,/<\/div>/' 'Acid Fast.html' | grep -Pzn -C1 [0-9\.]+ -
1: <div class="power-bar-text">
9
</div>
<div class="power-bar-text">
8
</div>
<div class="power-bar-text">
11.25
</div>
<div class="power-bar-text">
10
</div>
<div class="power-bar-text">
6
</div>
<div class="power-bar-text">
5
</div>
<div class="power-bar-text">
2 (1s)
</div>
<div class="power-bar-text">
3
</div>
<div class="power-bar-text">
2.50
</div>
我不知道如何在上面的代码框中设置着色,但终端确实为那里的每个数字和句点使用默认匹配字体颜色红色对其进行编码。
(如果类名恰好是“power.bar.text”,这可能行不通,因为句点会在那里匹配......所以任何关于确保任何句点都是数字的帮助?我想这可能适用于正则表达式[0-9]+\.?[0-9]*
。 )
但是回到使用 bash 代码的第一个代码块,它提供的最终输出是9811.2510652132.50
. 但我想要类似的东西9,8,11.25,10,6,5,2,1,3,2.50
如果我对 grep 进行编码,我将可以选择-d,
将分隔符设置为输出中的命令。不幸的是,当我尝试时,这个想法没有奏效。
我有一个可能有用的可怕想法是使用 -m 参数输出重复处理它,增加允许的匹配数,然后找到每个输出之间的新内容。再一次,这听起来很糟糕。(例如,我希望 -m1 得到 9,然后 -m2 得到 98,-m3 得到 9811.25,我将从 m1 的输出中“减去”m2 的输出为 8;m3 的输出从 m2 的输出中得到11.25.)
实际上刚刚尝试过,它不起作用,因为我猜 awk 使它成为单行,所以无论我将它限制为多少匹配,都会输出完整的字符串,因为9811.2510652132.50
它的整体是第一个也是唯一的匹配。
当然有更好的方法吗?
如评论中所述,
grep
(用于从非结构化文本文档中提取行的实用程序)不是您想要用于解析 HTML 或一般结构化文档的工具。理想情况下,您希望使用能够对文档应用结构化查询的工具以其他方式提取、修改或处理数据。对于 XML 文档,一种这样的命令行工具是xmlstarlet
,您可以使用它对 XML 文档应用XPath 查询。div
假设您的 HTML 文档是正确的 XHTML,我们可以提取具有class
value 属性的节点的内容power-bar-text
,同时修剪掉侧翼空格:这首先匹配
div
我们感兴趣的节点,然后提取normalize-space()
应用于这些匹配节点的函数的结果。最后,-nl
用换行符分隔每个输出。或者,使用短选项,
给定您显示的文档片段,这可能会输出如下内容:
这可以通过将其传递到以逗号作为分隔符的单行
...像这样:
如果您只想在命令的每行输出的第一个空格之前发生任何事情,请添加一些额外的处理
xmlstarlet
:如果你的文件不是 XHTML,你可能会把它转换成可用的东西
要添加到 Kusalananda 的答案中,如果您有更通用的 HTML,您可能希望使用 BeautifulSoup 而不是希望转换为 XML(并不是说它本身不使用不同的 XML 解析器,它处理解析的方式可能只是对您的用例更优雅)。
你会写一个脚本——但不是
bash
脚本,而是 Python 脚本(这是直接从我的脑海中写出来的,只是表面测试)保存到某个文件,例如
myparser.py
,生成可执行文件 (chmod 755 myparser.py
),然后以 HTML 文件名作为参数运行 (/path/to/myparser.py /path/to/input.html
)。漂亮的、不言自明的代码就这么多了。如果您觉得需要在您的 shell 中执行此操作,您可以将其压缩为一个单行代码。(我建议你不要那样做;你可以在你的 bash 脚本中以多行字符串/HEREDOC 的形式嵌入上面完整的易读、易产生错误的 python 代码):