Парсинг HTML в Bash
У меня есть процесс, в котором мне нужно скопировать все изображения с веб-страницы. Раньше я запускал этот процесс с помощью xmllint
, который будет обрабатывать файл XML или HTML и распечатывать указанные вами записи. Но когда мой хост-провайдер обновил свои системы, они не включили xmlint
. Поэтому мне пришлось найти другой способ извлечь список изображений из HTML-страницы. Оказывается, вы можете сделать это в Bash.
Вы можете не думать, что Bash может анализировать файлы данных, но это возможно, если подумать. Bash, как и другие оболочки UNIX до него, может анализировать строки из файла по одной за раз с помощью встроенного оператора read
.
По умолчанию оператор read
сканирует строку данных и разбивает ее на поля. Обычно read
разбивает поля с помощью пробелов и табуляции, при этом каждая строка заканчивается новой строкой, но вы можете изменить это поведение, установив значение внутреннего разделителя полей (IFS
) и конец- межстрочный разделитель (-d
).
Чтобы проанализировать файл HTML с помощью read
, установите для IFS
символ «больше» (>
), а в качестве разделителя — символ «меньше». (<
). Каждый раз, когда Bash сканирует строку, он выполняет синтаксический анализ до следующего <
(начало HTML-тега), а затем разбивает эти данные на каждый >
(конец HTML-тега). ). Этот пример кода принимает строку ввода и разбивает данные на переменные TAG
и VALUE
:
local IFS='>' read -d '<' TAG VALUE
Давайте посмотрим, как это работает. Рассмотрим этот простой файл HTML:
<img src="logo.png" alt="My logo" /> <p>some text</p>
При первом анализе read
этого файла он останавливается на первом символе <
. Поскольку <
является первым символом этого примера ввода, это означает, что Bash находит пустую строку. Результирующие строки TAG
и VALUE
также пусты. Но это нормально для моего варианта использования.
В следующий раз, когда Bash читает ввод, он получает img src=\logo.png\↲alt=\Мой логотип\ />↲
с новой строкой прямо перед alt и останавливается перед символ <
на следующей строке. Затем read
разделяет строку по символу >
, оставляя TAG
с img src=\logo.png\↲alt =\Мой логотип\ /
и VALUE
с пустой новой строкой.
В третий раз, когда read
анализирует файл HTML, он получает p>какой-то текст
. Bash разбивает строку на >
, в результате чего TAG
содержит p
и VALUE
с некоторым текстом
.
Теперь, когда вы понимаете, как использовать read
, легко проанализировать более длинный HTML-файл с помощью Bash. Начните с функции Bash с именем xmlgetnext
для анализа данных с помощью read
, так как вы будете делать это снова и снова в скрипте. Я назвал свою функцию xmlgetnext
, чтобы напомнить себе, что это замена программе Linux xmllint
, но я мог бы так же легко назвать ее htmlgetnext
.
xmlgetnext () { local IFS='>' read -d '<' TAG VALUE }
Теперь вызовите эту функцию xmlgetnext
для анализа HTML-файла. Это мой полный скрипт htmltags
:
#!/bin/sh # print a list of all html tags xmlgetnext () { local IFS='>' read -d '<' TAG VALUE } cat $1 | while xmlgetnext ; do echo $TAG ; done
Последняя строка является ключевой. Он перебирает файл с помощью xmlgetnext
для анализа HTML и выводит только записи TAG
. И из-за того, как echo
работает со стандартными разделителями полей, любые строки, такие как img src=\logo.png\↲alt=\My logo\ /
, которые содержать новую строку, которая будет напечатана в одной строке, как img src=\logo.png\ alt=\My logo\ /
.
Чтобы получить только список изображений, я запускаю выходные данные этого скрипта через grep
и печатаю только те строки, которые имеют тег img
в начале строки.