首页 > 解决方案 > 如何通过 ID 提取 HTML 标签?

问题描述

如何按 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,它将返回 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 bloglisting 变成了 blogpost。这真的是唯一的大区别。

标签: bashsedhtml-parsing

解决方案


您可以使用这些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>or ,请通过在命令末尾<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'

推荐阅读