Как извлечь данные из HTML-таблицы в сценарии оболочки? - PullRequest
11 голосов
/ 28 июля 2011

Я пытаюсь создать скрипт BASH, который бы извлекал данные из таблицы 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, используя grep "<tr><td>, поэтому для следующего анализа (sed) будут выбраны только строки, начинающиеся с <tr><td>.Вот что я использовал: sed 's@<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\2@g' Но тогда теги <tr> все еще остаются, и они не разделяют строки.Другими словами, результат этого сценария:

<tr>SAVE_DOCUMENTOK0.406 s</tr>

Полная команда сценария, над которым я работаю:

cat $FILENAME | grep "<tr><td>" | sed 's@<\([^<>][^<>]*\)>\([^<>]*\)</\1>@\2@g'

Ответы [ 6 ]

13 голосов
/ 28 июля 2011

Используйте (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. затем работает только со строками, соответствующими этим тегам И, по крайней мере, в двух полях верхнего уровня

  3. затем печатает необходимые поля.

НТН

11 голосов
/ 28 июля 2011

Вы можете использовать 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'
5 голосов
/ 10 октября 2015

Вы можете использовать команду 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, см. Пример здесь или здесь .

5 голосов
/ 28 июля 2011

Есть много способов сделать это, но вот один:

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.

1 голос
/ 11 июля 2017

Решение, основанное на многоплатформенном 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 (на основе backspace), которые html2text выводит по умолчанию, и анализирует строки в поля на |, а затем выводит их с пробелом в качестве разделителя ( пробел является стандартным разделителем выходных полей в Awk, например, чтобы изменить его на вкладку, используйте -v OFS='\t').

Примечание. Использование -nobs для подавления последовательностей возврата в исходном коде - это , а не вариант, поскольку в этом случае вы не сможете различать скрытые по умолчанию _ экземпляры, используемые для заполнения и фактические _ символов в данных.

Примечание: учитывая, что html2text, по-видимому, неизменно использует | в качестве разделителя столбцов, выше будет работать надежно, только если нет | экземпляров в данных , которые извлекаются .

0 голосов
/ 16 сентября 2017

Вы можете проанализировать файл, используя 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 переводит буфер в стандартный вывод.
...