Как я могу извлечь HTML-контент на странице по идентификатору?
Я пытался исследовать решения sed/grep в течение часа. Ни один не работал. Затем я сдался и изучил парсеры HTML/XML. html-xml-utils может получить элемент только по классу, а не по идентификатору, что делает его совершенно бесполезным. Я проконсультировался с руководством, и кажется, что нет никакого способа получить id.
xmlstarlet казался более многообещающим, но он скулит, когда я пытаюсь передать ему HTML-файлы, а не XML-файлы. Следующее выдает не менее 100 ошибок:
cat /home/com/interlinked/blog.html | tail -n +2 | xmlstarlet sel -T -t -m '/div/article[@id = "post33"]' -v '.' -n
Я использовал здесь кошку, потому что не хочу изменять фактический файл. Я использовал tail, чтобы вырезать объявление DOCTYPE, которое раньше вызывало проблемы: Extra content at the end of the document
Контент на странице хорошо отформатирован и составлен. Контент выглядит так:
<article id = "post44">
... more HTML tags and content here...
</article>
Я хотел бы иметь возможность извлекать все между конкретными тегами статьи здесь по идентификатору (например, если я передам ему «44», он вернет содержимое post44, если я передам его 34, он вернет содержимое post34).
Что отличает это от других вопросов, так это то, что мне нет нужен только контент, я хочу фактический HTML между тегами статьи. Мне не нужны сами теги статьи, хотя их удаление, вероятно, тривиально.
Есть ли способ сделать это с помощью встроенных инструментов Unix, xmlstarlet или html-xml-utils? Я также попробовал следующий sed, который также не сработал:
article=`patt=$(printf 'article id = "post%d"' $1); sed -n '/<$patt>/,/</article>/{ /article>/d; p }' $file`
Здесь я передаю путь к файлу как $file, а $1 — это идентификатор сообщения в блоге (44 или 34 или что-то еще). Причина двух операторов в одном заключается в том, что $1 не оценивается в операторе sed иначе из-за одинарных кавычек. Это помогает разрешать переменную в связанной команде grep, но не в этой команде sed.
Полная структура HTML:
<!doctype html>
<html lang = "en">
<head>
<title>Page</title>
</head>
<body>
<header>
<nav>
<div id = "sitelogo">
<a href = "/"><img src = "/img/logo/logo.png" alt = "InterLinked"></img></a>
</div>
<ul>
<p>Menu</p>
</ul>
</nav>
<hr>
</header>
<div id = "main">
<h1>Blog</h1>
<div id = "bloglisting">
<article id = "post44">
<p>Content</p>
</article>
<article id = "post43">
</p>Content</p>
</article>
</div>
</div>
</body>
</html>
Кроме того, чтобы уточнить, мне нужно, чтобы это работало на 2 разных страницах. Некоторые сообщения встроены в эту главную страницу, но у более длинных есть собственная страница. Структура похожа, но не совсем та же. Мне нужно решение, которое просто находит идентификатор и не нужно беспокоиться о родительских тегах, если это возможно. Сами теги статьи форматируются одинаково на обоих типах страниц. Например, в более длинном сообщении в блоге с собственной страницей отличие здесь:
<div id = "main">
<h1>Why Ridesharing Is Evil</h1>
<div id = "blogpost">
<article id = "post43">
<div>
В этом случае div bloglisting становится blogpost. Это действительно единственная большая разница.





Вы можете использовать инструменты libxml2 для правильного разбора HTML/XML с правильным пониманием синтаксиса. В вашем случае вы можете использовать xmllint и попросить его проанализировать HTML-файл с флагом --html и предоставить запрос xpath с верхнего уровня, чтобы получить узел по вашему выбору.
Например, чтобы получить содержимое для идентификатора сообщения post43 используйте фильтр, например
xmllint --html --xpath \
"//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='post43']" html
Если xmllint, скомпилированный на вашем компьютере, не понимает несколько последних (HTML5) тегов, таких как <article> или <nav>, отключите предупреждения, добавив 2>/dev/null в конце команды.
Если вы хотите получить только содержимое внутри <article> и не иметь самих тегов, удалите первую и последнюю строку, передав результат в sed, как показано ниже.
xmllint --html --xpath \
"//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='post43']" html 2>/dev/null |
sed '1d; $d'
Чтобы использовать переменную для пост-идентификатора, определите переменную оболочки и используйте ее в запросе xpath.
postID = "post43"
xmllint --html --xpath \
"//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='"$postID"']" html 2>/dev/null |
sed '1d; $d'