0

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

这个问题已经在这里解决了:Easest 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

我怎样才能以尽可能少的依赖项做到这一点?

4

3 回答 3

7

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

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

方法一

您可以将wget'-k选项与一些正则表达式一起使用(阅读有关以这种方式解析 HTML 的更多信息)。

来自 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 层次结构中的正则表达式之下,因此必然会在一些奇异的页面上中断。
  2. 您不能传递本地文件系统中的位置;您必须传递工作 URL。

方法二

您可以将 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. 您需要手动处理标签和属性,如,<img src>等(上面的脚本中没有显示)。<link src><script src>

方法 3

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

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

优点:

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

缺点:

  1. 你需要猞猁。
  2. 尽管您也可以从文件中提取链接,但您无法控制基本 URL,最终会得到file://localhost/链接。您可以使用丑陋的技巧来解决此问题,例如手动将<base href="">标签插入 HTML。
于 2013-06-30T19:50:15.010 回答
3

另一个选择是我的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,它不包含在任何标准存储库中
于 2013-06-30T21:26:47.390 回答
1

为什么不简单地这样做呢?

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

你只需要

如果您同时拥有相对和绝对网址,请随意改进代码段。

于 2013-06-30T21:58:51.153 回答