[왕초보 웹크롤링 무작정 따라하기] 웹크롤링, 셀레니움, 오류 무시, 오류 예외 만들기, Try, Except, Exception.
업무지옥을 탈출한 건에 대하여(feat.업무자동화)
#18 오류 무시/예외 처리(Try/Except)
Try / Except 사용하기 (바로가기 Click)
인스타그램(동적페이지)를 크롤링하기 위해 필수적인 코드들을 익혔다. 만들어둔 동작 자동화 코드에 .find 와 .text 메소드를 사용해 텍스트를 추출하면 된다. 브라우저 개발자 도구에서 경로를 추출하고 추출할 데이터에 맞게 수정해 코드에 넣어주었다. (브라우저 개발자도구에서 경로 파악하는 과정 생략)
#라이브러리 활성화
import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
#웹 열
dr = webdriver.Chrome()
wait = WebDriverWait(dr, 5)
dr.set_window_size(414, 800)
dr.get('https://www.instagram.com/')
dr.implicitly_wait(2)
#로그인
id_box = dr.find_element_by_css_selector("#loginForm > div > div:nth-child(1) > div > label > input")
password_box = dr.find_element_by_css_selector("#loginForm > div > div:nth-child(2) > div > label > input")
login_button = dr.find_element_by_css_selector('#loginForm > div > div:nth-child(3) > button')
act = ActionChains(dr)
act.send_keys_to_element(id_box, '아이디').send_keys_to_element(password_box, '비밀번호').click(
login_button).perform()
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#react-root > div > div > section > main > div > div > div > div > button')))
# 3.내 피드로 이동하기
# 3-1. 팝업 클릭하기
first_popup = dr.find_element_by_css_selector(
'#react-root > div > div > section > main > div > div > div > div > button')
first_popup.click()
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.RnEpo.Yx5HN > div > div > div > div.mt3GC > button.aOOlW.HoLwm')))
second_popup = dr.find_element_by_css_selector('div.RnEpo.Yx5HN > div > div > div > div.mt3GC > button.aOOlW.HoLwm')
second_popup.click()
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'section > nav > div._8MQSO.Cx7Bp > div > div > div.ctQZg > div > div:nth-child(6) > span')))
#프로필 사진 클릭하기
my_photo = dr.find_element_by_css_selector(
'section > nav > div._8MQSO.Cx7Bp > div > div > div.ctQZg > div > div:nth-child(6) > span')
my_photo.click()
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'section > nav > div._8MQSO.Cx7Bp > div > div > div.ctQZg > div > div:nth-child(6) > div.poA5q > div.uo5MA._2ciX.tWgj8.XWrBI > div._01UL2 > a:nth-child(1) > div')))
#프로필 버튼 클릭하기
profile = dr.find_element_by_css_selector(
'section > nav > div._8MQSO.Cx7Bp > div > div > div.ctQZg > div > div:nth-child(6) > div.poA5q > div.uo5MA._2ciX.tWgj8.XWrBI > div._01UL2 > a:nth-child(1) > div')
profile.click()
wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="react-root"]/div/div/section/main/div/header/div/div/div/button/img')))
dr.find_element_by_xpath('//*[@id="react-root"]/div/div/section/main/div/div[4]/article/div/div/div[5]/div[1]').location
#상대좌표 사용을 위한 스크롤 위치 지정
dr.execute_script("window.scrollTo(0, 479)")
scroll_location = dr.execute_script("return window.pageYOffset")
#동작/스크롤/크롤링 코드
while True:
# 로고 좌표 추출
standard_logo = dr.find_element_by_xpath('//section/nav/div[2]/div/div/div[1]/a/div/div')
for line in range(0, 4):
y = 110 + 175 * line
for box in range(0, 3):
x = 175 * box
#피드 마우스 오버
act = ActionChains(dr)
act.move_to_element(standard_logo).move_by_offset(x, y).perform()
#좋아요/댓글 수 크롤링
data = dr.find_elements_by_xpath('//article//ul/li')
likes = data[0].text
comments = data[1].text
print(likes)
print(comments)
# 649 씩 스크롤을 내림
dr.execute_script("window.scrollTo(0,{})".format(scroll_location + 648))
# 전체 스크롤이 늘어날 때까지 대기
dr.implicitly_wait(2)
scroll_height = dr.execute_script("return window.pageYOffset")
# 현재 스크롤 위치와 전체 스크롤 높이가 같으면(더 이상 스크롤이 늘어나지 않으면) 종료
if scroll_location == scroll_height:
break
# 같지 않으면 다음 조건 실행
else:
# 스크롤 이동 후 스크롤 위치값을 수정
scroll_location = dr.execute_script("return window.pageYOffset")
▲ xpath 경로 작성 및 텍스트 추출 관련 글
코드를 실행하니 좋아요와 댓글 순으로 개수가 프린트된다. 그런데 마지막에 오류가 발생한다?
문제의 원인은 인스타그램 피드에서 찾을 수 있었다. 코드 상 데이터를 추출해야 하지만 해당 위치의 피드가 비어있어 데이터를 추출하지 못하여 오류가 발생하는 것이다. 원래의 계획대로라면 더 이상 데이터를 추출할 피드가 없다면, 코드를 종료하게 만들어야 한다. 반대로 생각하면, 피드가 없어 발생하는 오류를 코드 종료로 바꿔주면 되는 것이다. 오류를 임의로 설정하는 코드는 Try와 Except로 만들 수 있다.
Try / Except 사용하기
Try와 Except문을 사용하면 오류가 발생하지 않았을 때는 코드가 순서대로 실행되지만, 오류가 발생했을 때는 except: 뒤에 오는 코드를 실행시킨다. 원래라면 오류 발생 시, 코드 실행이 멈추게 되지만 이를 통해 오류를 무시하거나 다른 결과로 출력할 수 있다.
code A try: code B code X except: code Y #code A를 수행하고 cod B를 실행한다. 오류가 없다면 code X를 실행하고 오류가 발생하면 code Y를 실행한다. |
|||
code B | 오류 없음 | 다음 코드 실행 | code X |
오류 발생 | except: 뒤의 코드 실행 | code Y |
이제 이를 코드에 적용시키면 된다. try: 뒤에는 원래 코드를 넣어주고, except: 다음에는 '데이터 수집이 종료되었습니다'가 출력하고 코드를 종료하게 만들어 보자. 그런데 try:를 어디에 넣어줘야 하는 걸까? 우선 데이터를 추출할 때 오류가 발생하니 데이터 추출코드 바로 직전에 넣어보았다.
#크롤링 반복코드
while True:
# 로고 좌표 추출
standard_logo = dr.find_element_by_xpath('//section/nav/div[2]/div/div/div[1]/a/div/div')
for line in range(0, 4):
y = 110 + 175 * line # 열 번호를 기준으로 175씩 y좌표를 더함
for box in range(0, 3):
x = 175 * box # 박스 번호를 기준으로 175씩 y좌표를 더함
#피드 마우스 오버
act = ActionChains(dr)
act.move_to_element(standard_logo).move_by_offset(x, y).perform()
#오류가 없을 때, 데이터 추출 실행
try:
#좋아요/댓글 수 크롤링
data = dr.find_elements_by_xpath('//article//ul/li')
likes = data[0].text
comments = data[1].text
print(likes)
print(comments)
#오류 발생시 메세지 출력 및 코드 종료
except:
print('데이터 수집이 종료되었습니다.')
break
dr.execute_script("window.scrollTo(0,{})".format(scroll_location + 648))
dr.implicitly_wait(2)
scroll_height = dr.execute_script("return window.pageYOffset")
if scroll_location == scroll_height:
break
else:
scroll_location = dr.execute_script("return window.pageYOffset")
실행시켜보니 뭔가가 잘못됐다. 종료되야할 시점에서 데이터를 한번 더 추출한다. 확인해보니 데이터 추출 코드를 끝내고 반복문 처음부터 다시 시작된 것이다. 오류 발생 시 for문 전체가 종료되게 try의 위치를 바꿔보자. for문 직전으로 try를 옮기고 except 위치도 수정해 주었다.
#크롤링 반복코드
while True:
# 로고 좌표 추출
standard_logo = dr.find_element_by_xpath('//section/nav/div[2]/div/div/div[1]/a/div/div')
#오류가 없을 때, 데이터 추출 실행
try:
for line in range(0, 4):
y = 110 + 175 * line # 열 번호를 기준으로 175씩 y좌표를 더함
for box in range(0, 3):
x = 175 * box # 박스 번호를 기준으로 175씩 y좌표를 더함
#피드 마우스 오버
act = ActionChains(dr)
act.move_to_element(standard_logo).move_by_offset(x, y).perform()
#좋아요/댓글 수 크롤링
data = dr.find_elements_by_xpath('//article//ul/li')
likes = data[0].text
comments = data[1].text
print(likes)
print(comments)
# 649 씩 스크롤을 내림
dr.execute_script("window.scrollTo(0,{})".format(scroll_location + 648))
# 전체 스크롤이 늘어날 때까지 대기
dr.implicitly_wait(2)
scroll_height = dr.execute_script("return window.pageYOffset")
# 현재 스크롤 위치와 전체 스크롤 높이가 같으면(더 이상 스크롤이 늘어나지 않으면) 종료
if scroll_location == scroll_height:
break
# 같지 않으면 다음 조건 실행
else:
# 스크롤 이동 후 스크롤 위치값을 수정
scroll_location = dr.execute_script("return window.pageYOffset")
#오류 발생시 메세지 출력 및 코드 종료
except:
print('데이터 수집이 종료되었습니다.')
break
수정된 코드를 실행시키니, 이번엔 반복 없이 정상적으로 데이터들이 추출되는 것을 확인할 수 있다. 이로써 동적 페이지 데이터 추출도 성공!
[system] '동적 페이지 크롤링'을 성공하였습니다.
'스킬: 오류 처리' 획득
승급자격을 획득하셨습니다.
현재 클래스 : 2 class
[보유 스킬]
오류처리, 동작제어, 자바스크립트 활용,
주문가속, 주문중첩, 주문연계,
데이터시각화, 데이터필터링, 웹데이터 소환
[보유 칭호]
브라우저를 제어하는 자, 웹데이터를 불러내는 자
'데이터 스킬업 > 웹크롤링' 카테고리의 다른 글
[파이썬:웹크롤링] #20 셀레니움과 input으로 로그인 하기 for 인스타그램 (0) | 2022.01.16 |
---|---|
[ep01:웹크롤링] #19 인스타그램 웹크롤링 자동화(예제) with 파이썬 (0) | 2021.08.13 |
[ep01:웹크롤링] #17 셀레니움 로딩될 때까지 시간/조건 설정하기 with 파이썬 (1) | 2021.08.05 |
[ep01:웹크롤링] #16 셀레니움 스크롤 조절하기 with 파이썬 (0) | 2021.08.03 |
[ep01:웹크롤링] #15 셀레니움 절대좌표/상대좌표 활용하기 with 파이썬 (2) | 2021.08.02 |
댓글