我正在尝试创建一个从HTML表中提取数据的BASH脚本。 下面是我需要提取数据的表格示例:
<table border=1>
<tr>
<td><b>Component</b></td>
<td><b>Status</b></td>
<td><b>Time / Error</b></td>
</tr>
<tr><td>SAVE_DOCUMENT</td><td>OK</td><td>0.406 s</td></tr>
<tr><td>GET_DOCUMENT</td><td>OK</td><td>0.332 s</td></tr>
<tr><td>DVK_SEND</td><td>OK</td><td>0.001 s</td></tr>
<tr><td>DVK_RECEIVE</td><td>OK</td><td>0.001 s</td></tr>
<tr><td>GET_USER_INFO</td><td>OK</td><td>0.143 s</td></tr>
<tr><td>NOTIFICATIONS</td><td>OK</td><td>0.001 s</td></tr>
<tr><td>ERROR_LOG</td><td>OK</td><td>0.001 s</td></tr>
<tr><td>SUMMARY_STATUS</td><td>OK</td><td>0.888 s</td></tr>
</table>
我希望BASH脚本像这样输出:
SAVE_DOCUMENT OK 0.475 s
GET_DOCUMENT OK 0.345 s
DVK_SEND OK 0.002 s
DVK_RECEIVE OK 0.001 s
GET_USER_INFO OK 4.465 s
NOTIFICATIONS OK 0.001 s
ERROR_LOG OK 0.002 s
SUMMARY_STATUS OK 5.294 s
怎么做?
到目前为止,我已尝试使用sed,但我不知道如何使用它。表格的标题(组件,状态,时间/错误)我使用grep "<tr><td>
将grep排除在外,因此只会选择以<tr><td>
开头的行进行下一次解析(sed)。
这就是我使用的:sed 's@<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\2@g'
但是<tr>
标签仍然存在,并且它也不会将字符串分开。换句话说,这个脚本的结果是:
<tr>SAVE_DOCUMENTOK0.406 s</tr>
我正在处理的脚本的完整命令是:
cat $FILENAME | grep "<tr><td>" | sed 's@<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\2@g'
答案 0 :(得分:13)
使用(g)awk
,它有能力:-),这是一个解决方案,但请注意:它只使用您发布的确切html表格式。
awk -F "</*td>|</*tr>" '/<\/*t[rd]>.*[A-Z][A-Z]/ {print $3, $5, $7 }' FILE
您可以在此处看到它:https://ideone.com/zGfLe
一些解释:
-F
将输入字段分隔符设置为正则表达式(tr
的任何一个或td
的开始或结束标记
然后仅适用于与这些标签匹配的行和至少两个超级字段
然后打印所需的字段。
HTH
答案 1 :(得分:11)
您可以使用bash xpath
( XML :: XPath perl模块)轻松完成该任务:
xpath -e '//tr[position()>1]' test_input1.xml 2> /dev/null | sed -e 's/<\/*tr>//g' -e 's/<td>//g' -e 's/<\/td>/ /g'
答案 2 :(得分:5)
有很多方法可以做到这一点,但这里有一个:
grep '^<tr><td>' < $FILENAME \
| sed \
-e 's:<tr>::g' \
-e 's:</tr>::g' \
-e 's:</td>::g' \
-e 's:<td>: :g' \
| cut -c2-
您可以使用更多 sed(1)(-e 's:^ ::'
)代替cut -c2-
来删除前导空格,但 cut(1)没有得到应有的爱。并且反斜杠只是用于格式化,你可以删除它们以获得一个衬里或留下它们并确保它们紧接着是换行符。
基本策略是逐步将HTML拉开,而不是试图用一堆难以理解的正则表达式语法一次完成所有操作。
使用shell管道解析HTML并不是最好的想法,但如果已知HTML具有非常特定的格式,则可以这样做。如果存在变化,那么在Perl,Ruby,Python甚至C中使用真正的HTML解析器你会更好。
答案 3 :(得分:5)
您可以使用html2text
命令并通过column
格式化列,例如:
$ html2text table.html | column -ts'|'
Component Status Time / Error
SAVE_DOCUMENT OK 0.406 s
GET_DOCUMENT OK 0.332 s
DVK_SEND OK 0.001 s
DVK_RECEIVE OK 0.001 s
GET_USER_INFO OK 0.143 s
NOTIFICATIONS OK 0.001 s
ERROR_LOG OK 0.001 s
SUMMARY_STATUS OK 0.888 s
然后从那里进一步解析(例如cut
,awk
,ex
)。
答案 4 :(得分:1)
基于多平台网络抓取CLI xidel
和 XQuery 的解决方案:
xidel -s --xquery 'for $tr in //tr[position()>1] return join($tr/td, " ")' file
通过样本输入,可以得到:
SAVE_DOCUMENT OK 0.406 s
GET_DOCUMENT OK 0.332 s
DVK_SEND OK 0.001 s
DVK_RECEIVE OK 0.001 s
GET_USER_INFO OK 0.143 s
NOTIFICATIONS OK 0.001 s
ERROR_LOG OK 0.001 s
SUMMARY_STATUS OK 0.888 s
说明:
XQuery查询for $tr in //tr[position()>1] return join($tr/td, " ")
处理tr
个元素,从第二个元素开始(position()>1
,跳过标题行),并加入子元素的值td
个元素($tr/td
),其中一个空格作为分隔符。
-s
使xidel
无声(禁止输出状态信息)。
虽然 html2text
方便显示 提取的数据,但提供机器可解析的输出非常重要,不幸的是:
html2text file | awk -F' *\\|' 'NR>2 {gsub(/^\||.\b/, ""); $1=$1; print}'
Awk命令删除\b
默认输出的基于隐藏html2text
的(基于退格的)序列,并按|
将行解析为字段,然后输出空格作为分隔符(空格是Awk的默认输出字段分隔符;例如,要将其更改为选项卡,请使用-v OFS='\t'
)。
注意:使用-nobs
来抑制源位置的退格序列不是选项,因为您无法区分隐藏的 - 用于填充的默认_
个实例和数据中的实际_
个字符。
注意:鉴于html2text
似乎总是使用|
作为列分隔符,如果数据中没有|
个实例,上述内容将只能有效运行被提取。
答案 5 :(得分:0)
您可以使用Ex editor(Vim的一部分)通过删除HTML标记来解析文件,例如:
$ ex -s +'%s/<[^>]\+>/ /g' +'v/0/d' +'wq! /dev/stdout' table.html
SAVE_DOCUMENT OK 0.406 s
GET_DOCUMENT OK 0.332 s
DVK_SEND OK 0.001 s
DVK_RECEIVE OK 0.001 s
GET_USER_INFO OK 0.143 s
NOTIFICATIONS OK 0.001 s
ERROR_LOG OK 0.001 s
SUMMARY_STATUS OK 0.888 s
这是通过在没有HTML标签的情况下打印整个文件的较短版本:
$ ex +'%s/<[^>]\+>/ /g|%p' -scq! table.html
说明:
%s/<[^>]\+>/ /g
- S 将所有HTML标记转换为空白区域。v/0/d
- D 排除所有没有0
的行。wq! /dev/stdout
- Q uits编辑器, w 将缓冲区用于标准输出。