对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. 裁剪指定元素


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 脚本,将页面的滚动条拖到最下方,然后再拖回顶部,最后才截图。这样可以解决像上面那种按需加载图片的情况。

< 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截图可以获取整个页面的长图。

其它还有一些坑等待发现