【问题标题】:How to get absolute URLs in Bash如何在 Bash 中获取绝对 URL
【发布时间】:2013-07-01 05:58:51
【问题描述】:

我想从 Bash 中的特定页面获取所有 URL。

这个问题已经在这里解决了:Easiest way to extract the urls from an html page using sed or awk only

然而,诀窍是将相对链接解析为绝对链接。所以如果http://example.com/ 包含如下链接:

<a href="/about.html">About us</a>
<script type="text/javascript" src="media/blah.js"></a>

我希望结果具有以下形式:

http://example.com/about.html
http://example.com/media/blah.js

如何在尽可能少的依赖下做到这一点?

【问题讨论】:

  • 上面的例子是不是有点不一致? (观察发布的链接和所需的转化。)
  • 你是对的,修复它。谢谢!

标签: html bash html-parsing


【解决方案1】:

简单地说,没有简单的解决方案。依赖很少会导致代码难看,反之亦然:代码健壮性会导致更高的依赖要求。

考虑到这一点,下面我将描述一些解决方案,并通过提供每个解决方案的优缺点来总结它们。

方法 1

您可以将wget-k 选项与一些正则表达式一起使用(阅读有关parsing HTML that way 的更多信息)。

来自 Linux 手册:

-k
--convert-links
    After the download is complete, convert the links in the document to 
    make them suitable for local viewing.  
    (...)
    The links to files that have not been downloaded by Wget will be 
    changed to include host name and absolute path of the location they 
    point to.
    Example: if the downloaded file /foo/doc.html links to /bar/img.gif
    (or to ../bar/img.gif), then the link in doc.html will be modified to
    point to http://hostname/bar/img.gif.

一个示例脚本:

#wget needs a file in order for -k to work
tmpfil=$(mktemp);

#-k - convert links
#-q - suppress output
#-O - redirect output to given file
wget http://example.com -k -q -O "$tmpfil";

#-o - print only matching parts
#you could use any other popular regex here
grep -o "http://[^'\"<>]*" "$tmpfil"

#remove unnecessary file
rm "$tmpfil"

优点:

  1. 假设您已安装 wget,可在大多数系统上开箱即用。
  2. 在大多数情况下,这将是足够的解决方案。

缺点:

  1. 具有正则表达式,由于 HTML 分层模型位于 Chomsky hierarchy 中的正则表达式下方,因此在某些特殊页面上必然会中断。
  2. 您无法传递本地文件系统中的位置;您必须传递有效的 URL。

方法2

您可以将 Python 与 BeautifulSoup 一起使用。示例脚本:

#!/usr/bin/python
import sys
import urllib
import urlparse
import BeautifulSoup

if len(sys.argv) <= 1:
    print >>sys.stderr, 'Missing URL argument'
    sys.exit(1)

content = urllib.urlopen(sys.argv[1]).read()
soup = BeautifulSoup.BeautifulSoup(content)
for anchor in soup.findAll('a', href=True):
    print urlparse.urljoin(sys.argv[1], anchor.get('href'))

然后:

dummy:~$ ./test.py http://example.com

优点:

  1. 这是处理 HTML 的正确方法,因为它正确使用了成熟的解析器。
  2. 外来输出很可能会得到很好的处理。
  3. 稍作修改后,此方法适用于文件,而不仅仅适用于 URL。
  4. 稍作修改,您甚至可以提供自己的基本 URL。

缺点:

  1. 它需要 Python。
  2. 它需要带有自定义包的 Python。
  3. 您需要手动处理标签和属性,例如&lt;img src&gt;&lt;link src&gt;&lt;script src&gt; 等(上面的脚本中没有显示)。

方法 3

您可以使用lynx 的一些功能。 (您在问题中提供的答案中提到了这一点。)示例:

lynx http://example.com/ -dump -listonly -nonumbers

优点:

  1. 非常简洁的用法。
  2. 适用于所有类型的 HTML。

缺点:

  1. 你需要 Lynx。
  2. 虽然您也可以从文件中提取链接,但您无法控制基本 URL,最终会得到 file://localhost/ 链接。您可以使用丑陋的技巧来解决此问题,例如手动将 &lt;base href=""&gt; 标记插入 HTML。

【讨论】:

    【解决方案2】:

    另一个选项是我的Xidel (XQuery/Webscraper)

    对于所有普通链接:

    xidel http://example.com/ -e '//a/resolve-uri(@href)'
    

    对于所有链接和src:

    xidel http://example.com/ -e '(//@href, //@src)/resolve-uri(.)'
    

    用rr-的格式:

    优点:

    1. 非常简洁的用法。

    2. 适用于所有类型的 HTML。

    3. 这是处理 HTML 的正确方法,因为它正确使用了成熟的解析器。

    4. 适用于文件和网址

    5. 您可以提供自己的基本 URL。 (resolve-uri(@href, "baseurl")

    6. 除了 Xidel 没有依赖(除了 openssl,如果你也有 https url)

    缺点:

    1. 您需要 Xidel,它不包含在任何标准存储库中

    【讨论】:

      【解决方案3】:

      为什么不简单呢?

      re='(src|href)='
      baseurl='example.com'
      wget -O- "http://$baseurl" | awk -F'(src|href)=' -F\" "/$re/{print $baseurl\$2}"
      

      您只需要

      如果您同时拥有相对网址和绝对网址,请随意改进 sn-p。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-19
        • 2011-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-10
        • 1970-01-01
        相关资源
        最近更新 更多