使用Python Selenium创建下载链接时图片未下载却打开的问题求助
Selenium Chrome爬取图片无法触发下载问题解析
问题描述
我正在使用Python Selenium在Chrome中爬取图片,通过以下代码创建下载链接来下载图片:
script_js = 'var imageURL = document.getElementsByTagName("{select_tag}")[{num}].getAttribute("src");' \ 'var link = document.createElement("a"); ' \ 'link.download = "{image_name}";' \ 'link.href = imageURL;' \ 'link.innerHTML = "download";' \ 'document.body.appendChild(link);' \ 'link.click();' \ 'document.body.removeChild(link);' \ 'delete link;'.format(select_tag="img", num=0, image_name=f"{order+1}.jpg") browser.execute_script(script_js)此前在其他网站用该方法成功下载过图片,但此次失效——创建下载链接并点击后,浏览器在当前标签页打开图片而非下载。尝试将单张图片URL在新标签页打开后用同样方法创建下载链接,却能成功下载。这些图片需登录才能查看,怀疑原页面无法下载是反爬机制?原页面中是否有办法创建可成功下载的链接?另外补充:图片的src属性为类似"img/a175/321F2061A9895…"的形式,属于同源资源。
可能原因
- 页面上下文拦截:原页面可能存在JavaScript监听
click事件,动态阻止了a标签的下载触发逻辑;或是网站设置了CSP(内容安全策略),限制了动态创建元素的下载行为。 - 响应头差异:原页面加载图片时,服务器返回的
Content-Disposition头为inline(默认打开),而新标签页单独请求时,服务器返回的头可能被调整为attachment(触发下载),这可能是网站根据请求上下文做的差异化处理。 - 反爬检测:部分网站会识别下载请求的触发源,动态创建的a标签点击属于非用户手动操作,会被判定为爬虫行为,从而强制以打开图片的方式替代下载。
原页面可行的解决方法
1. 直接获取图片二进制数据保存(最稳定)
绕开浏览器下载逻辑,利用Selenium获取的登录会话,直接用请求库下载图片:
import requests from selenium import webdriver # 假设browser是已登录的Chrome实例 cookies = browser.get_cookies() session = requests.Session() # 同步浏览器Cookies到requests会话 for cookie in cookies: session.cookies.set(cookie['name'], cookie['value'], domain=cookie['domain']) # 获取图片元素的src img_element = browser.find_elements_by_tag_name('img')[0] img_src = img_element.get_attribute('src') # 补全相对路径为完整URL if not img_src.startswith(('http://', 'https://')): base_url = f"{browser.current_url.split('//')[0]}//{browser.current_url.split('//')[1].split('/')[0]}" img_src = f"{base_url}/{img_src.lstrip('/')}" # 下载并保存图片 response = session.get(img_src) with open(f"{order+1}.jpg", 'wb') as img_file: img_file.write(response.content)
2. 通过Chrome DevTools修改响应头强制下载
利用CDP(Chrome DevTools协议)拦截图片请求,修改Content-Disposition响应头,让浏览器触发下载:
from selenium import webdriver browser = webdriver.Chrome() # 启用网络监控 browser.execute_cdp_cmd('Network.enable', {}) def modify_response_headers(request_id, response): # 只处理图片请求 if response['mimeType'].startswith('image/'): # 添加或修改Content-Disposition头 new_headers = [] for header in response['headers']: if header['name'].lower() != 'content-disposition': new_headers.append(header) new_headers.append({ 'name': 'Content-Disposition', 'value': f'attachment; filename="{order+1}.jpg"' }) # 修改响应头 browser.execute_cdp_cmd('Network.setResponseHeaders', { 'requestId': request_id, 'headers': new_headers }) # 继续请求 browser.execute_cdp_cmd('Network.continueInterceptedRequest', { 'requestId': request_id }) # 设置请求拦截 browser.execute_cdp_cmd('Network.setRequestInterception', { 'patterns': [{'urlPattern': '*', 'resourceType': 'Image', 'interceptionStage': 'HeadersReceived'}] }) browser.add_cdp_listener('Network.requestIntercepted', lambda params: modify_response_headers(params['requestId'], params['response'])) # 访问目标页面并触发图片加载 browser.get('你的目标页面URL')
3. 模拟右键另存为操作
通过ActionChains模拟用户右键点击图片并选择“另存为”,需提前设置Chrome默认下载路径避免弹窗:
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys # 设置Chrome默认下载路径 options = webdriver.ChromeOptions() prefs = {'download.default_directory': '/你的下载路径'} options.add_experimental_option('prefs', prefs) browser = webdriver.Chrome(options=options) # 登录并定位图片元素 browser.get('你的目标页面URL') img_element = browser.find_elements_by_tag_name('img')[0] # 模拟右键点击 -> 选择“另存为”(注意:菜单选项文本需匹配浏览器语言,此处为中文示例) actions = ActionChains(browser) actions.context_click(img_element) # 按向下箭头选中“图片另存为...”选项,按回车确认 actions.send_keys(Keys.ARROW_DOWN * 2).send_keys(Keys.ENTER).perform()
内容的提问来源于stack exchange,提问作者Cloud
相关产品推荐
相关产品推荐

