Как извлечь данные из таблицы html в оболочке script?
Я пытаюсь создать BASH script, что бы извлечь данные из таблицы 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 script выводил его так:
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 с помощью grep "<tr><td>
, поэтому для следующего синтаксического анализа (sed) будут выбраны только строки, начинающиеся с <tr><td>
.
Это то, что я использовал: sed '[email protected]<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\[email protected]'
Но тогда теги <tr>
все еще остаются, и также он не будет разделять строки. Другими словами, результатом этого script является:
<tr>SAVE_DOCUMENTOK0.406 s</tr>
Полную команду script, над которой я работаю:
cat $FILENAME | grep "<tr><td>" | sed '[email protected]<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\[email protected]'
Ответы
Ответ 1
Перейдите с (g)awk
, он способен:-), вот решение, но учтите: он работает только с точным форматом html-таблицы, который вы разместили.
awk -F "</*td>|</*tr>" '/<\/*t[rd]>.*[A-Z][A-Z]/ {print $3, $5, $7 }' FILE
Здесь вы можете увидеть его в действии: https://ideone.com/zGfLe
Некоторое объяснение:
-
-F
устанавливает разделитель полей ввода в regexp (любой из tr
или td
открывающего или закрывающего тега
-
затем работает только в строках, соответствующих этим тегам, и по крайней мере два поля upercasse
-
затем распечатает необходимые поля.
НТН
Ответ 2
Вы можете использовать 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'
Ответ 3
Вы можете использовать команду 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
).
Если вы хотите сначала отсортировать его, вы можете использовать ex
, см. пример здесь или здесь.
Ответ 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, как известно, поставляется в очень специфическом формате. Если будет вариация, вам будет лучше с помощью реального парсера HTML в Perl, Ruby, Python или даже C.
Ответ 5
Решение на основе многоплатформенного 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
, по-видимому, неизменно использует |
в качестве разделителя столбцов, приведенное выше будет работать только с уверенностью, если экземпляры no |
в извлекаемых данных.
Ответ 6
Вы можете проанализировать файл, используя редактор Ex (часть 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 обменивает буфер на стандартный вывод.