对WebElement截图
WebDriver.Chrome自带的方法只能对当前窗口截屏,且不能指定特定元素。若是需要截取特定元素或是窗口超过了一屏,就只能另辟蹊径了。
WebDriver.PhantomJS自带的方法支持对整个网页截屏。
下面提供几种思路。
方式一
针对WebDriver.Chrome
通过WebDriver的js脚本注入功能,曲线救国。
1. 注入第三方html转canvas的js库(见下方推荐)
2. 获取元素html源码
3. 将html转换为canvas
4. 下载canvas
优点: 截取长图容易实现
缺点: 加载第三方库耗费时间,转换原理请参考这篇文章:
将 DOM 对象绘制到 canvas 中
方式二
针对WebDriver.Chrome
截取全图,自行裁剪、拼接
1. 获取元素位置、大小
2. 获取窗口大小
3. 截取包含元素的窗口
4. 进行相应的裁剪和拼接。
具体算法思路很清晰,但需要注意的细节较多。这里就不在赘述。示例代码请移步:
[Github]PythonSpiderLibs
优点: 不需太多js工作,python+少量js代码即可完成
缺点: 拼接等工作会被WebDriver的实现差异、图片加载速度等因素影响,需多加注意。 在保证截图质量的情况下,速度较慢
方式三
针对WebDriver.PhantomJS
由于接口实现的差异,PhantomJS相比于Chrome,可以截取到整个网页。所以获取指定元素的截图也就简单很多
- 截取网页全图
- 裁剪指定元素
1
2
3
4
5
6
7
8
9
10
11
12
13
|
driver
=
webdriver
.
Chrome
(
)
driver
.
<
span
class
=
"hljs-keyword"
>
get
<
/
span
>
(
<
span
class
=
"hljs-string"
>
'<a class="vglnk" href="http://stackoverflow.com/" rel="nofollow">http://stackoverflow.com/</a>'
<
/
span
>
)
driver
.
save_screenshot
(
<
span
class
=
"hljs-string"
>
'screenshot.png'
<
/
span
>
)
left
=
element
.
location
[
<
span
class
=
"hljs-string"
>
'x'
<
/
span
>
]
top
=
element
.
location
[
<
span
class
=
"hljs-string"
>
'y'
<
/
span
>
]
right
=
element
.
location
[
<
span
class
=
"hljs-string"
>
'x'
<
/
span
>
]
+
element
.
size
[
<
span
class
=
"hljs-string"
>
'width'
<
/
span
>
]
bottom
=
element
.
location
[
<
span
class
=
"hljs-string"
>
'y'
<
/
span
>
]
+
element
.
size
[
<
span
class
=
"hljs-string"
>
'height'
<
/
span
>
]
im
=
Image
.
open
(
<
span
class
=
"hljs-string"
>
'screenshot.png'
<
/
span
>
)
im
=
im
.
crop
(
(
left
,
top
,
right
,
bottom
)
)
im
.
save
(
<
span
class
=
"hljs-string"
>
'screenshot.png'
<
/
span
>
)
|
优点: 实现简单
缺点: 对于高度太高的页面会导致文件过大,处理会有问题,我测试的最大图片尺寸是12.8M。
解决图片加载不完整的问题
参考: 利用 Python + Selenium 自动化快速截图
我们先在首页上执行一段 JavaScript 脚本,将页面的滚动条拖到最下方,然后再拖回顶部,最后才截图。这样可以解决像上面那种按需加载图片的情况。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<
span
class
=
"hljs-keyword"
>
from
<
/
span
>
selenium
<
span
class
=
"hljs-keyword"
>
import
<
/
span
>
webdriver
<
span
class
=
"hljs-keyword"
>
import
<
/
span
>
time
<
span
class
=
"hljs-function"
>
<
span
class
=
"hljs-keyword"
>
def
<
/
span
>
<
span
class
=
"hljs-title"
>
take_screenshot
<
/
span
>
<
span
class
=
"hljs-params"
>
(
url
,
save_fn
=
<
span
class
=
"hljs-string"
>
"capture.png"
<
/
span
>
)
<
/
span
>
:
<
/
span
>
browser
=
webdriver
.
Firefox
(
)
<
span
class
=
"hljs-comment"
>
# Get local session of firefox</span>
browser
.
set_window_size
(
<
span
class
=
"hljs-number"
>
1200
<
/
span
>
,
<
span
class
=
"hljs-number"
>
900
<
/
span
>
)
browser
.
get
(
url
)
<
span
class
=
"hljs-comment"
>
# Load page</span>
browser
.
execute_script
(
<
span
class
=
"hljs-string"
>
"""
(function () {
var y = 0;
var step = 100;
window.scroll(0, 0);
function f() {
if (y < document.body.scrollHeight) {
y += step;
window.scroll(0, y);
setTimeout(f, 100);
} else {
window.scroll(0, 0);
document.title += "scroll-done";
}
}
setTimeout(f, 1000);
})();
"""
<
/
span
>
)
<
span
class
=
"hljs-keyword"
>
for
<
/
span
>
i
<
span
class
=
"hljs-keyword"
>
in
<
/
span
>
xrange
(
<
span
class
=
"hljs-number"
>
30
<
/
span
>
)
:
<
span
class
=
"hljs-keyword"
>
if
<
/
span
>
<
span
class
=
"hljs-string"
>
"scroll-done"
<
/
span
>
<
span
class
=
"hljs-keyword"
>
in
<
/
span
>
browser
.
title
:
<
span
class
=
"hljs-keyword"
>
break
<
/
span
>
time
.
sleep
(
<
span
class
=
"hljs-number"
>
10
<
/
span
>
)
browser
.
save_screenshot
(
save_fn
)
browser
.
close
(
)
<
span
class
=
"hljs-keyword"
>
if
<
/
span
>
__name__
==
<
span
class
=
"hljs-string"
>
"__main__"
<
/
span
>
:
take_screenshot
(
<
span
class
=
"hljs-string"
>
"<a class="
vglnk
" href="
http
:
/
/
codingpy
.
com
/
" rel="
nofollow
">http://codingpy.com</a>"
<
/
span
>
)
|
不同wewbdriver对某些方法的实现不同
Chrome和PhantomJS 的接口差异
抓知乎时的坑,
1. Chrome用WebElement.text
可以正常得到值,用PhantomJS只能用 WebElement.get_attribute('innerHTML')
2. WebDriver.Chrome截图只能截当前屏幕区域。WebDriver.PhantomJS截图可以获取整个页面的长图。
其它还有一些坑等待发现