본문 바로가기
IT

우분투에서 크롬 드라이버와 Selenium으로 headless(헤드리스) 웹 크롤링 문제 해결하기

by developer's warehouse 2024. 9. 23.

크롬 드라이버와 셀레니엄을 통해 로그인을 하는데 headless로 했더니 아래와 같이 버튼 클릭시 에러가 납니다. 

오늘은 헤드리스로 느린 우분투 서버에서 동작시킬때 왜 문제가 발생하는지 알아보겠습니다. 

우분투에서 크롬 드라이버와 Selenium으로 headless(헤드리스) 웹 크롤링 문제 해결하기

Traceback (most recent call last):
  File "web-tools/ss-crawling/apiSellout.py", line 31, in main
    inStockOriginProductsNo.extend(crawlerupick.checkInStockAPI(productsCodes))
  File "/home/ubuntu/web-tools/ss-crawling/crawlerUPick.py", line 840, in checkInStockAPI
    inStockCodes = self.checkInStock(sellerCodes)
  File "/home/ubuntu/web-tools/ss-crawling/crawlerUPick.py", line 849, in checkInStock
    self.login()
  File "/home/ubuntu/web-tools/ss-crawling/crawlerUPick.py", line 73, in login
    login_button.click()
  File "/home/ubuntu/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 94, in click
    self._execute(Command.CLICK_ELEMENT)
  File "/home/ubuntu/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webelement.py", line 395, in _execute
    return self._parent.execute(command, params)
  File "/home/ubuntu/venv/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 354, in execute
    self.error_handler.check_response(response)
  File "/home/ubuntu/venv/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <a href="#none" class="btnSubmit gFull size                                              L" onclick="MemberAction.login('member_form_4077296188'); return false;">...</a> is not clickable at point (382, 389). Other element would receive t                                              he click: <ul class="bottom-nav__tabBar">...</ul>
  (Session info: chrome=129.0.6668.58)
Stacktrace:
#0 0x55ecf457413a <unknown>
#1 0x55ecf425a5e0 <unknown>
#2 0x55ecf42b0866 <unknown>
#3 0x55ecf42ae78d <unknown>
#4 0x55ecf42ac237 <unknown>
#5 0x55ecf42ab646 <unknown>
#6 0x55ecf429ea98 <unknown>
#7 0x55ecf42ceb22 <unknown>
#8 0x55ecf429e478 <unknown>
#9 0x55ecf42cecee <unknown>
#10 0x55ecf42edd7d <unknown>
#11 0x55ecf42ce8c3 <unknown>
#12 0x55ecf429c6b3 <unknown>
#13 0x55ecf429d68e <unknown>
#14 0x55ecf453eb3b <unknown>
#15 0x55ecf4542ac1 <unknown>
#16 0x55ecf452b335 <unknown>
#17 0x55ecf4543642 <unknown>
#18 0x55ecf451049f <unknown>
#19 0x55ecf4563038 <unknown>
#20 0x55ecf4563203 <unknown>
#21 0x55ecf4572f8c <unknown>
#22 0x7f3d41f87609 start_thread


먼저 위의 에러에서 ElementClickInterceptedException 오류는 클릭하려는 요소가 페이지의 다른 요소에 의해 가려지거나, 클릭이 가로채졌을 때 발생합니다. 

주로 headless 모드에서 발생하는 이유는 화면 크기나 렌더링 속도 차이 때문에 페이지 레이아웃이 달라지기 때문입니다.

이 문제를 해결하기 다음의 몇 가지 방법을 적용해볼 수 있습니다:

1. 명시적 대기(Explicit Wait) 사용하기

페이지가 완전히 로드되기 전에 클릭을 시도할 경우 발생할 수 있는 문제를 해결할 수 있습니다. 요소가 클릭 가능한 상태가 될 때까지 기다리도록 코드를 수정합니다.

find_element와 같은걸 대신해서 element_to_be_clickable로 바꿔서 대기해 봅니다. 

def login(self):
    # Explicit wait to ensure the login button is clickable
    wait = WebDriverWait(self.driver, 10)
    login_button = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "btnSubmit")))
    
    # Try clicking the login button
    login_button.click()

 

2. JavaScript로 클릭 실행하기

headless 모드에서 발생하는 화면 요소 문제를 피하기 위해 JavaScript를 통해 강제로 클릭할 수 있습니다.

click()을 호출하는 대신에 execute_script 안에 click()을 넣어서 javascript를 강제로 호출하는 방법을 사용해 봅니다. 

def login(self):
    # Locate the login button
    login_button = self.driver.find_element(By.CLASS_NAME, "btnSubmit")
    
    # Use JavaScript to click the button
    self.driver.execute_script("arguments[0].click();", login_button)

3. 화면 크기 설정

headless 모드에서 화면 크기를 설정하지 않으면 기본적으로 매우 작은 크기로 설정되기 때문에, 요소가 화면 밖에 있을 수 있습니다. 이 문제는 특히, 크롤링 할 때 헤드리스를 사용하면 다른 문제를 발생시킬 수도 있으므로 화면 크기는 꼭 적절하게 설정해 주어야 합니다. 
아래와 같이 add_argument에 window-size=1920x1080을 넣어줍니다.

    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    
    # Set the window size
    chrome_options.add_argument("window-size=1920x1080")
    
    driver = webdriver.Chrome(options=chrome_options)

 

 

4. headless 모드 사용 중지

만약 위의 방법으로 다 해봤는데 해결되지 않는다면, headless 모드를 일시적으로 중지하고 디버깅을 해야합니다. ㅠㅠ

페이지가 실제로 어떻게 렌더링되는지 확인하면서 디버깅 해봐야 합니다. ㅠㅠ 

5. 결론 

headless 모드를 사용하면 일반 화면과 기본적으로 다르게 동작하는 것이 윈도우 크기이므로, 윈도우 크기는 기본적으로 꼭 설정해주시고, 느린 장비에서 버튼을 대기하는 시간을 가질 수 있도록 해주는 것이 중요합니다. 

이상으로 저는 문제가 해결되었습니다. 

다른 분들도 위의 방법으로 해결되길 바랍니다~

오늘도 수고하셨습니다. 

facebook twitter kakaoTalk kakaostory naver band shareLink