selenium
爬取页面时经常遇到要保存图片的需求,通常的做法是获取链接后用 requests
下载,但这种方法脱离了selenium环境,如遇到有校验的情况还需要绕过校验。
下面介绍两种直接通过selenium保存图片的方法:
1. 通过抓包
selenium-wire
是selenium扩展,它可以对所有请求抓包,同时还可以修改请求头,请求body,请求返回值等,功能非常强大。
selenium-wire
的使用和selenium一样,你只从seleniumwire导入webdriver就行,对于其他包还是从selenium导入
1
2
3
4
|
from selenium.webdriver.chrome.options import Options
from seleniumwire.webdriver import Chrome
driver = Chrome(options = Options())
|
下载图片有两种方法:
1-1.通过拦截器
通过拦截器预先把所有图片保存下来,要用到时在缓存目录中找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
def get_img_path_from_url(url):
# 自行实现
return url
def response_interceptor(request, response):
t = response.headers[ 'Content-Type' ]
if request.host = = 'xxx' and t and 'image' in t:
with open (get_img_path_from_url(request.url), 'wb' ) as f:
f.write(response.body)
driver.response_interceptor = response_interceptor
driver.get( '...' )
src = driver.find_element_by_tag_name( 'img' ).get_attribute( 'src' )
img_path = get_img_path_from_url(src)
|
1-2. 请求后在所有请求中获取
这种方法有个缺点,浏览器会自动缓存图片,如果之前已经缓存过这张图片是不会有网络请求的
1
2
3
4
5
6
7
8
9
|
# 下载前先清理数据,不然请求太多
del driver.requests
driver.get( '...' )
src = driver.find_element_by_tag_name( 'img' ).get_attribute( 'src' )< / code>
for r in driver.iter_requests():
if r.url = = src:
with open ( 'img' , 'wb' ) as f:
f.write(r.response.body)
|
2. 通过canvas
使用js把图片放到canvas中,然后获取base64字符串,再保存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import base64
import os
import re
from io import BytesIO
from PIL import Image
def base64_to_image(base64_str):
base64_data = re.sub( '^data:image/.+;base64,' , '', base64_str)
byte_data = base64.b64decode(base64_data)
image_data = BytesIO(byte_data)
img = Image. open (image_data)
return img
js = "let c = document.createElement('canvas');let ctx = c.getContext('2d');"
"let img = document.getElementsByTagName('img')[0]; /*找到图片*/ "
"c.height=img.naturalHeight;c.width=img.naturalWidth;"
"ctx.drawImage(img, 0, 0,img.naturalWidth, img.naturalHeight);"
"let base64String = c.toDataURL();return base64String;"
base64_str = driver.execute_script(js)
img = base64_to_image(base64_str)
img.save( 'xx.png' )
|