【问题标题】:Extract part of the code and parse HTML in bash提取部分代码并在 bash 中解析 HTML
【发布时间】:2017-04-21 10:52:10
【问题描述】:

我有外部 HTML 站点,我需要从该站点上的表中提取数据。但是HTML网站的源除了代码中的表格之外格式错误,所以我不能使用

xmllint --html --xpath <xpath> <file>

因为它不能正常工作,当网站上的 HTML 格式被破坏时。

我的想法是使用 curl 并删除表格上方和下方的代码。提取表格后,代码很干净,适合 xmllint 工具(我可以使用 xpath)。但是,删除匹配项之上的所有内容对 shell 来说具有挑战性,如您在此处看到的:Sed doesn't backtrack: once it's processed a line, it's done. 有没有办法只从 bash 中的 HTML 站点中提取表格的代码?假设,代码具有这种结构。

<html>
<head>
</head>
<body>
<p>Lorem ipsum ....</p>
  <table class="my-table">
    <tr>
      <th>Company</th>
      <th>Contact</th>
    </tr>
  </table>
<p>... dolor.</p>
</body>
</html>

我需要这样的输出来正确解析数据:

  <table class="my-table">
    <tr>
      <th>Company</th>
      <th>Contact</th>
    </tr>
  </table>

请不要因为尝试使用 bash 而给我减号。

【问题讨论】:

  • 你试过用 HTML-Tidy 清理 HTML html-tidy.org
  • 我尝试了“tidy -ashtml page.html -output page2.html”,但不幸的是它返回“此文档有错误,必须在使用 HTML Tidy 生成整理后的版本之前修复。”它需要是全自动的。不管怎样,谢谢。 @Dan-Dev
  • @Dan-Dev 非常感谢,毕竟 tidy 帮了大忙。我使用了 force-output,然后 xmllint 可以读取 html 文件。

标签: bash sed html-parsing


【解决方案1】:

我将分解我尝试使用xmllint 的答案,它支持--html 标志来解析html 文件

首先,您可以通过如下解析来检查您的 HTML 文件的完整性,确认文件是否符合标准,或者在看到时抛出错误:-

$ xmllint --html YourHTML.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
</head>
<body>
<p>Lorem ipsum ....</p>
  <table class="my-table">
    <tr>
      <th>Company</th>
      <th>Contact</th>
    </tr>
  </table>
<p>... dolor.</p>
</body>
</html>

我原来的 YourHTML.html 文件只是您问题中的输入 HTML 文件。

现在是值提取部分:-

开始从根节点解析文件到table 节点 (//html/body/table) 并在 HTML 解析器和交互式 shell 模式下运行 xmllint (xmllint --html --shell)

简单地运行命令会产生结果,

$ echo "cat //html/body/table" |  xmllint --html --shell YourHTML.html
/ >  -------
<table class="my-table">
    <tr>
      <th>Company</th>
      <th>Contact</th>
    </tr>
  </table>
/ > 

现在使用sed 删除特殊字符,即sed '/^\/ &gt;/d' 产生

$ echo "cat //html/body/table" |  xmllint --html --shell YourHTML.html | sed '/^\/ >/d'
<table class="my-table">
    <tr>
      <th>Company</th>
      <th>Contact</th>
    </tr>
  </table>

这是您所期望的输出结构。测试于xmllint: using libxml version 20900

我会更进一步,如果你想获取table标签内的值,你可以应用sed命令将它们提取为

$ echo "cat //html/body/table" |  xmllint --html --shell YourHTML.html | sed '/^\/ >/d' | sed 's/<[^>]*.//g' | xargs
Company Contact

【讨论】:

  • 当 HTML 有效且未损坏时,此代码可以完美运行。但我不能在我的情况下应用它(抱歉简化了误导性示例)。显然,很多网页没有有效的 html 代码,所以它不允许我从它们中解析数据。假设,只有有效的代码在表内。不幸的是,我必须承认,bash 并不适合提取网页上不符合 W3C 标准的部分代码。您知道如何以不同的方式提取表格吗?
  • 我毕竟发现,这个解决方案与@Dan-Dev 建议完美配合使用 tidy 选项 force-output: yes
  • xmllint 对现实世界的 html 毫无用处。它会在大多数网站上失败
【解决方案2】:

为了您的目的,一个快速的解决方案是 1-liner:

sed -n '/<table class="my-table">/,/<\/table>/p'  <file>

说明: 打印两个指定标签之间的所有内容,在本例中为 &lt;table&gt;

您还可以轻松地为 &lt;body&gt;&lt;p&gt; 创建一个标签变量,并即时更改输出。但上述解决方案无需外部工具即可满足您的要求。

【讨论】:

  • sed 不是bash% bash type sed -> sed is /usr/bin/sed
猜你喜欢
  • 2014-04-24
  • 2021-10-07
  • 1970-01-01
  • 2011-02-04
  • 2016-12-12
  • 1970-01-01
  • 2011-06-23
  • 2017-06-02
  • 2017-05-18
相关资源
最近更新 更多