简单地说,没有简单的解决方案。依赖很少会导致代码难看,反之亦然:代码健壮性会导致更高的依赖要求。
考虑到这一点,下面我将描述一些解决方案,并通过提供每个解决方案的优缺点来总结它们。
方法 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"
优点:
- 假设您已安装
wget,可在大多数系统上开箱即用。
- 在大多数情况下,这将是足够的解决方案。
缺点:
- 具有正则表达式,由于 HTML 分层模型位于 Chomsky hierarchy 中的正则表达式下方,因此在某些特殊页面上必然会中断。
- 您无法传递本地文件系统中的位置;您必须传递有效的 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
优点:
- 这是处理 HTML 的正确方法,因为它正确使用了成熟的解析器。
- 外来输出很可能会得到很好的处理。
- 稍作修改后,此方法适用于文件,而不仅仅适用于 URL。
- 稍作修改,您甚至可以提供自己的基本 URL。
缺点:
- 它需要 Python。
- 它需要带有自定义包的 Python。
- 您需要手动处理标签和属性,例如
<img src>、<link src>、<script src> 等(上面的脚本中没有显示)。
方法 3
您可以使用lynx 的一些功能。 (您在问题中提供的答案中提到了这一点。)示例:
lynx http://example.com/ -dump -listonly -nonumbers
优点:
- 非常简洁的用法。
- 适用于所有类型的 HTML。
缺点:
- 你需要 Lynx。
- 虽然您也可以从文件中提取链接,但您无法控制基本 URL,最终会得到
file://localhost/ 链接。您可以使用丑陋的技巧来解决此问题,例如手动将 <base href=""> 标记插入 HTML。