2011-07-28 622 views
9

我想創建一個BASH腳本,它將從HTML表中提取數據。 下面是桌子的距離,我需要提取數據的例子:如何從shell腳本中的html表中提取數據?

<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 '[email protected]<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\[email protected]' 但後來<tr>標籤仍然存在,也是它不會分開的字符串。換句話說這個腳本的結果是:

<tr>SAVE_DOCUMENTOK0.406 s</tr> 

我工作的腳本的完整命令是:

cat $FILENAME | grep "<tr><td>" | sed '[email protected]<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\[email protected]' 
+0

它是否必須是bash腳本?如果你在Linux上,也許一個Perl腳本將是一個更簡單的選擇。然後,您可以使用[HTML :: Parser](http://search.cpan.org/~gaas/HTML-Parser-3.68/Parser.pm)模塊或類似模塊。 – Mike

+0

必須是bash :) – Marko

回答

10

圍棋與(g)awk更好,它能夠:-),這裏是一個解決方案,但請注意:它只能使用您發佈的精確html表格格式。

awk -F "</*td>|</*tr>" '/<\/*t[rd]>.*[A-Z][A-Z]/ {print $3, $5, $7 }' FILE 

在這裏,你可以看到它在行動:https://ideone.com/zGfLe

一些解釋:

  1. -F輸入字段分隔符設置爲一個正則表達式(任何tr的或td的開放或者只在線路關閉標籤

  2. 即可工作,這些標籤和至少t匹配WO upercasse字段

  3. 然後打印所需的字段。

HTH

+0

精湛的解釋!萬分感謝! – Marko

+0

如何編輯輸出更多?例如,如果我希望輸出如下所示:SAVE_DOCUMENT =「OK 0.475 s」 GET_DOCUMENT =「OK 0.345 s」 DVK_SEND =「OK 0.002 s」 – Marko

+0

只需更換'{print $ 3,$ 5,$ 7}'部分與'{打印$ 3「= \」「$ 5,$ 7」\「」}' HTH –

4

有很多的這樣做的方法,但這裏有一個:

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一塊一塊分開,而不是試圖用正則表達式語法的一個難以理解的一堆做的一次。

解析HTML用一個管道是不是有史以來最好的想法,但你可以做到這一點,如果HTML被稱爲進來一個非常特定的格式。是否會有變化,然後你會用在Perl和Ruby,Python或甚至C.真正的HTML解析器

+0

也謝謝!也是很好的解釋,但Zsolt Botykai解決方案看起來更酷:) – Marko

+1

@Marko:是的,awk是這類事情的一個更好的工具,比sed更一致的正則表達式處理。 –

10

您可以使用bash xpathXML :: 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' 
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  

然後從那裏進一步解析它(例如, cutawkex)。

如果您想先排序,可以使用ex,請參閱示例herehere

+1

不幸的是,'html2text'默認使用退格字符來輸出它的輸出,所以即使你的輸出_looks_ OK,隱藏'\ b'(退格)序列。安全地刪除它們需要更多的工作(使用'-nobs'不是一種選擇,因爲它會顯示用於填充的隱藏'_'實例,這些實例很難與_data_中的'_'實例區分開來)。 – mklement0

0

基於多平臺web的刮CLI xidelXQuery A液:

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, " ")在循環中處理以第二個(position()>1,跳過標題行)開頭的tr元素,並將子元素($tr/td)的值與單個空格作爲分隔符進行連接。

  • -s使xidel無聲(禁止輸出狀態信息)。


雖然html2text方便顯示所提取的數據的提供計算機可解析的輸出是不平凡的,不幸的是:

html2text file | awk -F' *\\|' 'NR>2 {gsub(/^\||.\b/, ""); $1=$1; print}' 

awk的命令除去html2text默認輸出的基於隱藏的\b(基於退格的)序列,以及pa通過|將行劃分到字段中,然後使用空格作爲分隔符輸出它們(空格是Awk的默認輸出字段分隔符;將其更改爲選項卡,例如,使用-v OFS='\t')。

注:使用-nobs,從源頭上抑制退格序列是一種選擇,因爲你那麼將無法使用填充用隱藏的默認_實例和實際_字符來區分在數據中。

注:鑑於html2text看似不變地使用|作爲列隔板,上述將僅魯棒地工作,如果是在數據沒有|情況下被提取的

0

您可以通過刪除HTML標籤,比如解析使用Ex editor(VIM的一部分)的文件:

$ 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 editor和w將標準輸出的緩衝區標準化。
相關問題