Как извлечь данные из таблицы 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 обменивает буфер на стандартный вывод.