requests-html图片提取功能详解:批量下载网页图片

requests-html图片提取功能详解:批量下载网页图片

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

你还在为手动保存网页图片而烦恼吗?面对包含几十甚至上百张图片的网页,逐个右键保存不仅耗时还容易遗漏。本文将带你掌握使用requests-html库实现网页图片批量提取的完整方案,从基础提取到异步下载,无需复杂编程知识也能轻松搞定。读完本文你将学会:快速定位网页图片资源、处理相对路径与绝对路径转换、应对JavaScript动态加载的图片,以及编写高效的批量下载工具。

核心功能解析

requests-html的图片提取能力源于其强大的HTML解析引擎。通过分析requests_html.py源码可知,该库基于PyQuery和lxml构建了完整的选择器系统,使得定位图片元素变得异常简单。

图片元素定位原理

requests_html.py的第181行定义的find()方法是提取图片的核心入口。该方法支持CSS选择器语法,通过指定img标签即可筛选出所有图片元素:

def find(self, selector: str = "*", *, containing: _Containing = None, clean: bool = False, first: bool = False, _encoding: str = None) -> _Find:
    # 实现代码...

实际使用时,只需调用r.html.find('img')即可获取页面所有图片元素。每个返回的Element对象包含了图片的完整属性,其中attrs字典中存储了关键的src属性值。

路径处理机制

网页图片的src属性常常使用相对路径,直接使用会导致下载失败。requests-html内置了智能路径转换功能,在requests_html.py的307-326行实现了_make_absolute()方法:

def _make_absolute(self, link):
    """Makes a given link absolute."""
    # 解析链接
    parsed = urlparse(link)._asdict()
    
    # 如果是相对链接,则与基础URL合并
    if not parsed['netloc']:
        return urljoin(self.base_url, link)
    
    # 如果链接缺少协议,则从基础URL继承
    if not parsed['scheme']:
        parsed['scheme'] = urlparse(self.base_url).scheme
        parsed = (v for v in parsed.values())
        return urlunparse(parsed)
    
    return link

这一机制确保了无论原始图片链接是绝对路径还是相对路径,最终都能转换为可直接访问的完整URL。

实战指南:提取图片的三种方法

基础提取法

最直接的图片提取方式是使用CSS选择器定位所有img标签,然后遍历获取src属性:

from requests_html import HTMLSession

# 创建会话
session = HTMLSession()
# 获取网页内容
r = session.get('https://example.com/gallery')

# 查找所有图片元素
images = r.html.find('img')

# 提取图片URL
image_urls = []
for img in images:
    if 'src' in img.attrs:
        # 获取绝对URL
        url = img.attrs['src']
        absolute_url = r.html._make_absolute(url)
        image_urls.append(absolute_url)

print(f"找到{len(image_urls)}张图片")

这种方法适用于大多数静态网页,但对于使用JavaScript动态加载的图片则无法捕获。

XPath提取法

对于结构复杂的网页,可以使用XPath表达式精确定位图片元素。在requests_html.py的237行实现了xpath()方法,支持直接提取属性值:

# 使用XPath直接提取所有img标签的src属性
image_urls = r.html.xpath('//img/@src')

# 转换为绝对URL
absolute_urls = [r.html._make_absolute(url) for url in image_urls]

XPath方法的优势在于可以添加更复杂的筛选条件,例如只提取特定尺寸的图片:

# 提取宽度大于300像素的图片
large_images = r.html.xpath('//img[@width>300]/@src')

动态内容提取法

现代网页常使用JavaScript动态加载图片,此时需要使用requests-html的渲染功能。在requests_html.py的603行定义的render()方法可以模拟浏览器渲染页面:

# 渲染页面以加载动态内容
r.html.render(
    retries=3,        # 重试次数
    wait=1,           # 加载等待时间(秒)
    scrolldown=2,     # 滚动次数,模拟用户浏览
    sleep=1           # 滚动间隔时间(秒)
)

# 重新提取图片
dynamic_images = r.html.find('img')
print(f"动态渲染后找到{len(dynamic_images)}张图片")

渲染功能依赖Pyppeteer库,首次使用会自动下载Chromium浏览器。如果需要保存浏览器实例以便后续操作,可以设置keep_page=True参数。

高级应用:批量下载与存储

获取图片URL后,我们需要将其批量下载到本地。以下是一个完整的下载器实现,包含异常处理和进度显示:

import os
import requests
from concurrent.futures import ThreadPoolExecutor
from requests_html import HTMLSession

def download_image(url, save_dir='images', timeout=10):
    """下载单张图片"""
    try:
        # 创建保存目录
        os.makedirs(save_dir, exist_ok=True)
        
        # 获取文件名
        filename = os.path.basename(url.split('?')[0])  # 去除URL参数
        if not filename:
            filename = f"image_{hash(url)}.jpg"
        
        # 下载图片
        response = requests.get(url, timeout=timeout)
        response.raise_for_status()  # 检查HTTP错误
        
        # 保存图片
        with open(os.path.join(save_dir, filename), 'wb') as f:
            f.write(response.content)
        
        return f"成功下载: {filename}"
    except Exception as e:
        return f"下载失败{url}: {str(e)}"

# 获取图片URL列表(代码见上文)
# ...

# 多线程下载
with ThreadPoolExecutor(max_workers=5) as executor:
    # 提交下载任务
    results = list(executor.map(
        lambda url: download_image(url, save_dir='my_gallery'),
        image_urls
    ))

# 显示结果
for result in results:
    print(result)

处理特殊情况

某些网站会对图片请求进行限制,此时需要添加请求头信息伪装成浏览器访问:

# 在创建会话时设置用户代理
session = HTMLSession()
session.headers['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'

# 对于需要登录的网站,可以添加Cookie
session.cookies.set('sessionid', 'your_session_id_here')

性能优化与最佳实践

异步提取与下载

对于大规模图片提取任务,推荐使用异步方式提升效率。requests-html提供了AsyncHTMLSession类支持异步操作:

from requests_html import AsyncHTMLSession

async def async_extract_images(url):
    session = AsyncHTMLSession()
    r = await session.get(url)
    
    # 异步渲染页面(如果需要)
    await r.html.arender(scrolldown=3, sleep=1)
    
    # 提取图片URL
    images = r.html.find('img')
    image_urls = [r.html._make_absolute(img.attrs['src']) for img in images if 'src' in img.attrs]
    
    await session.close()
    return image_urls

# 运行异步函数
image_urls = asyncio.run(async_extract_images('https://example.com/gallery'))

图片去重与过滤

实际应用中常常需要过滤掉重复或不需要的图片,可以通过集合去重和条件筛选实现:

# 去重
unique_urls = list(set(image_urls))

# 过滤小尺寸图片(通过URL判断)
filtered_urls = []
for url in unique_urls:
    # 排除过小的图片(通常是图标)
    if 'small' not in url and 'icon' not in url.lower():
        filtered_urls.append(url)

# 按文件类型筛选
extensions = ('.jpg', '.jpeg', '.png', '.gif')
image_urls = [url for url in filtered_urls if url.lower().endswith(extensions)]

常见问题解决方案

动态加载图片无法提取

问题表现:使用基础方法只能提取到部分图片,页面滚动后才出现的图片无法获取。

解决方案:使用render()方法模拟浏览器渲染,在test_requests_html.py的163-177行有渲染功能的测试示例:

def test_render():
    r = get()
    script = """
    () => {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
            deviceScaleFactor: window.devicePixelRatio,
        }
    }
    """
    val = r.html.render(script=script)
    for value in ('width', 'height', 'deviceScaleFactor'):
        assert value in val

应用到图片提取:

# 渲染页面,模拟滚动加载
r.html.render(
    scrolldown=5,  # 滚动5次
    sleep=2,       # 每次滚动后等待2秒
    timeout=10     # 超时时间
)

# 重新提取图片
images = r.html.find('img')

SSL证书错误

问题表现:下载图片时出现SSL: CERTIFICATE_VERIFY_FAILED错误。

解决方案:添加verify参数跳过证书验证(仅在可信网站使用):

# 方法1:在get请求时跳过验证
r = session.get(url, verify=False)

# 方法2:下载图片时跳过验证
response = requests.get(url, timeout=10, verify=False)

提取速度过慢

问题表现:提取包含大量图片的网页时耗时过长。

解决方案:使用多线程或异步请求,结合连接池提升效率:

# 使用会话对象的连接池
session = HTMLSession()
adapter = requests.adapters.HTTPAdapter(max_retries=3, pool_connections=10, pool_maxsize=10)
session.mount('http://', adapter)
session.mount('https://', adapter)

总结与扩展应用

requests-html提供了简洁而强大的API,使得网页图片提取任务变得前所未有的简单。通过本文介绍的方法,你可以轻松实现从简单到复杂的各种图片提取需求。官方文档docs/source/index.rst中还有更多高级功能等待探索。

扩展应用方向:

  • 结合调度工具实现定时抓取
  • 构建图片素材管理系统
  • 开发网页截图工具(利用render()方法)
  • 实现图片内容分析与分类

掌握这些技能后,无论是构建个人图片库、收集设计素材还是进行数据挖掘,你都能游刃有余地处理各种网页图片提取场景。

最后提醒:使用图片提取功能时,请遵守网站的robots协议和版权规定,合理合法地获取和使用网络资源。

【免费下载链接】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、付费专栏及课程。

余额充值