利用 Python + Selenium 實現對頁面的指定元素截圖(可截長圖元素)

斯科特安的時間

對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.get('http://stackoverflow.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 自動化快速截圖](http://codingpy.com/article/take-screenshot-of-web-page-using-selenium/)

我們先在首頁上執行一段 JavaScript 腳本,將頁面的滾動條拖到最下方,然后再拖回頂部,最后才截圖。這樣可以解決像上面那種按需加載圖片的情況。
from selenium import webdriver
import time

def take_screenshot(url, save_fn="capture.png"):
    browser = webdriver.Firefox() # Get local session of firefox
    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")


不同wewbdriver對某些方法的實現不同

Chrome和PhantomJS 的接口差異

抓知乎時的坑,

  1. Chrome用WebElement.text可以正常得到值,用PhantomJS只能用 WebElement.get_attribute('innerHTML')

  2. WebDriver.Chrome截圖只能截當前屏幕區域。WebDriver.PhantomJS截圖可以獲取整個頁面的長圖。

其它還有一些坑等待發現

推薦

  1. html2canvas庫
  2. 將 DOM 對象繪制到 canvas 中
  3. 利用 Python + Selenium 自動化快速截圖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容