如何通过ID提取HTML标签?

时间:2019-07-12 14:21:31

标签: bash sed html-parsing

如何通过ID提取页面上的HTML内容?

我尝试探索sed / grep解决方案一个小时。没有工作。 然后,我放弃并探索了HTML / XML解析器。 html-xml-utils只能按类获取元素,而不能按ID获取元素,从而使其完全无用。我查阅了手册,似乎没有办法获取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

我在这里使用cat是因为我不想修改实际文件。我用tail剪切了DOCTYPE声明,该声明似乎导致了更早的问题:Extra content at the end of the document

页面上的内容格式正确且包含内容。内容如下:

<article id="post44">
    ... more HTML tags and content here...
</article>

我希望能够通过ID在此处提取特定文章标签之间的所有内容(例如,如果我将其传递为“ 44”,它将返回post44的内容,如果我将其传递为34,它将返回内容的44) 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是博客文章ID(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个不同的页面上使用它。主页上有一些内联帖子,而较长的帖子则有自己的页面。结构相似,但不完全相同。我想要一个解决方案,它可以找到ID,并且不必担心父标记(如果可能)。文章标签本身在两种页面上的格式都相同。例如,在较长的博客文章中有自己的页面,不同之处在这里:

<div id="main">
        <h1>Why Ridesharing Is Evil</h1>
        <div id="blogpost">
            <article id="post43">
                <div>

在这种情况下,div博客列表成为博客文章。这确实是唯一的大区别。

1 个答案:

答案 0 :(得分:1)

您可以使用libxml2工具以适当的语法意识正确地解析HTML / XML。对于您的情况,可以使用xmllint并要求其解析带有标志--html的HTML文件,并从顶层提供一个xpath查询以获取您选择的节点。

例如要获取帖子ID 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'

要将变量用于post-id,请定义一个shell变量,并在xpath查询中使用它

postID="post43"
xmllint --html --xpath \
   "//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='"$postID"']" html 2>/dev/null | 
   sed '1d; $d'