7

sau khi thử các cách tiếp cận khác nhau ... Tôi đã tình cờ gặp trang này để chụp ảnh toàn màn hình với chromedriver, selenium và python.Chụp Ảnh Toàn cảnh với Selenium Python (chromedriver)

mã gốc trong đây: http://seleniumpythonqa.blogspot.com/2015/08/generate-full-page-screenshot-in-chrome.html (và sao chép mã trong đăng tải dưới đây)

Nó sử dụng PIL và nó hoạt động tuyệt vời !!!!! Tuy nhiên có một vấn đề ... đó là nó nắm bắt tiêu đề cố định và lặp lại cho toàn bộ trang và cũng bỏ lỡ một số phần của trang trong khi thay đổi trang. url mẫu để chụp màn hình:

http://www.w3schools.com/js/default.asp

Làm thế nào để tránh các tiêu đề lặp đi lặp lại với mã này ... Hoặc là có bất kỳ lựa chọn tốt hơn trong đó sử dụng python chỉ ...(tôi không biết java và không muốn sử dụng java).

Vui lòng xem ảnh chụp màn hình của kết quả hiện tại và mã mẫu bên dưới.

full page screenshot with repeated headers

test.py

""" 
This script uses a simplified version of the one here: 
https://snipt.net/restrada/python-selenium-workaround-for-full-page-screenshot-using-chromedriver-2x/ 

It contains the *crucial* correction added in the comments by Jason Coutu. 
""" 

import sys 

from selenium import webdriver 
import unittest 

import util 

class Test(unittest.TestCase): 
    """ Demonstration: Get Chrome to generate fullscreen screenshot """ 

    def setUp(self): 
     self.driver = webdriver.Chrome() 

    def tearDown(self): 
     self.driver.quit() 

    def test_fullpage_screenshot(self): 
     ''' Generate document-height screenshot ''' 
     #url = "http://effbot.org/imagingbook/introduction.htm" 
     url = "http://www.w3schools.com/js/default.asp" 
     self.driver.get(url) 
     util.fullpage_screenshot(self.driver, "test.png") 


if __name__ == "__main__": 
    unittest.main(argv=[sys.argv[0]]) 

util.py

import os 
import time 

from PIL import Image 

def fullpage_screenshot(driver, file): 

     print("Starting chrome full page screenshot workaround ...") 

     total_width = driver.execute_script("return document.body.offsetWidth") 
     total_height = driver.execute_script("return document.body.parentNode.scrollHeight") 
     viewport_width = driver.execute_script("return document.body.clientWidth") 
     viewport_height = driver.execute_script("return window.innerHeight") 
     print("Total: ({0}, {1}), Viewport: ({2},{3})".format(total_width, total_height,viewport_width,viewport_height)) 
     rectangles = [] 

     i = 0 
     while i < total_height: 
      ii = 0 
      top_height = i + viewport_height 

      if top_height > total_height: 
       top_height = total_height 

      while ii < total_width: 
       top_width = ii + viewport_width 

       if top_width > total_width: 
        top_width = total_width 

       print("Appending rectangle ({0},{1},{2},{3})".format(ii, i, top_width, top_height)) 
       rectangles.append((ii, i, top_width,top_height)) 

       ii = ii + viewport_width 

      i = i + viewport_height 

     stitched_image = Image.new('RGB', (total_width, total_height)) 
     previous = None 
     part = 0 

     for rectangle in rectangles: 
      if not previous is None: 
       driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1])) 
       print("Scrolled To ({0},{1})".format(rectangle[0], rectangle[1])) 
       time.sleep(0.2) 

      file_name = "part_{0}.png".format(part) 
      print("Capturing {0} ...".format(file_name)) 

      driver.get_screenshot_as_file(file_name) 
      screenshot = Image.open(file_name) 

      if rectangle[1] + viewport_height > total_height: 
       offset = (rectangle[0], total_height - viewport_height) 
      else: 
       offset = (rectangle[0], rectangle[1]) 

      print("Adding to stitched image with offset ({0}, {1})".format(offset[0],offset[1])) 
      stitched_image.paste(screenshot, offset) 

      del screenshot 
      os.remove(file_name) 
      part = part + 1 
      previous = rectangle 

     stitched_image.save(file) 
     print("Finishing chrome full page screenshot workaround...") 
     return True 

Trả lời

4

Bạn có thể đạt được điều này bằng cách thay đổi CSS của tiêu đề trước khi ảnh chụp màn hình:

topnav = driver.find_element_by_id("topnav") 
driver.execute_script("arguments[0].setAttribute('style', 'position: absolute; top: 0px;')", topnav) 

EDIT: Đặt dòng này sau khi cửa sổ cuộn của bạn:

driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');") 

Vì vậy, trong bạn util.py nó sẽ là:

driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1])) 
driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');") 

Nếu trang web đang sử dụng header , bạn có thể làm điều đó với find_element_by_tag_name("header")

+0

hi cảm ơn .. chỉ cần thêm ở trên để kịch bản không giải quyết được vấn đề .. tuy nhiên tôi hiểu ý nghĩa .. và đã vô hiệu hóa topnav .. bằng cách sử dụng thanh tra .. và cần phải đào xung quanh để tìm javascript (không css) sửa đổi css .. và thay đổi thành tuyệt đối .. theo cách thủ công. va no đa hoạt động. (nhưng ảnh chụp màn hình kịch bản vẫn không hoạt động). Có cách nào để cải thiện kịch bản ur mà vô hiệu hóa các sửa đổi css javascript .. và cho bất kỳ trang web mới .. làm tôi phải đào xung quanh một lần nữa để tìm #id của tiêu đề .. và thay đổi nó. – ihightower

+0

Bạn không thể biết trước cách mọi trang web đã triển khai tiêu đề của họ. Nhưng bạn có thể đoán. Tôi sẽ thêm một ví dụ. – Moshisho

+0

mã của bạn hoạt động nhưng với một số trục trặc nhỏ .. đó là nó bao gồm tiêu đề trên một số trang. Vì vậy, sau khi thêm vào giấc ngủ 0,2 giây .. nó hoạt động hoàn hảo. tôi đã cập nhật mã và cũng đã đánh dấu câu trả lời của bạn. Hy vọng làm chỉnh sửa trong câu trả lời của bạn là chính xác cho stackoverflow. – ihightower

5

Sau khi biết cách tiếp cận của @ Moshisho.

đầy đủ kịch bản độc lập làm việc của tôi là ... (thêm giấc ngủ 0,2 sau mỗi cuộn và vị trí)

import sys 
from selenium import webdriver 
import util 
import os 
import time 
from PIL import Image 

def fullpage_screenshot(driver, file): 

     print("Starting chrome full page screenshot workaround ...") 

     total_width = driver.execute_script("return document.body.offsetWidth") 
     total_height = driver.execute_script("return document.body.parentNode.scrollHeight") 
     viewport_width = driver.execute_script("return document.body.clientWidth") 
     viewport_height = driver.execute_script("return window.innerHeight") 
     print("Total: ({0}, {1}), Viewport: ({2},{3})".format(total_width, total_height,viewport_width,viewport_height)) 
     rectangles = [] 

     i = 0 
     while i < total_height: 
      ii = 0 
      top_height = i + viewport_height 

      if top_height > total_height: 
       top_height = total_height 

      while ii < total_width: 
       top_width = ii + viewport_width 

       if top_width > total_width: 
        top_width = total_width 

       print("Appending rectangle ({0},{1},{2},{3})".format(ii, i, top_width, top_height)) 
       rectangles.append((ii, i, top_width,top_height)) 

       ii = ii + viewport_width 

      i = i + viewport_height 

     stitched_image = Image.new('RGB', (total_width, total_height)) 
     previous = None 
     part = 0 

     for rectangle in rectangles: 
      if not previous is None: 
       driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1])) 
       time.sleep(0.2) 
       driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');") 
       time.sleep(0.2) 
       print("Scrolled To ({0},{1})".format(rectangle[0], rectangle[1])) 
       time.sleep(0.2) 

      file_name = "part_{0}.png".format(part) 
      print("Capturing {0} ...".format(file_name)) 

      driver.get_screenshot_as_file(file_name) 
      screenshot = Image.open(file_name) 

      if rectangle[1] + viewport_height > total_height: 
       offset = (rectangle[0], total_height - viewport_height) 
      else: 
       offset = (rectangle[0], rectangle[1]) 

      print("Adding to stitched image with offset ({0}, {1})".format(offset[0],offset[1])) 
      stitched_image.paste(screenshot, offset) 

      del screenshot 
      os.remove(file_name) 
      part = part + 1 
      previous = rectangle 

     stitched_image.save(file) 
     print("Finishing chrome full page screenshot workaround...") 
     return True 


driver = webdriver.Chrome() 

''' Generate document-height screenshot ''' 
url = "http://effbot.org/imagingbook/introduction.htm" 
url = "http://www.w3schools.com/js/default.asp" 
driver.get(url) 
fullpage_screenshot(driver, "test1236.png") 
4

tôi đã thay đổi mã cho Python 3.6, có thể nó sẽ có ích cho ai đó:

from selenium import webdriver 
from sys import stdout 
from selenium.webdriver.common.by import By 
from selenium.webdriver.common.keys import Keys 
from selenium.webdriver.support.ui import WebDriverWait 
from selenium.webdriver.support import expected_conditions as EC 
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 
import unittest 
#from Login_Page import Login_Page 
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary 
from io import BytesIO 
from PIL import Image 

def testdenovoUIavailable(self): 
     binary = FirefoxBinary("C:\\Mozilla Firefox\\firefox.exe") 
     self.driver = webdriver.Firefox(firefox_binary=binary) 
     verbose = 0 

     #open page 
     self.driver.get("http://yandex.ru") 

     #hide fixed header   
     #js_hide_header=' var x = document.getElementsByClassName("topnavbar-wrapper ng-scope")[0];x[\'style\'] = \'display:none\';' 
     #self.driver.execute_script(js_hide_header) 

     #get total height of page 
     js = 'return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);' 

     scrollheight = self.driver.execute_script(js) 
     if verbose > 0: 
      print(scrollheight) 

     slices = [] 
     offset = 0 
     offset_arr=[] 

     #separate full screen in parts and make printscreens 
     while offset < scrollheight: 
      if verbose > 0: 
       print(offset) 

      #scroll to size of page 
      if (scrollheight-offset)<offset: 
       #if part of screen is the last one, we need to scroll just on rest of page 
       self.driver.execute_script("window.scrollTo(0, %s);" % (scrollheight-offset)) 
       offset_arr.append(scrollheight-offset) 
      else: 
       self.driver.execute_script("window.scrollTo(0, %s);" % offset) 
       offset_arr.append(offset) 

      #create image (in Python 3.6 use BytesIO) 
      img = Image.open(BytesIO(self.driver.get_screenshot_as_png())) 


      offset += img.size[1] 
      #append new printscreen to array 
      slices.append(img) 


      if verbose > 0: 
       self.driver.get_screenshot_as_file('screen_%s.jpg' % (offset)) 
       print(scrollheight) 

     #create image with 
     screenshot = Image.new('RGB', (slices[0].size[0], scrollheight)) 
     offset = 0 
     offset2= 0 
     #now glue all images together 
     for img in slices: 
      screenshot.paste(img, (0, offset_arr[offset2])) 
      offset += img.size[1] 
      offset2+= 1  

     screenshot.save('test.png') 
0
element=driver.find_element_by_tag_name('body') 
element_png = element.screenshot_as_png 
with open("test2.png", "wb") as file: 
    file.write(element_png) 

Điều này phù hợp với tôi. Nó lưu toàn bộ trang dưới dạng ảnh chụp màn hình. Để biết thêm thông tin bạn có thể đọc lên các tài liệu api: http://selenium-python.readthedocs.io/api.html

0
element=driver.find_element_by_tag_name('body') 
element_png = element.screenshot_as_png 
with open("test2.png", "wb") as file: 
    file.write(element_png) 

Có một lỗi trong mã đề nghị trước đó trong dòng 2. Dưới đây là sau khi chỉnh sửa. Là một noob ở đây, không thể chỉnh sửa bài đăng của riêng tôi.

Đôi khi vỏ bọc không nhận được kết quả tốt nhất. Vì vậy, có thể sử dụng phương pháp khác để lấy chiều cao của tất cả các yếu tố và tổng hợp chúng để đặt chiều cao chụp như sau:

element=driver.find_elements_by_xpath("/html/child::*/child::*") 
    eheight=set() 
    for e in element: 
     eheight.add(round(e.size["height"])) 
    print (eheight) 
    total_height = sum(eheight) 
    driver.execute_script("document.getElementsByTagName('html')[0].setAttribute('style', 'height:"+str(total_height)+"px')") 
    element=driver.find_element_by_tag_name('body') 
    element_png = element.screenshot_as_png 
    with open(fname, "wb") as file: 
     file.write(element_png) 

BTW, nó hoạt động trên FF.

Các vấn đề liên quan