본문 바로가기
IT/Web

[python] 웹사이트 크롤링 - FullScreen 캡쳐하기 (Selenium)

by 한동두 2024. 1. 10.
반응형

크롤링을 하면서 화면을 캡쳐해야 할 일이 왕왕 있는데,

구글에 검색해보면 주로 Selenium으로 직접 scroll을 움직이면서 캡쳐하는 방법만 잔뜩 있다.

 

해당 코드를 보면 좀 하드코딩 하는 느낌이 난달까?

코드가 지저분해지고 길어지고.. 좀 꼴보기 싫어져서

라이브러리를 설치하든 어쨌든 간결하게 만들수 없을까 해서 열심히 조사를 해봤다.

 

역시, 없는건 없다.

꽤 괜찮은 방법들을 찾아서 소개해 주도록 하겠다.

[시간이 없으신 분들은 방법 3을 바로 읽어보세요!!!]

 

관련 출처 : 

https://stackoverflow.com/questions/41721734/take-screenshot-of-full-page-with-selenium-python-with-chromedriver

 

Take screenshot of full page with Selenium Python with chromedriver

After trying out various approaches... I have stumbled upon this page to take full-page screenshot with chromedriver, selenium and python. The original code is here. (and I copy the code in this p...

stackoverflow.com

위 StackoverFlow의 답변에서 해답을 얻었음을 알린다!


방법 1. Html의 Body tag를 이용하기 

1-1. headless X

여러 답변들 중 가장 간결해보이는 코드이다.

답변 일부 캡쳐

 

일단 딱보기에도 scroll 관련된 코드가 없어서 아주 깔끔하다.

코드에서도 그 의미를 직접적으로 알 수 있다.

웹페이지의 Body부분을 가져온다는 뜻으로 즉 현재 화면 전체를 캡쳐한다는 말이 된다.

 

(Body = 웹페이지에 보이는 내용물 대부분)

(Head= script, style, link 등 메타데이터들. 웹페이지에 보이지 않는 부분들을 담고있음.)

 

위 코드의 find_element_by_tag_name을 보니, 구버전 selenium 코드인 것으로 보인다.
따라서 현재 사용할 수 있는 셀레니움 4 기준으로 작성을 해보도록 하겠다.

 

FullScreenshot-useTagName.py

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 셀레니움 드라이버 실행
CHROME_DRIVER_PATH = 'C:/your/chromedriver/path/chromedriver.exe'
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(CHROME_DRIVER_PATH, options=options)
driver.maximize_window()

# url, 경로 설정
url = 'https://www.naver.com/'
path = 'TagName_Body.png'

#실행
driver.get(url)
time.sleep(1)
el = driver.find_element(By.TAG_NAME,'body')
el.screenshot(path)

 

위 답변 내용을 그대로 옮겨 보았다.

결과 - 실패

 

방법 1의 결과 - TagName_Body.png

 

내가 원하는 FullScreenshot이 나오지 않았다.

 

해당 답변 아래의 코멘트들. headless 옵션이 필수라고 한다.

 

답변을 보니 headless 옵션이 필수라고 한다.

내 경우에는 헤드리스를 사용할 수 없기 때문에 내 기준에는 적당하지 않은 코드이다.

 

1-2. headless O

혹시 headless를 하면 잘 될까 해서 headless 옵션을 넣고 다시 해봤다.

 

FullScreenshot-useTagName-2.py

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 셀레니움 드라이버 실행
CHROME_DRIVER_PATH = 'C:/your/chromedriver/path/chromedriver.exe'
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--start-maximized')
driver = webdriver.Chrome(CHROME_DRIVER_PATH, options=options)
# driver.maximize_window()

# url, 경로 설정
url = 'https://www.naver.com/'
path = 'TagName_Body-headlessOptions.png'

#실행
driver.get(url)
time.sleep(1)
el = driver.find_element(By.TAG_NAME,'body')
el.screenshot(path)

결과 - 실패

방법 1-2의 결과 - TagName_Body-headlessOptions

더 이상하게 나왔다ㅋㅋㅋㅋ.

 

FullScreenshot을 노리는게 아니라면 headless 옵션을 사용하지 않는 상태에서

캡쳐할 때 사용할 수 있을듯 하다.

하지만 전체 캡쳐에는 적합하지 않는것으로 보인다.


방법 2. Selenium-Screenshot 라이브러리를 이용하기 

역시 같은 게시물의 다른 답변을 통해서 접근할 수 있었다.

답변 캡쳐

라이브러리만 설치하면 아주 깔끔하게 짤 수 있었다.

관련 링크를 타고 들어가서 참고해가며 현재 버전에 맞게끔 수정해보았다.

 

FullScreenshot-useScreenshotLibrary.py

# 라이브러리 설치
pip install Selenium-Screenshot
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from Screenshot import Screenshot

# 셀레니움 드라이버 실행
CHROME_DRIVER_PATH = 'C:/your/chromedriver/path/chromedriver.exe'
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(CHROME_DRIVER_PATH, options=options)
driver.maximize_window()

# url 설정
url = 'https://www.naver.com/'

# 실행
ob = Screenshot.Screenshot()
driver.get(url)
time.sleep(1)

img_url = ob.full_screenshot(driver, save_path=r'.', image_name='Selenium-Screenshot.png', is_load_at_runtime=True, load_wait_time=3)

 

결과 - 애매함

방법 2의 결과 - Selenium-Screenshot.png

 

작동하는걸 보고있으면

로딩이 다 됐는지 확인하고 페이지의 크기에 맞게 직접 자동으로 스크롤을 내려가면서 캡쳐하고

여러 사진을 합친 다음에 경로에 저장하는것 같다.

 

스크롤  할 때 그냥 그대로 쭉 내려가는 페이지이면 나쁘지 않을 것 같은데, 
내가 캡쳐한 네이버 홈페이지처럼 웹페이지 상단부에 오브젝트가 함께 움직이는 경우

결과물이 좀 아쉽다.

 

근본적으로 전체를 캡쳐하는게 아니라,

스크롤을 조작하면서 캡쳐하는것이기 때문에 나타나는 현상으로 보인다.

 

좀 애매하긴 하지만 웹페이지에 스크롤시 따라다니는 오브젝트가 없다면 써볼법 한 라이브러리인것 같다.


방법 3. Chrome의 devtools protocol을 이용하기 

결론적으로 말하면 내가 가장 만족한 방법이다.

답변 캡쳐

 

추천 수는 좀 적지만, comment에 "non-headless" 상황에 동작한다는 말을 보고

재빨리 시도해보았다.

코드 윗부분이 스킵된듯이? 저렇게 ... 처리를 해놓기도 했고

다른 코드들처럼 selenium 옵션을 사용하지 않는거같아서 감이 잘 안왔었다.

그래서 이 사이트를 참고했다.

 

https://dev.to/gdledsan/selenium-4-and-chrome-driver-take-full-page-screenthos-2j8d

 

Selenium 4 and chrome driver, take full page screenshots

I spent some time playing with Selenium 4 trying to get a full page screenshot, this is what I found....

dev.to

이 홈페이지에서도 완벽히 다 써주지는 않았지만, 

주석이 써져있어서 바로 작성해 볼 수 있었다.

 

현재 버전에 맞추어 작성한 코드는 다음과 같다.

 

FullScreenshot-useChromeDevProtocol.py

import base64

# I am assuming we already have a driver object.
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 셀레니움 드라이버 실행
CHROME_DRIVER_PATH = 'C:/your/chromedriver/path/chromedriver.exe'
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(CHROME_DRIVER_PATH, options=options)
driver.maximize_window()

# url 설정
url = 'https://www.naver.com/'

# 실행
driver.get(url)
time.sleep(1)

# We need the dimensions of the content
page_rect = driver.execute_cdp_cmd('Page.getLayoutMetrics', {})

# parameters needed for ful page screenshot
# note we are setting the width and height of the viewport to screenshot, same as the site's content size
screenshot_config = {'captureBeyondViewport': True,
                             'fromSurface': True,
                             'clip': {'width': page_rect['cssContentSize']['width'],
                                      'height': page_rect['cssContentSize']['height'], #contentSize -> cssContentSize
                                      'x': 0,
                                      'y': 0,
                                      'scale': 1},
                             }
# Dictionary with 1 key: data
base_64_png = driver.execute_cdp_cmd('Page.captureScreenshot', screenshot_config)
# driver.execute_script("document.body.style.zoom='80%'")

# Write img to file
with open("chrome-devtools-protocol.png", "wb") as fh:
    fh.write(base64.urlsafe_b64decode(base_64_png['data']))

 

결과 - 성공

방법 3의 결과 - chrome-devtools-protocol.png

 

문제 없는 FullScreenshot이다.

완벽한 캡쳐다.

headless든지 non-headless든지 사용가능하다고 하니까 혹시 headless로 해야하는 경우

Chrome devtools protocol의 Cature Screenshot을 검색해 보길 바란다.

 

다만 주의점으로는 페이지가 다 로딩될때까지 time.sleep을 해줘야한다.
아니면 로딩 되기도 전에 캡쳐를 해버리기 때문에! 그 점만 조심한다면 전혀 문제 없을것이다.

 

예전부터 전체 스샷 저장하는걸 좀 찾고싶었는데

이번기회에 제대로 파보고 적당한 방법을 찾아서 속 시원하다.

 

 

 

 

 

혹시 코드 실행시 안되거나 게시물에 문제가 있는 경우 댓글 달아주시면

최대한 빠르게 답변할수 있도록 하겠습니다!!

 

 

 

#영어태그

full screen capture python selenium

how to capture full screeen in python using selenuim

 

반응형