[토이 프로젝트] 자동 갱신 게임 명부 제작(3) - 스크래핑 오류 다루기

chaejm55·2022년 4월 16일
0

0. 이번 단계 진행 아이디어

selenium exception에 여러 스크래핑 중 발생가능한 exception이 정의 되어 있으니깐 이걸 이용해서 오류를 다뤄보자! 😀

1. 갱신 중 발생 가능한 예외 찾아보기

1) NoSuchElementException

존재하지 않는 캐릭터명을 검색했을 때 발생하는 오류입니다. 캐릭터 검사 페이지가 아닌 다른 페이지로 이동 되므로 우리가 찾는 element가 존재하지 않아서 Exception이 발생합니다. 또는 웹페이지 구조 변경으로 해당 element 변경 시에도 발생합니다.

2) unexpected alert open

잠시 후 다시 갱신 요청이나 캐릭터명 변경 혹은 캐릭터 삭제로 갱신이 불가능한 경우 등에 Alert 창이 생성됩니다. 예상되지 않은 Alert창이 생성되었으므로 Exception이 발생합니다.

3) AttributeError

빈 값을 가져와서 그 값으로 메서드 실행 등을 하려 할 때 발생하는 Error입니다. 해당 값이 비어 있거나, 해당 element 로딩 전에 값을 가져와 Error가 발생합니다.

2. selenium exception 살펴보기

selenium.common.exceptions에 많은 exception 들이 있으니 이를 활용하여 위의 예외들을 처리해보았습니다.

1) NoSuchElementException

앞서 언급했던 NoSuchElementException입니다. 해당 오류 발생 시 페이지 구조 변경이나 페이지 로딩 완료 여부 등을 확인해야합니다.
wait 등을 활용할 수도 있는데 이는 다음 포스팅에서 다루겠습니다.

2) UnexpectedAlertPresentException

앞서 언급했던 unexpected alert open입니다. alert 창을 닫고 다음 작업을 진행해야합니다.

3) WebDriverException

selenium webdriver exception의 base exception입니다. 해당 exception을 except절에 사용하여 webdriver exception들을 예외처리 가능합니다.

AttributeError는 파이썬 Error이므로 따로 더 다루지는 않겠습니다.

3. try ~ exception 블록 작성하기


import gspread
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, UnexpectedAlertPresentException, WebDriverException
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager


def main():
    ...
    
    for character in character_list:
        if character == '' or character in worlds:
            continue
        base_url = 'https://maple.gg/u/'
        url = base_url + character
        try:
            driver.get(url)  # 검색 결과 페이지로 이동
        except UnexpectedAlertPresentException:
            print("일시적인 오류이거나 캐릭터명이 변경 혹은 삭제되었습니다.")
            driver.get(url)
        except WebDriverException:
            print("웹 페이지 로딩 중 오류가 발생했습니다.")
            continue

        try:
            refresh = driver.find_element(by=By.XPATH, value='//*[@id="btn-sync"]')  # 갱신버튼 가져오기
        except NoSuchElementException:
            print("올바르지 않은 캐릭터명이거나 올바르지 않은 경로입니다.")
        else:
            try:
                refresh.click()  # 갱신버튼 클릭
            except AttributeError:
                print("웹 페이지 로딩이 완료되지 않았거나 일시적인 오류입니다.")
        time.sleep(3)  # 갱신 시간 기다림


if __name__ == '__main__':
    main()

  • driver.get(): 웹 페이지 로드 중에 여러 에러가 발생가능하므로 WebDriverException으로 예외처리를 합니다. alert가 남아 있으면 페이지 로드에 문제가 발생하니 UnexpectedAlertPresentException으로 처리해줍니다.
  • refresh = driver.find_element(): 갱신버튼의 경로가 올바르지 않으면 NoSuchElementException으로 예외처리를 합니다.
  • refresh.click(): 갱신버튼이 올바르게 존재하면 click 합니다. alert 창이 뜨거나 AttributeError가 발생할 수 있으므로 각각 예외처리를 해줍니다.

4. 다음 고민

time.sleep()로 무작정 기다리는 대신에 좀 더 깔끔하게 갱신을 기다리는 방법은 없을까? 🤔

5. Reference

Selenium 4.1.0 documentation

profile
여러가지를 시도하는 학생입니다

1개의 댓글

comment-user-thumbnail
2022년 12월 13일

예외처리문을 무한루프 돌리면 sleep()할 필요가 없더라고요.

while True:
try:
...
break
except:
continue

좋은 방법일지는 모르겠지만 sleep()보다는 빠릅니다.

답글 달기