如何在Bash中获取绝对URL

时间:2013-06-30 19:50:15

标签: html bash html-parsing

我希望从Bash中的特定页面获取所有网址。

此问题已在此处解决: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

如何尽可能减少依赖?

3 个答案:

答案 0 :(得分:7)

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

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

方法1

您可以将wget的{​​{1}}选项与一些正则表达式一起使用(了解有关parsing HTML that way的更多信息)。

来自Linux手册:

-k

示例脚本:

-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.

优点:

  1. 假设您安装了#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" ,大多数系统都可以开箱即用。
  2. 在大多数情况下,这将是足够的解决方案。
  3. 缺点:

    1. 功能正则表达式,由于HTML层次模型位于Chomsky hierarchy中的正则表达式下方,因此在某些异域页面上会出现中断。
    2. 您无法在本地文件系统中传递位置;你必须通过工作网址。

    3. 方法2

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

      wget

      然后:

      #!/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'))
      

      优点:

      1. 这是处理HTML的正确方法,因为它正确使用了完全成熟的解析器。
      2. 异乎寻常的输出很可能会得到很好的处理。
      3. 通过少量修改,此方法适用于文件,而不仅适用于网址。
      4. 只需稍加修改,您甚至可以提供自己的基本网址。
      5. 缺点:

        1. 它需要Python。
        2. 它需要Python和自定义包。
        3. 您需要手动处理标记和属性,例如dummy:~$ ./test.py http://example.com <img src><link src>等(上面的脚本中未显示)。

        4. 方法3

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

          lynx

          优点:

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

            1. 你需要Lynx。
            2. 虽然您也可以从文件中提取链接,但您无法控制基本网址,最终会获得lynx http://example.com/ -dump -listonly -nonumbers 个链接。您可以使用丑陋的黑客来解决此问题,例如手动将file://localhost/标记插入HTML。

答案 1 :(得分:3)

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

对于所有普通链接:

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

对于所有链接和srcs:

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

使用rr-格式:

优点:

  1. 使用非常简洁。

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

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

  4. 适用于文件和网址

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

  6. 除了Xidel之外没有任何依赖(除了openssl,如果你还有https网址)

  7. 缺点:

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

答案 2 :(得分:1)

为什么不简单呢?

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

您只需要

如果你有亲戚和朋友,请随意改善一下片段。绝对的网址同时。