3行代码搞定网页资源下载:requests-html文件保存终极指南

3行代码搞定网页资源下载:requests-html文件保存终极指南

【免费下载链接】requests-html Pythonic HTML Parsing for Humans™ 【免费下载链接】requests-html 项目地址: https://gitcode.com/gh_mirrors/re/requests-html

你是否还在为网页资源下载写几十行代码?还在纠结相对路径处理、二进制流保存、异步下载等复杂问题?本文将带你用requests-html库的3个核心功能,轻松实现图片、文档、视频等各类资源的批量下载,让Python文件下载效率提升10倍。

为什么选择requests-html下载文件

requests-html作为"面向人类的Pythonic HTML解析库",在文件下载方面有三大优势:

  • 一体化流程:从网页请求、元素解析到资源下载全程无感知衔接
  • 智能路径处理:自动处理相对URL转换,无需手动拼接requests_html.py
  • 异步支持:原生支持异步下载,大幅提升多文件获取效率requests_html.py

项目官方文档详细说明了这些特性:docs/source/index.rst,而完整的实现逻辑可以在主模块中查看:requests_html.py

核心功能解析:3个关键方法

1. absolute_links:获取完整资源URL

在下载文件前,首先需要获取完整的资源链接。requests-html的absolute_links属性会自动将页面中的相对链接转换为绝对URL:

from requests_html import HTMLSession

session = HTMLSession()
r = session.get('https://example.com/gallery')
# 获取所有图片的绝对URL
image_urls = [img.attrs['src'] for img in r.html.find('img') if 'src' in img.attrs]
# 或者直接获取所有链接
all_links = r.html.absolute_links

这个功能的核心实现位于requests_html.pyabsolute_links方法,它通过_make_absolute函数处理各种URL情况:requests_html.py

2. HTMLSession:同步文件下载

获取资源URL后,使用HTMLSessionget方法即可下载文件。以下是一个完整的图片下载示例:

from requests_html import HTMLSession
import os

session = HTMLSession()
r = session.get('https://example.com/images')

# 创建保存目录
os.makedirs('downloads', exist_ok=True)

# 下载所有图片
for img in r.html.find('img'):
    try:
        img_url = img.attrs['src']
        # 获取图片响应
        img_response = session.get(img_url)
        # 提取文件名
        filename = os.path.basename(img_url)
        # 保存图片
        with open(f'downloads/{filename}', 'wb') as f:
            f.write(img_response.content)
        print(f"下载成功: {filename}")
    except Exception as e:
        print(f"下载失败: {e}")

这个过程中,session.get()方法返回的HTMLResponse对象包含了文件的二进制内容,通过content属性即可获取:requests_html.py

3. AsyncHTMLSession:异步批量下载

对于需要下载多个文件的场景,异步下载能显著提高效率。requests-html的AsyncHTMLSession完美支持这一需求:

from requests_html import AsyncHTMLSession
import os
import asyncio

async def download_file(session, url, save_path):
    try:
        response = await session.get(url)
        with open(save_path, 'wb') as f:
            f.write(response.content)
        return f"成功: {os.path.basename(save_path)}"
    except Exception as e:
        return f"失败: {url}, 错误: {e}"

async def main():
    session = AsyncHTMLSession()
    r = await session.get('https://example.com/documents')
    
    os.makedirs('pdf_downloads', exist_ok=True)
    
    # 获取所有PDF链接
    pdf_links = [link for link in r.html.absolute_links if link.endswith('.pdf')]
    
    # 创建下载任务
    tasks = []
    for url in pdf_links:
        filename = os.path.basename(url)
        tasks.append(download_file(session, url, f'pdf_downloads/{filename}'))
    
    # 执行所有任务
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result)

if __name__ == '__main__':
    session = AsyncHTMLSession()
    session.run(main)

异步功能的核心实现位于requests_html.pyarender方法,它使用了Python的asyncio库来处理并发请求。

实战案例:电商网站图片批量下载器

下面我们将综合运用上述功能,创建一个电商网站图片批量下载工具,支持按商品分类保存图片:

from requests_html import HTMLSession
import os
import re

def sanitize_filename(name):
    """清理文件名中的非法字符"""
    return re.sub(r'[\\/*?:"<>|]', '', name)

def download_product_images(category_url, save_dir='products'):
    session = HTMLSession()
    r = session.get(category_url)
    
    # 获取所有商品卡片
    products = r.html.find('.product-card')
    
    for product in products:
        try:
            # 获取商品名称
            name = product.find('.product-title', first=True).text
            sanitized_name = sanitize_filename(name)
            product_dir = os.path.join(save_dir, sanitized_name)
            os.makedirs(product_dir, exist_ok=True)
            
            # 获取商品图片
            images = product.find('.product-image img')
            for i, img in enumerate(images):
                if 'src' in img.attrs:
                    img_url = img.attrs['src']
                    # 处理可能的缩略图URL,获取原图
                    img_url = img_url.replace('thumb_', '')
                    
                    # 下载图片
                    img_response = session.get(img_url)
                    img_ext = os.path.splitext(img_url)[1] or '.jpg'
                    img_path = os.path.join(product_dir, f'image_{i}{img_ext}')
                    
                    with open(img_path, 'wb') as f:
                        f.write(img_response.content)
                    
                    print(f"已保存: {img_path}")
                    
        except Exception as e:
            print(f"处理商品时出错: {e}")
            continue

# 使用示例
if __name__ == '__main__':
    categories = {
        '手机': 'https://example.com/category/phones',
        '笔记本电脑': 'https://example.com/category/laptops',
        '智能手表': 'https://example.com/category/smartwatches'
    }
    
    for category, url in categories.items():
        print(f"===== 开始下载 {category} 图片 =====")
        download_product_images(url, save_dir=f'products/{category}')

这个案例展示了如何结合requests-html的选择器功能requests_html.py和文件下载功能,实现结构化的数据获取与保存。

高级技巧:自定义下载器配置

对于复杂的下载需求,我们可以扩展HTMLSession类,创建自定义下载器,添加超时控制、重试机制和进度显示:

from requests_html import HTMLSession
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import time
from tqdm import tqdm

class DownloadSession(HTMLSession):
    def __init__(self, retries=3, backoff_factor=0.3, timeout=10):
        super().__init__()
        # 配置重试策略
        retry_strategy = Retry(
            total=retries,
            backoff_factor=backoff_factor,
            status_forcelist=[429, 500, 502, 503, 504]
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self.mount("https://", adapter)
        self.mount("http://", adapter)
        self.timeout = timeout
        
    def download_with_progress(self, url, save_path):
        """带进度条的文件下载"""
        try:
            response = self.get(url, stream=True, timeout=self.timeout)
            total_size = int(response.headers.get('content-length', 0))
            
            with open(save_path, 'wb') as f, tqdm(
                desc=os.path.basename(save_path),
                total=total_size,
                unit='iB',
                unit_scale=True,
                unit_divisor=1024,
            ) as bar:
                for data in response.iter_content(chunk_size=1024):
                    size = f.write(data)
                    bar.update(size)
            return True
        except Exception as e:
            print(f"下载失败: {e}")
            return False

这个增强版下载器使用了requests的会话适配器功能,实现了网络错误自动重试,同时添加了进度条显示,让大文件下载过程更加可控。

常见问题解决方案

1. 处理JavaScript动态加载的资源

有些网站使用JavaScript动态加载图片等资源,这时需要使用requests-html的渲染功能:

r = session.get(url)
# 渲染JavaScript
r.html.render(scrolldown=3, sleep=1)  # 模拟滚动加载更多内容
# 之后再获取图片链接
images = r.html.find('img')

渲染功能的实现位于requests_html.pyrender方法,它使用Pyppeteer库来模拟浏览器行为。

2. 解决反爬限制

对于有反爬机制的网站,可以通过设置User-Agent和Cookie来绕过限制:

session = HTMLSession()
# 设置请求头
session.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Referer': 'https://www.google.com/'
})
# 添加Cookie
session.cookies.set('sessionid', 'your_session_id_here')

r = session.get(url)

3. 处理大型文件下载

对于GB级别的大型文件,建议使用流式下载,避免占用过多内存:

with session.get(large_file_url, stream=True) as r:
    with open('large_file.iso', 'wb') as f:
        for chunk in r.iter_content(chunk_size=8192): 
            if chunk:  # 过滤掉保持连接的空块
                f.write(chunk)
                f.flush()

性能优化指南

为了进一步提升下载效率,可以从以下几个方面进行优化:

1. 连接池复用

通过设置适配器参数,复用HTTP连接:

from requests.adapters import HTTPAdapter

session = HTMLSession()
# 设置连接池大小
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=10)
session.mount('http://', adapter)
session.mount('https://', adapter)

2. 异步并发控制

在异步下载时,控制并发数量避免过载:

async def bounded_gather(tasks, limit=5):
    """限制并发数量的gather"""
    semaphore = asyncio.Semaphore(limit)
    
    async def sem_task(task):
        async with semaphore:
            return await task
    
    return await asyncio.gather(*[sem_task(task) for task in tasks])

3. 断点续传

对于不稳定的网络环境,实现断点续传功能:

def resume_download(url, save_path, chunk_size=1024):
    if os.path.exists(save_path):
        file_size = os.path.getsize(save_path)
        headers = {'Range': f'bytes={file_size}-'}
    else:
        file_size = 0
        headers = {}
        
    with session.get(url, headers=headers, stream=True) as r:
        total_size = int(r.headers.get('content-length', 0)) + file_size
        
        with open(save_path, 'ab') as f, tqdm(
            initial=file_size,
            total=total_size,
            unit='iB',
            unit_scale=True
        ) as bar:
            for data in r.iter_content(chunk_size=chunk_size):
                size = f.write(data)
                bar.update(size)

总结与扩展学习

通过本文的介绍,你已经掌握了使用requests-html下载网页资源的核心方法和高级技巧。这个强大的库不仅简化了文件下载流程,还提供了丰富的HTML解析功能,让网页数据提取变得前所未有的简单。

想要深入学习更多功能,可以参考以下资源:

项目的完整文档可以在docs/source/index.rst找到,而所有源代码都位于项目根目录中。现在,你已经具备了处理各种网页资源下载任务的能力,快去用这3行代码的魔力简化你的工作流吧!

【免费下载链接】requests-html Pythonic HTML Parsing for Humans™ 【免费下载链接】requests-html 项目地址: https://gitcode.com/gh_mirrors/re/requests-html

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值