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协议和版权规定,合理合法地获取和使用网络资源。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



