基于Selenium的网页图片爬取:解决重复下载与漏存问题
解决网页图片重复下载与遗漏问题的方案
从你的代码来看,导致重复保存和图片遗漏的核心问题有这几个:
- 错误选中非图片元素:第一个XPath定位到的是轮播的「下一页按钮」(
swiper-button-next),不是目标图片轮播项,这会把按钮的背景图混入列表,完全偏离需求。 - 重复选择同一图片:后两个XPath的选择范围有重叠(比如
swiper-slide-active同时属于swiper-slide-visible),导致同一个图片URL被多次添加到links列表。 - 遍历逻辑无依据:
len(links)//2 +1这种写法没有合理逻辑,会导致部分图片被跳过或重复下载。 - 缺少去重处理:即使重复添加了URL,也没有做去重操作,自然会出现重复保存的情况。
修复步骤与优化后的代码
1. 修正图片元素定位
首先把所有定位调整为只针对轮播图片项,避免选中按钮或重复元素。用更精准的XPath,只选择包含背景图的轮播slide;同时用visibility_of_all_elements_located替代presence_of_all_elements_located,确保元素已可见(图片加载完成),避免遗漏未渲染的图片:
# 只选择带有background-image属性的swiper-slide元素 all_images = wait.until( EC.visibility_of_all_elements_located((By.XPATH, "//div[contains(@class,'swiper-slide') and contains(@style,'background-image')]")) )
2. 提取URL并自动去重
提取图片URL后,用集合(set)自动去重,再转回列表处理:
links = set() for image in all_images: style_attr = image.get_attribute('style') # 兼容单引号/双引号的URL格式 img_url = style_attr.split("(")[1].split(")")[0].replace('"', '').replace("'", "") links.add(img_url) # 集合自动去重 # 转成列表方便后续遍历 unique_links = list(links)
3. 正确遍历下载所有图片
直接遍历去重后的列表,加入异常处理避免单个图片下载失败中断程序:
index = 1 for img_url in unique_links: try: response = requests.get(img_url, timeout=10) response.raise_for_status() # 检查请求是否成功 filename = f"{title.replace(' ', '-')}_{index}.jpg" with open(filename, 'wb') as file: file.write(response.content) print(f"Saving image.. {title} {index}") index += 1 except requests.exceptions.RequestException as e: print(f"Failed to download {img_url}: {str(e)}")
完整修复后的代码
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import requests # 假设driver和title变量已提前定义 links = set() wait = WebDriverWait(driver, 10) # 适当延长等待时间,确保图片完全加载 # 定位所有包含背景图的轮播slide all_images = wait.until( EC.visibility_of_all_elements_located((By.XPATH, "//div[contains(@class,'swiper-slide') and contains(@style,'background-image')]")) ) # 提取URL并去重 for image in all_images: style_attr = image.get_attribute('style') img_url = style_attr.split("(")[1].split(")")[0].replace('"', '').replace("'", "") links.add(img_url) # 下载所有去重后的图片 index = 1 for img_url in links: try: response = requests.get(img_url, timeout=10) response.raise_for_status() filename = f"{title.replace(' ', '-')}_{index}.jpg" with open(filename, 'wb') as file: file.write(response.content) print(f"Saving image.. {title} {index}") index += 1 except requests.exceptions.RequestException as e: print(f"Error downloading {img_url}: {e}")
额外优化(针对动态加载的轮播图)
如果你的目标页面是点击「下一页」才加载新图片的动态轮播,需要模拟点击按钮直到没有更多图片,避免遗漏未加载的内容:
# 模拟点击下一页按钮,收集所有动态加载的图片 while True: try: next_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[contains(@class,'swiper-button-next')]"))) next_btn.click() # 等待新图片加载完成(通过判断旧元素失效) wait.until(EC.staleness_of(all_images[0])) # 重新获取所有图片元素 all_images = wait.until( EC.visibility_of_all_elements_located((By.XPATH, "//div[contains(@class,'swiper-slide') and contains(@style,'background-image')]")) ) # 更新URL集合 for image in all_images: style_attr = image.get_attribute('style') img_url = style_attr.split("(")[1].split(")")[0].replace('"', '').replace("'", "") links.add(img_url) except: # 按钮不可点击,说明没有更多图片 break
内容的提问来源于stack exchange,提问作者pickle rick
相关产品推荐
相关产品推荐

