소스 공유

|  나만의 소스나 나만 알고 있는 좋은 소스를 서로 공유하는 자리입니다.

조회 수 65 추천 수 2 댓글 2
Atachment
첨부 '1'
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
Extra Form
라이선스 MIT

안녕하세요?


Selenium을 이용하여 웹페이지의 특정 element를 캡처하는 스크립트를 작성해보았습니다.


일반적인 윈도우의 캡처 프로그램(픽픽 등)은 element를 선택하여 캡처할 수는 없다고 알고 있네요.


물론 아래 URL에 소개된 것처럼 크롬 개발자도구를 이용하여 element를 캡처하는 방법이 있지만요.


https://umaar.com/dev-tips/156-element-screenshot/


그래서 이 스크립트를 작성하게 되었습니다.



여러모로 부족한 점이 많지만 이 스크립트의 대략적인 구동방법을 말씀드리자면 


Selenium으로 웹페이지에 접속한 후에 해당 element의 위치와 크기를 구하고


전체 화면을 캡처한 후에 element의 위치와 크기에 알맞게 crop을 하는 방법을 택했습니다.


Selenium 이외에도 이미지처리와 관련하여 Pillow를 필요로 합니다.



Stackoverflow 등에 관련된 Q&A가 있었지만 제가 직접 구동해보니 약간의 문제가 있었습니다.

https://stackoverflow.com/questions/13832322/how-to-capture-the-screenshot-of-a-specific-element-rather-than-entire-page-usin


제가 구글링 실력이 부족한지 제대로 작동하는 스크립트를 찾지는 못했어요 ㅠㅠ


단순히 get_screenshot_as_png를 이용하면 element가 화면보다 긴 경우에 짤리는 문제가 발생하더군요.


Stackoverflow에 location 대신에 location_once_scrolled_into_view를 이용하면 된다는 리플도 있었지만


element가 아주 길어지면 역시 중간에서 짤리더군요 ㅠㅠ


그래서 주먹구구식이기는 하지만 일단 전체 페이지의 사이즈를 구하고


브라우저의 창 크기를 그에 맞게 확대한 후에 스크린캡처를 하는 방법을 택했습니다.


이것이 최선의 방법은 아닐 것 같지만 일단 제가 테스트한 바로는 잘 작동하네요 ^^



from selenium import webdriver
from PIL import Image
from io import BytesIO
from selenium.webdriver.firefox.options import Options

options = Options()
options.headless = True
driver = webdriver.Firefox(options=options)
driver.get(캡쳐할 웹페이지의 주소)

# 전체 페이지의 사이즈를 구하여 브라우저의 창 크기를 확대하고 스크린캡처를 합니다.
page_width = driver.execute_script('return document.body.parentNode.scrollWidth')
page_height = driver.execute_script('return document.body.parentNode.scrollHeight')
driver.set_window_size(page_width, page_height)
png = driver.get_screenshot_as_png()

# 특정 element의 위치를 구하고 selenium 창을 닫습니다.
element = driver.find_element_by_class_name(캡쳐할 element의 class)
image_location = element.location
image_size = element.size
driver.quit()

# 이미지를 element의 위치에 맞춰서 crop 하고 저장합니다.
im = Image.open(BytesIO(png))
left = image_location['x']
top = image_location['y']
right = image_location['x'] + image_size['width']
bottom = image_location['y'] + image_size['height']
im = im.crop((left, top, right, bottom))
im.save('저장할 파일명.png')



제가 이 스크립트를 작성하면서 느낌 점이 있는데 Selenium이 굉장히 민감한 것 같아요 ㅠㅠ


구글링을 해보니 크롬과 파이어폭스에 따라 캡처된 결과물이 다르다고 하더군요.

(대체로 스크린캡처와 관련해서는 파이어폭스를 조금 더 추천하는 것 같더군요)


그리고 제가 테스트해본 바로는 headless 모드와 일반 모드에 따라 캡처된 결과물이 달라지는 경우도 있었어요.



여러모로 부족한 글 읽어주셔서 감사합니다 ^^


그럼 내일부터 또 더워진다는데 스포어 회원님들께서도 항상 건강하세요!



+)


humit 님의 https://studyforus.com/freeboard/583864 게시물에서 .board-wrapper를 캡처해봤어요 ^-^



  • profile
    title: 황금 서버 (30일)humit 2019.07.10 00:44
    Firefox는 잘 모르겠지만 크롬의 경우에는 headless 모드와 일반 모드일 때 윈도우 사이즈가 동일하더라도 화면의 사이즈가 달라지더라고요.
    화면 사이즈만 동일하게 맞춰주면 UI 상으로는 크게 차이가 없는 것처럼 보였습니다.
  • profile
    이니스프리 2019.07.10 00:58
    옙 구글링해보니 Stackoverflow 등에서는 humit 님께서 말씀하신 그런 이유도 있고 해서
    스크린 캡쳐와 관련해서는 대체로 파폭을 더 추천하는 분위기이더군요.

    그런데 이 스크립트가 윈도우에서는 분명히 잘 작동하는데
    VPS에서 테스트를 해보니 에러가 나는 경우가 많더군요.
    from pyvirtualdisplay import Display로 display를 지정해봐도 마찬가지이구요.
    Stackoverlfow를 검색해보니 파폭을 업데이트하거나 아예 낮은 버전을 쓰라고 되어 있어서 둘 다 시도해봤는데 잘 안 되더군요.
    항상 안 되는 것은 아니고 시스템을 reboot를 하고 다시 시도해보면 어쩌다가 한 번 캡쳐가 되기도 하던데요.
    geckodriver.log를 봐도 실행할 때마다 에러로그가 달라서 정확한 원인을 찾지 못했네요 ㅠㅠ
    제 추측으로는 상하로 긴 element를 png 파일로 저장할 때 시스템 리소스가 부족한 것이 아닌가 하는 생각도 드네요.

    humit 님께서 해결해주신 PyQt의 GUI 문제와 더불어 우분투에서 Selenium의 문제까지 겹쳐서
    요새 며칠 파이썬 대신 C#이나 C++을 공부해야 되는 것이 아닌가 하는 생각마저 들었네요 ㄷㄷ

    그럼 humit 님께서도 편안한 밤 되시고 안녕히 주무세요 ^^
    늘 진심으로 감사드립니다!

소스 공유

나만의 소스나 나만 알고 있는 좋은 소스를 서로 공유하는 자리입니다.

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
63 코드 [아미나] Dropbox API를 이용한 이미지 호스팅 보드스킨 11 file 이니스프리 2019.07.13 97
62 코드 [Python] 네이버 모바일 이미지 검색에서의 이미지 파일을 멀티스레드로 다운받고 1개의 파일로 병합 10 file 이니스프리 2019.07.12 86
61 코드 [PHP/Javascript] 아미나에 자동으로 게시글을 생성하고 Ajax로 전송하여 결과를 표시하기 2 file 이니스프리 2019.07.09 34
» 코드 [Python] Selenium을 이용하여 특정 element를 캡처하는 스크립트 2 file 이니스프리 2019.07.03 65
59 코드 [Python] 선택한 파일을 Dropbox API를 이용하여 업로드하고 공유링크를 받아서 이미지 호스팅 용도로 URL을 변환하기 file 이니스프리 2019.07.02 66
58 자바스크립트 미니 시계 7 도토리묵 2019.02.22 308
57 코드 [JS]클라이언트에서 Ip를 얻어보자 2 title: 500포인트로 초록불 SSL!!Hanam09 2019.01.21 268
56 코드 [JS] http를 https로 리디렉션! 3 title: 500포인트로 초록불 SSL!!Hanam09 2018.12.30 309
55 코드 [PHP] 이미지를 원하는 크기(원본비율 유지)로 리사이즈 하여 출력 (원본 이미지는 수정하지 않습니다) 6 이니스프리 2018.12.20 818
54 코드 [아미나] 네이트 실시간 검색어 순위 위젯 (아미나 캐시 적용) 3 file 이니스프리 2018.12.18 248
53 코드 [아미나] 출석 여부를 나타내는 메인화면 위젯 4 file 이니스프리 2018.12.15 314
52 코드 [PHP] 간단한 캐싱 클래스 3 title: 황금 서버 (30일)humit 2018.12.06 276
51 코드 [Python] 텔레그램을 이용한 게시판 새 글 알림봇 7 이니스프리 2018.12.02 615
50 코드 [아미나] 게시글을 작성하면 ID와 IP로 필터링하여 자동으로 랜덤 댓글을 남기기 (+랜덤 포인트) 7 file 이니스프리 2018.11.18 183
49 코드 [PHP] 그누보드 자동 게시글 작성 - 일본기상협회의 우리나라 날씨를 크롤링한 후 파파고로 번역하여 글 작성 4 file 이니스프리 2018.11.15 174
48 코드 [PHP] 기상청 RSS 시간별 예보 위젯 - cache 적용(?) 9 file 이니스프리 2018.10.28 150
47 코드 [오토핫키] 브라우저를 열어 지난번과 동일한 폴더에 MZK를 다운받고 압축을 네이티브로 해제하는 스크립트 file 이니스프리 2018.10.20 218
46 코드 [PHP] 기상청 중기예보를 캐러셀로 보여주는 위젯 (매우 허접합니다 ㅠㅠ) 10 file 이니스프리 2018.09.28 179
45 코드 [오토핫키] 구글 드라이브의 공유링크를 이미지 호스팅을 위한 다이렉트 링크로 바꿔주는 스크립트 10 file 이니스프리 2018.09.25 616
44 코드 [오토핫키] 특정 사이트에 대한 ping 테스트 결과를 실행시간과 함께 로그 파일로 저장하는 스크립트 2 이니스프리 2018.09.22 335
목록
Board Pagination Prev 1 2 3 4 Next
/ 4
서버에 요청 중입니다. 잠시만 기다려 주십시오...