[PYTHON] chromedriver가있는 Selenium Python으로 전체 페이지의 스크린 샷 찍기
PYTHONchromedriver가있는 Selenium Python으로 전체 페이지의 스크린 샷 찍기
다양한 접근법을 시도한 후에 ... chromedriver, selenium 및 python으로 전체 페이지 스크린 샷을 찍는이 페이지를 우연히 발견했습니다.
원본 코드 : http://seleniumpythonqa.blogspot.com/2015/08/generate-full-page-screenshot-in-chrome.html (이 게시물의 코드는 아래에 복사되어 있습니다)
그것은 PIL을 사용하고 멋지게 작동합니다 !!!!! 그러나 한 가지 문제가 있습니다 ... 그것은 고정 된 헤더를 캡처하고 전체 페이지에 대해 반복하며 페이지가 변경되는 동안 페이지의 일부분을 누락시킵니다. 스크린 샷을 찍을 샘플 URL :
http://www.w3schools.com/js/default.asp
이 코드로 반복되는 헤더를 피하는 방법 ... 아니면 파이썬 만 사용하는 더 좋은 옵션이 있습니까? (나는 자바를 모르며 자바를 사용하고 싶지 않습니다).
아래의 현재 결과 및 샘플 코드의 스크린 샷을 참조하십시오.
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
해결법
-
==============================
1.스크린 샷 이전에 헤더의 CSS를 변경하면됩니다.
스크린 샷 이전에 헤더의 CSS를 변경하면됩니다.
topnav = driver.find_element_by_id("topnav") driver.execute_script("arguments[0].setAttribute('style', 'position: absolute; top: 0px;')", topnav)
편집 : 창 스크롤 후이 줄을 넣어 :
driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');")
따라서 util.py에서는 다음과 같이됩니다.
driver.execute_script("window.scrollTo({0}, {1})".format(rectangle[0], rectangle[1])) driver.execute_script("document.getElementById('topnav').setAttribute('style', 'position: absolute; top: 0px;');")
사이트에서 header 태그를 사용하는 경우 find_element_by_tag_name ( "header")을 사용하여이를 수행 할 수 있습니다.
-
==============================
2.
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)
이것은 나를 위해 작동합니다. 전체 페이지를 스크린 샷으로 저장합니다. 자세한 내용은 api 문서를 참조하십시오. http://selenium-python.readthedocs.io/api.html
-
==============================
3.@Moshisho의 접근 방식을 알고 난 후에.
@Moshisho의 접근 방식을 알고 난 후에.
내 독립 실행 형 작업 스크립트는 ... (각 스크롤 및 위치 후에 절전 0.2 추가됨)
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.사람들이 여전히이 문제를 겪고 있는지 확실하지 않습니다. 나는 꽤 잘 작동하는 작은 해킹을 해왔고 동적 영역과 잘 맞습니다. 희망이 도움이된다.
사람들이 여전히이 문제를 겪고 있는지 확실하지 않습니다. 나는 꽤 잘 작동하는 작은 해킹을 해왔고 동적 영역과 잘 맞습니다. 희망이 도움이된다.
# 1. get dimensions browser = webdriver.Chrome(chrome_options=options) browser.set_window_size(default_width, default_height) browser.get(url) time.sleep(sometime) total_height = browser.execute_script("return document.body.parentNode.scrollHeight") browser.quit() # 2. get screenshot browser = webdriver.Chrome(chrome_options=options) browser.set_window_size(default_width, total_height) browser.get(url) browser.save_screenshot(screenshot_path)
-
==============================
5.나는 Python 3.6을위한 코드를 변경했다. 아마 누군가에게 유용 할 것이다.
나는 Python 3.6을위한 코드를 변경했다. 아마 누군가에게 유용 할 것이다.
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')
-
==============================
6.이 대답은 am05mhz와 Javed Karim의 사전 답변을 향상시킵니다.
이 대답은 am05mhz와 Javed Karim의 사전 답변을 향상시킵니다.
헤드리스 모드를 가정하고 창 크기 옵션이 초기에 설정되지 않았습니다. 이 함수를 호출하기 전에 페이지가 완전히 또는 충분히로드되었는지 확인하십시오.
너비와 높이를 모두 필요한 것으로 설정하려고 시도합니다. 전체 페이지의 스크린 샷에는 때때로 불필요한 세로 스크롤 막대가 포함될 수 있습니다. 일반적으로 스크롤바를 피하는 한 가지 방법은 body 요소의 스크린 샷을 대신 찍는 것입니다. 스크린 샷을 저장하면 원래의 크기로 되돌아 가고 다음 스크린 샷의 크기가 올바르게 설정되지 않을 수 있습니다.
궁극적으로이 기술은 일부 예제에서는 여전히 완벽하게 작동하지 않을 수 있습니다.
def save_screenshot(driver: webdriver.Chrome, path: str = '/tmp/screenshot.png'): # Ref: https://stackoverflow.com/a/52572919/ original_size = driver.get_window_size() required_width = driver.execute_script('return document.body.parentNode.scrollWidth') required_height = driver.execute_script('return document.body.parentNode.scrollHeight') driver.set_window_size(required_width, required_height) # driver.save_screenshot(path) # has scrollbar driver.find_element_by_tag_name('body').screenshot(path) # avoids scrollbar driver.set_window_size(original_size['width'], original_size['height'])
3.6 이전의 Python을 사용하는 경우 함수 정의에서 유형 주석을 제거하십시오.
-
==============================
7.
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)
앞의 2 행에서 제안한 코드에 오류가 있습니다. 수정 된 오류가 있습니다. 여기 멍청한 놈이기 때문에 아직 내 자신의 소식을 수정할 수 없습니다.
때때로 baove는 최상의 결과를 얻지 못합니다. 따라서 다른 방법을 사용하여 모든 요소의 높이를 얻고 합계하여 캡처 높이를 아래와 같이 설정합니다.
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, 그것은 FF로 작동합니다.
-
==============================
8.@ihightower 및 @ A.Minachev의 코드를 약간 수정하고 Mac 망막에서 작동하게하십시오.
@ihightower 및 @ A.Minachev의 코드를 약간 수정하고 Mac 망막에서 작동하게하십시오.
import time from PIL import Image from io import BytesIO def fullpage_screenshot(driver, file, scroll_delay=0.3): device_pixel_ratio = driver.execute_script('return window.devicePixelRatio') total_height = driver.execute_script('return document.body.parentNode.scrollHeight') viewport_height = driver.execute_script('return window.innerHeight') total_width = driver.execute_script('return document.body.offsetWidth') viewport_width = driver.execute_script("return document.body.clientWidth") # this implementation assume (viewport_width == total_width) assert(viewport_width == total_width) # scroll the page, take screenshots and save screenshots to slices offset = 0 # height slices = {} while offset < total_height: if offset + viewport_height > total_height: offset = total_height - viewport_height driver.execute_script('window.scrollTo({0}, {1})'.format(0, offset)) time.sleep(scroll_delay) img = Image.open(BytesIO(driver.get_screenshot_as_png())) slices[offset] = img offset = offset + viewport_height # combine image slices stitched_image = Image.new('RGB', (total_width * device_pixel_ratio, total_height * device_pixel_ratio)) for offset, image in slices.items(): stitched_image.paste(image, (0, offset * device_pixel_ratio)) stitched_image.save(file) fullpage_screenshot(driver, 'test.png')
-
==============================
9.한 번만 URL을 얻을 수 있도록 제레미의 대답을 수정했습니다.
한 번만 URL을 얻을 수 있도록 제레미의 대답을 수정했습니다.
browser = webdriver.Chrome(chrome_options=options) browser.set_window_size(default_width, default_height) browser.get(url) height = browser.execute_script("return document.body.parentNode.scrollHeight") # 2. get screenshot browser.set_window_size(default_width, height) browser.save_screenshot(screenshot_path) browser.quit()
from https://stackoverflow.com/questions/41721734/take-screenshot-of-full-page-with-selenium-python-with-chromedriver by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] Pandas : 여러 DataFrame에 존재하지 않는 행을 여러 열로 찾습니다. (0) | 2018.11.16 |
---|---|
[PYTHON] 파이썬으로 rss 리다이렉트하기 / urllib2 (0) | 2018.11.16 |
[PYTHON] 파이썬에서 바이트를 비트로 변환 (0) | 2018.11.16 |
[PYTHON] QWidget은 배경색을 그려 내지 않습니다. (0) | 2018.11.16 |
[PYTHON] 요청 파이썬 라이브러리에서 HTTP 요청의 다운로드 속도를 제한하는 방법은 무엇입니까? (0) | 2018.11.16 |