对WebElement截图
WebDriver.Chrome自带的方法只能对当前窗口截屏,且不能指定特定元素。若是需要截取特定元素或是窗口超过了一屏,就只能另辟蹊径了。
WebDriver.PhantomJS自带的方法支持对整个网页截屏。
下面提供几种思路。
方式一
针对WebDriver.Chrome
通过WebDriver的js脚本注入功能,曲线救国。
注入第三方html转canvas的js库(见下方推荐)
获取元素html源码
将html转换为canvas
下载canvas
优点: 截取长图容易实现
缺点: 加载第三方库耗费时间,转换原理请参考这篇文章:
方式二
针对WebDriver.Chrome
截取全图,自行裁剪、拼接
获取元素位置、大小
获取窗口大小
截取包含元素的窗口
进行相应的裁剪和拼接。
具体算法思路很清晰,但需要注意的细节较多。这里就不在赘述。示例代码请移步:
优点: 不需太多js工作,python+少量js代码即可完成
缺点: 拼接等工作会被WebDriver的实现差异、图片加载速度等因素影响,需多加注意。 在保证截图质量的情况下,速度较慢
方式三
针对WebDriver.PhantomJS
由于接口实现的差异,PhantomJS相比于Chrome,可以截取到整个网页。所以获取指定元素的截图也就简单很多
截取网页全图
裁剪指定元素
driver = webdriver.Chrome() driver.get('http://*.com/') driver.save_screenshot('screenshot.png') left = element.location['x'] top = element.location['y'] right = element.location['x'] + element.size['width'] bottom = element.location['y'] + element.size['height'] im = Image.open('screenshot.png') im = im.crop((left, top, right, bottom)) im.save('screenshot.png')
优点: 实现简单
缺点: 对于高度太高的页面会导致文件过大,处理会有问题,我测试的最大图片尺寸是12.8M。
解决图片加载不完整的问题
参考: 利用 Python + Selenium 自动化快速截图
我们先在首页上执行一段 JavaScript 脚本,将页面的滚动条拖到最下方,然后再拖回顶部,最后才截图。这样可以解决像上面那种按需加载图片的情况。
# -*- coding: utf-8 -*- from selenium import webdriver import time def take_screenshot(url, save_fn="capture.png"): # browser = webdriver.Firefox() # Get local session of firefox #谷歌浏览器截取当前窗口网页 chromedriver = r"C:\soft\chromedriver2.31_win32\chromedriver.exe" browser = webdriver.Chrome(chromedriver) #phantomjs截取整张网页 # browser = webdriver.PhantomJS() browser.set_window_size(1200, 900) browser.get(url) # Load page #将页面的滚动条拖到最下方,然后再拖回顶部 browser.execute_script(""" (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); })(); """) for i in xrange(30): if "scroll-done" in browser.title: break time.sleep(10) browser.save_screenshot(save_fn) browser.close() if __name__ == "__main__": take_screenshot("http://codingpy.com")
如何截取某个网页元素
有时候我们只想截取某个网页元素的图片呢?比如说会动态变化的验证码。本来 Selenium 也提供了对元素截图的支持,只要在选中的元素上调用其 screenshot() 方法即可。
但是在实际使用时却遇到了 Unrecognized command 这个异常,经过一段时间检索也没有找到解决办法。所以,只能曲线救国,利用 Selenium 执行JS代码,将页面上不需要的元素一一删除,只保留我们希望留下的元素,然后再利用上面的窗口截屏功能。
例如,如果我们只截取编程派网站右侧的二维码,可以执行这样一段JQuery代码:
$('#main').siblings().remove(); $('#aside__wrapper').siblings().remove(); $('.ui.sticky').siblings().remove(); $('.follow-me').siblings().remove(); $('img.ui.image').siblings().remove();
代码执行完毕之后,就只剩下二维码的图片了。然后我们再截屏。不过这样有一点不好,就是截屏图片的下方会有大量空白内容。
- 代码
# -*- coding: utf-8 -*- from selenium import webdriver import time def take_screenshot(url, save_fn="capture.png"): # browser = webdriver.Firefox() # Get local session of firefox chromedriver = r"C:\soft\chromedriver2.31_win32\chromedriver.exe" browser = webdriver.Chrome(chromedriver) # browser = webdriver.PhantomJS() browser.set_window_size(1200, 900) browser.get(url) # Load page #将页面的滚动条拖到最下方,然后再拖回顶部 # browser.execute_script(""" # (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); # })(); # """) # # for i in xrange(30): # if "scroll-done" in browser.title: # break # time.sleep(10) #只截取编程派网站右侧的二维码,可以执行这样一段JQuery代码:siblings().remove()移除兄弟姐妹元素 browser.execute_script(""" $('#main').siblings().remove(); $('#aside__wrapper').siblings().remove(); $('.ui.sticky').siblings().remove(); $('.follow-me').siblings().remove(); $('img.ui.image').siblings().remove(); """) browser.save_screenshot(save_fn) browser.close() if __name__ == "__main__": take_screenshot("http://codingpy.com/article/take-screenshot-of-web-page-using-selenium/")
不同wewbdriver对某些方法的实现不同
Chrome和PhantomJS 的接口差异
抓知乎时的坑,
Chrome用
WebElement.text
可以正常得到值,用PhantomJS只能用WebElement.get_attribute('innerHTML')
WebDriver.Chrome截图只能截当前屏幕区域。WebDriver.PhantomJS截图可以获取整个页面的长图。
其它还有一些坑等待发现