Selenium을 주로 크롤링 할 때 사용하다보니 따로 다뤄볼 일이 없었다. 그러다가,PC를 켜면 항상 실행하고 로그인해야 하는 웹이 몇개 있는데 이 과정들을 자동화하기로 하였다. 가장 먼저 해야할 일은 웹을 한번에 여러개 실행할 수 있도록 탭을 여러개 띄우는 것이었다. 구글링을 하여 방법을 찾아봤는데 꽤 많은 방법들이 있었다. 그런데, 링크를 가진 요소를 찾아서 [ Ctrl ] + [ Mouse Click ] 이벤트를 발생시키거나, 버전이 안맞아서 그런지 정상적으로 동작하지 않는게 대부분이었다. 그래서, 좀 더 찾다가 가장 깔끔하다고 생각하는 방법을 소개하려고 한다.
1. 예제 소스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import selenium.webdriver.support.ui as ui from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.common.keys import Keys from selenium.webdriver import ActionChains #chromedriver 경로 설정 CHROMEDRIVER_PATH = './chromedriver.exe' chrome_options = Options() chrome_options.add_argument('--start-maximized') #브라우저 실행 및 탭 추가 driver = webdriver.Chrome( executable_path=CHROMEDRIVER_PATH, chrome_options=chrome_options ) driver.execute_script('window.open("about:blank", "_blank");') driver.execute_script('window.open("about:blank", "_blank");') tabs = driver.window_handles # TAB_1 driver.switch_to_window(tabs[0]) driver.get('//www.naver.com/') # TAB_2 driver.switch_to_window(tabs[1]) driver.get('//www.google.com/') # TAB_3 driver.switch_to_window(tabs[2]) driver.get('//heodolf.tistory.com/') | cs |
- 18~19 ln: driver.execute_script()를 이용하면 javascript를 실행할 수 있음.
*여기서 새 탭을 생성하는 Javascript를 작성. window.open("about:blank", "_blank");
- 21 ln: driver.window_handles에는 현재 열려있는 탭 리스트가 있음.
- 24 ln: driver.switch_to_window() 함수로 탭을 자유롭게 전환할 수 있음.
2. 실행 결과.
3. 마치며
- 새로운 탭을 여러개 사용하는 방법에 대해서 찾아보다가, selenium으로 javascript 까지도 실행할 수 있다는 것을 알게되었다. 이걸 잘만 활용하면 유용하게 쓸 수 있을것 같다.
- 그리고 Seleninum을 실행했을 때, 'Chrome이 자동화된 테스트 소프트웨어에 의해 제어되고 있습니다.' 이 문구가 거슬린다. 다음 포스트에서는 이 문구를 지우는 방법에 대해서 알아보도록 하겠다.
파이썬 multiprocessing 이용해서 selenium 창 여러개 띄워서 하는방법도 괜찬을거같아요 ㅋㅋㅋ 근데 여러 프로세스에서 동시에 하나의 엑셀파일에 접근할순 없을거 같으니, 엑셀파일 내용을 csv로 옮긴 다음에 각 셀에 index를 메기고 각각의 프로세스에서 index범위에 따라서 파싱을 해오는 방법도 괜찬을거같아요 그리고 selenium쓰면 브라우저 열고, 검색하고 이런과정을 직접 사용자가 하는 방식이랑 똑같이 하기때문에 resource도 많이 잡아먹고 속도가 상당히 느려요!! beautifulSoup+ request쓰면 바로 http request요청으로 (client-side 렌더링 제외 왠만한 경우면) 더빠르게 가져올수있는데 그것도 속도를 올릴수있는 괜찬은 방법인거같아요 ^^
크롤링을 병렬로 처리하고 싶어요. 셀레니움으로 webdriver를 사용하는데 멀티쓰레딩이 안 돼요!
pathos를 써도 안 돼요!
멀티프로세싱과 멀티쓰레딩이 다른 의미긴 하지만 multiprocessing 모듈을 사용하기 떄문에 제목에 멀티프로세싱이라고 적어두었다..
웹드라이버는 멀티쓰레딩을 지원하지 않기 때문에 안 된다. multiprocessing 모듈을 사용할수가 없다.
이 원인을 찾으려고 얼마나 뒤졌는지..ㅠㅠ
//stackoverflow.com/questions/30808606/can-selenium-use-multi-threading-in-one-browser
Can Selenium use multi threading in one browser?
I want to test a web in multi threading but when I open too many chromedrivers they use too much memory. Can I use multi threading in one browser?
stackoverflow.com
해결법
프로세스마다 webdriver를 각각 생성해서 만들어준다.
한 브라우저에 탭을 이용하는게 아니고, 브라우저 여러개를 띄우면 된다.
from pathos.multiprocessing import ProcessingPool as Pool #pip install pathos class Parser(Subject): def __init__(self): self.pool = Pool(processes=3) """웹드라이버가 여기에 있으면 오류가 난다! 웹드라이버는 싱글스레드라서!""" # self.driver = webdriver.Chrome('./chromedriver.exe') def open_browser(self, site): """ process별로 브라우저를 따로 열어주면 오류가 안 난다 """ driver = webdriver.Chrome('./chromedriver.exe') driver.get(site) def multi_processing(self): sites = ['//www.naver.com', '//www.daum.net', '//www.tistory.com'] pool.map(open_browser, browsers) parser = Parser() parser.multi_processing()pathos multiprocess를 쓰는 게 정신건강에 좋다.
일반 pool은 top-level method에만 쓸 수 있기 때문이다.
pathos는 다른 클래스 내 메소드, 같은 클래스 내 다른 메소드에도 쓸 수 있다!
안 되는 걸 되게 하는 pathos ↓
//stackoverflow.com/questions/3288595/multiprocessing-how-to-use-pool-map-on-a-function-defined-in-a-class
Multiprocessing: How to use Pool.map on a function defined in a class?
When I run something like: from multiprocessing import Pool p = Pool(5) def f(x): return x*x p.map(f, [1,2,3]) it works fine. However, putting this as a function of a class: class calculate(
stackoverflow.com