2022년 5월 9일 월요일

python selenium, chrome driver 파일 저장시 저장 위치 설정 다운로드 완료시 까지 대기

 selenium을 사용하다보면 가끔 저장받는 파일 위치를 설정할 필요가 있는 경우가 있습니다. 기본적으로 브라우저를 사용하기 때문에 브라우저 저장 위치로 설정이 됩니다. 그리고 파일이 완벽하게 다운로드 될때까지 기다려야 할 필요도 있기 때문에 이 부분에 대해 정리해서 함수로 만들어 봤습니다.

기본 구성은 selenium을 래핑해서 간단하게 만들어 봤습니다. 다운로드 받는 위치는 기본적으로 브라우저가 생성될때 설정이 됩니다. 그래서 create_web_driver_chrome 함수를 통해서 경로를 설정해야하며 내부적으로는 절대 경로로 변경하는 self.download_path = os.path.abspath(download_path) 함수를 사용하였습니다.

또한 이전에 사용하였던 chromedriver_autoinstaller 를 이용해서 크롬 버전이 맞지 않더라도 자동으로 다운로드 하도록 구현하였습니다.

http url중 자동으로 다운로드가 걸리게 되는 링크들이 있는데 크롬은 다운로드가 시작되면 crdownload라는 확장자 파일이 생깁니다. (여기에서는 python 예전 버전 다운로드 링크를 예제로 담아봤습니다.) download_wait()에서 해당 파일의 크기를 주기적으로 확인해서 크기 증가가 발생하지 않으면 오류로 판단해서 리턴하게 됩니다.


import chromedriver_autoinstaller
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import os

class selenium_v1:
	def __init__(self):
		self.driver = None
		self.download_path = None
		return
		
	def create_web_driver_chrome(self, headless=True, download_path=None):
		options = webdriver.ChromeOptions()
		options.add_argument('disable-gpu')
		options.add_experimental_option('excludeSwitches',['enable-logging'])
		
		if headless:
			options.add_argument('headless')
		
		if download_path!=None:
			self.download_path = os.path.abspath(download_path)
			prefs = {"download.default_directory":self.download_path}
			options.add_experimental_option("prefs",prefs)
		
		if self.driver!=None:
			self.driver.close()
		self.driver = None
		
		chromedriver_autoinstaller.install()
		
		try:
			self.driver = webdriver.Chrome(options=options)
			self.driver.implicitly_wait(10)
		except Exception as e:
			print("exception",e)
		
		return self.driver
		
	def download_wait(self, timeout_min=1):
		if self.download_path==None:
			print("error can not find download path")
			return -2
		path_to_downloads = self.download_path
		seconds = 0
		dl_wait = True
		sum_after = 0
		while dl_wait and seconds < timeout_min*60:
			time.sleep(5)
			dl_wait = False
			sum_before = sum_after
			sum_after = 0
			for fname in os.listdir(path_to_downloads):
				if fname.endswith('.crdownload'):
					sum_after += os.stat(path_to_downloads+'/'+fname).st_size
					dl_wait = True
			if dl_wait and seconds > 10 and sum_before == sum_after:
				print("download timeout")
				dl_wait = False
				return -1
			seconds += 5
		return seconds
	
	def get(self,url):
		if self.driver == None:
			return -1
		return self.driver.get(url)
		
	def close(self):
		if self.driver == None:
			return -1
		return self.driver.close()
		
	def save_page_source(self, filename):
		if self.driver == None:
			return -1
		html = self.driver.page_source
		try:
			f = open(filename, 'w', encoding = 'utf-8')
			f.write(html)
			f.close()
		except:
			print("exception",e)
		return 0
		
if __name__ == "__main__":
	sel = selenium_v1()
	sel.create_web_driver_chrome(headless=True,download_path=".")
	print(sel.get("https://www.daum.net"))
	print(sel.driver.page_source)
	print(sel.get("https://www.python.org/ftp/python/3.9.11/python-3.9.11-embed-amd64.zip"))
	sel.download_wait()
	print(sel.driver.page_source)
	sel.save_page_source("test.html")


2023-03-28 업데이트

크롬드라이버가 버전업이 되면서 폴더 설정하는 부분이 동작 하지 않아서 소스 코드를 변경했습니다.

if headless:
# options.add_argument('headless')
# for chrome driver version up
options.add_argument('headless=new')

위와 같이 "headless=new" 로 변경해줘야하고

if sys.platform.startswith('win'):
self.download_path = self.download_path.replace("/", "\\")

path를 '/' 대신 "\" 를 사용해줘야 합니다. \\ 두개를 사용하는 이유는 \ 하나는 특수 문자라서 그렇습니다.

아래 변경한 전체 소스를 공유합니다.

Preview:

import chromedriver_autoinstaller
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import os
import sys

class selenium_v1:
	def __init__(self):
		self.driver = None
		self.download_path = None
		return
		
	def create_web_driver_chrome(self, headless=True, download_path=None):
		options = webdriver.ChromeOptions()
		options.add_argument('disable-gpu')
		options.add_experimental_option('excludeSwitches',['enable-logging'])
		
		if headless:
			# options.add_argument('headless')
			# for chrome driver version up
			options.add_argument('headless=new')
		
		if download_path!=None:
			self.download_path = os.path.abspath(download_path)
			if sys.platform.startswith('win'):
				self.download_path = self.download_path.replace("/", "\\")
			prefs = {"download.default_directory":self.download_path}
			options.add_experimental_option("prefs",prefs)
		
		if self.driver!=None:
			self.driver.close()
		self.driver = None
		
		chromedriver_autoinstaller.install()
		
		try:
			self.driver = webdriver.Chrome(options=options)
			self.driver.implicitly_wait(10)
		except Exception as e:
			print("exception",e)
		
		return self.driver
		
	def download_wait(self, timeout_min=1):
		if self.download_path==None:
			print("error can not find download path")
			return -2
		path_to_downloads = self.download_path
		seconds = 0
		dl_wait = True
		sum_after = 0
		while dl_wait and seconds < timeout_min*60:
			time.sleep(5)
			dl_wait = False
			sum_before = sum_after
			sum_after = 0
			for fname in os.listdir(path_to_downloads):
				if fname.endswith('.crdownload'):
					sum_after += os.stat(path_to_downloads+'/'+fname).st_size
					dl_wait = True
			if dl_wait and seconds > 10 and sum_before == sum_after:
				print("download timeout")
				dl_wait = False
				return -1
			seconds += 5
		return seconds
	
	def get(self,url):
		if self.driver == None:
			return -1
		return self.driver.get(url)
		
	def close(self):
		if self.driver == None:
			return -1
		return self.driver.close()
		
	def save_page_source(self, filename):
		if self.driver == None:
			return -1
		html = self.driver.page_source
		try:
			f = open(filename, 'w', encoding = 'utf-8')
			f.write(html)
			f.close()
		except Exception as e:
			print("exception", e)
		return 0
		
if __name__ == "__main__":
	sel = selenium_v1()
	sel.create_web_driver_chrome(headless=True, download_path=".")
	print(sel.get("https://www.daum.net"))
	print(sel.driver.page_source)
	print(sel.get("https://www.python.org/ftp/python/3.9.11/python-3.9.11-embed-amd64.zip"))
	sel.download_wait()
	print(sel.driver.page_source)
	sel.save_page_source("test.html")





댓글 없음:

댓글 쓰기