下载HTML页面及其内容

61

在给定URL的情况下,Python是否有下载整个HTML页面及其内容(如图片、CSS)到本地文件夹的方法?并更新本地HTML文件以从本地获取内容。


可能是如何使用Python程序下载完整网页?的重复问题。 - imbr
我猜这是最佳答案。 - imbr
4个回答

44
你可以使用 urllib 模块下载单个URL,但这只会返回数据。它不会解析HTML并自动下载像CSS文件和图像这样的东西。
如果你想要下载“整个”页面,你需要解析HTML并找到其他需要下载的东西。你可以使用类似 Beautiful Soup 这样的工具来解析所检索的HTML。 这个问题 包含了一些能够做到这一点的示例代码。

13

你可以使用urllib:

import urllib.request

opener = urllib.request.FancyURLopener({})
url = "http://stackoverflow.com/"
f = opener.open(url)
content = f.read()

4
这似乎只考虑了HTTP响应代码来下载页面,除非我漏掉了什么,否则它实际上并没有下载页面资源。 - bdeniker
1
很不幸,这已经过时了: DeprecationWarning:FancyURLopener调用请求的方式已过时。请使用更新的urlopen函数/方法 - rien333
1
FancyURLopener对我来说也已经过时了。谷歌带我找到了这个答案:https://dev59.com/67Hma4cB1Zd3GeqPIDn0#54261548 - Jesus is Lord
1
FancyURLopener对我来说已经过时了。谷歌带我去了这个答案:https://stackoverflow.com/a/54261548/569302 - undefined

11
你需要的是镜像工具。如果你想要一个Python版本的,PyPI上列出了spider.py,但我没有使用过它。其他工具可能更好,但我不知道 - 我使用'wget',它支持获取CSS和图片。这可能可以实现你想要的效果(引自手册)。

仅检索一个HTML页面,但确保所有需要显示页面的元素,例如内联图像和外部样式表,也被下载。还要确保下载的页面引用已下载的链接。

wget -p --convert-links http://www.server.com/dir/page.html

11

下面是savePage函数的功能:

  • 根据tags_inner字典的键,保存 .html 以及下载的 javascriptscssimages,这些资源文件都基于 scriptlinkimg 标签。
  • 资源文件会被保存在带有后缀名为 _files 的文件夹中。
  • 任何异常情况都会打印到 sys.stderr 中。

该函数使用 Python 3+ 中的 RequestsBeautifulSoup 和其他标准库。

函数savePage接收一个urlpagepath作为参数,用来指定页面的保存位置。

你可以根据自己的需要扩展/调整它

import os, sys, re
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

def savePage(url, pagepath='page'):
    def savenRename(soup, pagefolder, session, url, tag, inner):
        if not os.path.exists(pagefolder): # create only once
            os.mkdir(pagefolder)
        for res in soup.findAll(tag):   # images, css, etc..
            if res.has_attr(inner): # check inner tag (file object) MUST exists  
                try:
                    filename, ext = os.path.splitext(os.path.basename(res[inner])) # get name and extension
                    filename = re.sub('\W+', '', filename) + ext # clean special chars from name
                    fileurl = urljoin(url, res.get(inner))
                    filepath = os.path.join(pagefolder, filename)
                    # rename html ref so can move html and folder of files anywhere
                    res[inner] = os.path.join(os.path.basename(pagefolder), filename)
                    if not os.path.isfile(filepath): # was not downloaded
                        with open(filepath, 'wb') as file:
                            filebin = session.get(fileurl)
                            file.write(filebin.content)
                except Exception as exc:
                    print(exc, file=sys.stderr)
    session = requests.Session()
    #... whatever other requests config you need here
    response = session.get(url)
    soup = BeautifulSoup(response.text, "html.parser")
    path, _ = os.path.splitext(pagepath)
    pagefolder = path+'_files' # page contents folder
    tags_inner = {'img': 'src', 'link': 'href', 'script': 'src'} # tag&inner tags to grab
    for tag, inner in tags_inner.items(): # saves resource files and rename refs
        savenRename(soup, pagefolder, session, url, tag, inner)
    with open(path+'.html', 'wb') as file: # saves modified html doc
        file.write(soup.prettify('utf-8'))

示例:将google.com保存为google.html,并将google_files文件夹中的内容保存在当前文件夹中。

savePage('https://www.google.com', 'google')

通过这个例子,我得到了“bs4.FeatureNotFound:找不到具有您请求的功能的树构建器:lxml。您需要安装解析器库吗?” - Wassadamo
1
@Wassadamo,你需要安装lxml包。但为了简化操作,我只是将soup = BeautifulSoup(response.text, "html.parser")中的“lxml”改为了“html.parser”。 - imbr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接