Python中相当于wget的下载网站及资源的工具

6 投票
2 回答
9089 浏览
提问于 2025-04-17 12:43

2.5年前在用Python下载网页及其所有资源文件这个问题上也有人问过类似的事情,但没有得到答案,而且“请查看相关主题”其实并不是在问同样的问题。

我想下载一个页面上的所有内容,这样就可以仅通过文件来查看它。

这个命令

wget --page-requisites --domains=DOMAIN --no-parent --html-extension --convert-links --restrict-file-names=windows

正好满足我的需求。不过我们希望能把它和其他需要便携的东西结合起来,所以需要用Python来实现。

我一直在研究Beautiful Soup、scrapy,还有一些网上发布的爬虫,但这些工具似乎都是以聪明但特定的方式来获取数据或链接。用它们来实现我想要的功能,感觉会需要花很多功夫去找所有的资源,我相信一定有更简单的方法。

非常感谢!

2 个回答

2

我的同事写了这段代码,很多部分是从其他地方拼凑过来的。我觉得可能有些特别的地方是为了我们自己的系统,但这段代码应该能帮助任何想做同样事情的人。

"""
    Downloads all links from a specified location and saves to machine.
    Downloaded links will only be of a lower level then links specified.
    To use: python downloader.py link
"""
import sys,re,os,urllib2,urllib,urlparse
tocrawl = set([sys.argv[1]])
# linkregex = re.compile('<a\s*href=[\'|"](.*?)[\'"].*?')
linkregex = re.compile('href=[\'|"](.*?)[\'"].*?')
linksrc = re.compile('src=[\'|"](.*?)[\'"].*?')
def main():
    link_list = []##create a list of all found links so there are no duplicates
    restrict = sys.argv[1]##used to restrict found links to only have lower level
    link_list.append(restrict)
    parent_folder = restrict.rfind('/', 0, len(restrict)-1)
    ##a.com/b/c/d/ make /d/ as parent folder
    while 1:
        try:
            crawling = tocrawl.pop()
            #print crawling
        except KeyError:
            break
        url = urlparse.urlparse(crawling)##splits url into sections
        try:
            response = urllib2.urlopen(crawling)##try to open the url
        except:
            continue
        msg = response.read()##save source of url
        links = linkregex.findall(msg)##search for all href in source
        links = links + linksrc.findall(msg)##search for all src in source
        for link in (links.pop(0) for _ in xrange(len(links))):
            if link.startswith('/'):
                ##if /xxx a.com/b/c/ -> a.com/b/c/xxx
                link = 'http://' + url[1] + link
            elif ~link.find('#'):
                continue
            elif link.startswith('../'):
                if link.find('../../'):##only use links that are max 1 level above reference
                    ##if ../xxx.html a.com/b/c/d.html -> a.com/b/xxx.html
                    parent_pos = url[2].rfind('/')
                    parent_pos = url[2].rfind('/', 0, parent_pos-2) + 1
                    parent_url = url[2][:parent_pos]
                    new_link = link.find('/')+1
                    link = link[new_link:]
                    link = 'http://' + url[1] + parent_url + link
                else:
                    continue
            elif not link.startswith('http'):
                if url[2].find('.html'):
                    ##if xxx.html a.com/b/c/d.html -> a.com/b/c/xxx.html
                    a = url[2].rfind('/')+1
                    parent = url[2][:a]
                    link = 'http://' + url[1] + parent + link
                else:
                    ##if xxx.html a.com/b/c/ -> a.com/b/c/xxx.html
                    link = 'http://' + url[1] + url[2] + link
            if link not in link_list:
                link_list.append(link)##add link to list of already found links
                if (~link.find(restrict)):
                ##only grab links which are below input site
                    print link ##print downloaded link
                    tocrawl.add(link)##add link to pending view links
                    file_name = link[parent_folder+1:]##folder structure for files to be saved
                    filename = file_name.rfind('/')
                    folder = file_name[:filename]##creates folder names
                    folder = os.path.abspath(folder)##creates folder path
                    if not os.path.exists(folder):
                        os.makedirs(folder)##make folder if it does not exist
                    try:
                        urllib.urlretrieve(link, file_name)##download the link
                    except:
                        print "could not download %s"%link
                else:
                    continue
if __name__ == "__main__":
    main()

谢谢大家的回复。

3

你应该使用合适的工具来完成手头的工作。

如果你想抓取一个网站并把页面保存到电脑上,Python可能不是最好的选择。开源项目通常是在有人需要某个功能时才会添加这个功能,而因为wget这个工具做得非常好,所以没有人去费心写一个Python库来替代它。

考虑到wget几乎可以在任何有Python解释器的平台上运行,你有没有什么理由不能使用wget呢?

撰写回答