티스토리 뷰

캡스톤 진행하면서 데이터를 수집해야 하는 상황이 생겼습니다.
그래서 BeautifulSoup , Selenium을 간단히 학습해 보았습니다.
단기간에 학습한 내용을 정리한 글로 더 많은 정보를 얻고 싶으신 분들은 구글링을 하시는 것을 추천드립니다 :)
저도 극 일부만 사용을 했습니다 ㅎㅎ

 

"나도 코딩"님의 인프런 무료 강의를 통해 간단하게 selenium 사용법들을 살펴보고,
네이버 항공권 사이트에서 text를 가져와보는 실습을 진행했습니다.

 

[준비 과정]

먼저, 스크래핑을 하기 위한 준비를 합시다.

1. pip install selenium

2. chromedriver 다운로드하기

chrome://version/  를 주소창에 입력하고, chrome에서 버전을 확인합니다.

해당 버전의 chrome driver를 깔아줍니다. => 저는 참고로 96 버전입니다.

https://chromedriver.chromium.org/downloads 

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 98, please download ChromeDriver 98.0.4758.48 If you are using Chrome version 97, please download ChromeDriver 97.0.4692.71 If you are using Chrome version 96, please download ChromeDriver 96.0.4664.45 For o

chromedriver.chromium.org

 

 

지금까지 잘 수행되었는지, 확인해 봅니다.

from selenium import webdriver

browser = webdriver.Chrome("./chromedriver") # 다운 받은 chromedriver 경로
browser.get("https://www.naver.com/") # 브라우저 이동

 

** chromedriver에서 개발자 확인할 수 없어~~ 경고가 뜬다면,

 

1. chromedriver가 있는 경로로 터미널에서 이동

2. 아래의 명령어 실행

xattr -d com.apple.quarantine chromedriver

 

실행시켰을 때, 브라우저가 열리고 "자동화된 테스트 소프트웨어에 의해 제어되고 있습니다."가 뜨면 성공!

 

[기본 문법]

1. 네이버로 접속해, class 이름이 link_login인 element를 찾아서 클릭하고, 창을 뒤, 앞, 새로고침

 

from selenium import webdriver
from selenium.webdriver.common.by import By

browser = webdriver.Chrome("./chromedriver")
browser.get("https://www.naver.com/")

elem = browser.find_element(By.CLASS_NAME,"link_login") # 뷰티풀 숲 find와 비슷
elem.click() # click
browser.back() # 창 뒤로 가기
browser.forward() # 창 앞으로 가기
browser.refresh() # 창 새로고침

 

2. 네이버 검색창에 오미크론 검색 

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys # ENTER를 위해 불러옴 앞에 k는 소문자 뒤에 K는 대문자임

browser = webdriver.Chrome("./chromedriver")
browser.get("https://www.naver.com/")

elem = browser.find_element(By.ID,"query")
elem.send_keys("오미크론") # 오미크론 입력

elem.send_keys(Keys.ENTER) # k 대문자

elems = browser.find_elements(By.TAG_NAME,"a")

for elem in elems:
    href = elem.get_attribute("href") # attr 가져오기
    print(href)

 

3. 브라우저 아예 종료 or 탭 하나 삭제

browser.quit() # 브라우저 아예 종료
browser.close() # 탭 하나 삭제

 

4. 사실 selenium document가 가장 친절합니다 ㅎㅎ

https://selenium-python.readthedocs.io/

 

Selenium with Python — Selenium Python Bindings 2 documentation

Note This is not an official documentation. If you would like to contribute to this documentation, you can fork this project in GitHub and send pull requests. You can also send your feedback to my email: baiju.m.mail AT gmail DOT com. So far 50+ community

selenium-python.readthedocs.io

from selenium.webdriver.common.by import By

driver.find_element(By.XPATH, '//button[text()="Some text"]')
driver.find_element(By.ID, '')
driver.find_element(By.NAME, '')
driver.find_element(By.LINK_TEXT, '')
driver.find_element(By.PARTIAL_LINK_TEXT)
driver.find_element(By.TAG_NAME, '')
driver.find_element(By.CLASS_NAME, '')
driver.find_element(By.CSS_SELECTOR, '')

driver.find_elements(By.XPATH, '//button')

find_element는 해당 요소 첫 번째 하나를 가져오고, find_elements는 여러 요소들을 가져옵니다.

요소 가져오는 것 이외에도 스크롤 이동, 창 사이즈 조절, 창 사이즈 최대화, 스크린 숏 등.. 다양한 기능들을 제공하고 있습니다.

 

5. 네이버 항공권에서 

가는 날 선택 -> 이번 달 24일, 27일 선택 -> 도착지 버튼 누르기 (일본, 도쿄, 항공권 검색) -> 결과 text들 뽑아내기

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC 
# 바로 위의 2줄은, Explicit Waits을 위해서 사용
# 코드가 더 진행 되기 전 특정 조건이 발생할 때까지 기다리도록 정의하기 위해 사용

options = webdriver.ChromeOptions()
options.add_argument("user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36")

browser = webdriver.Chrome("./chromedriver", options=options)
# browser.set_window_position(0,0) # 브라우저 창의 좌측상단 점이 모니터 화면 어디에서 시작할지 결정
# browser.set_window_size(700,1000) # 가로 700, 세로 1000으로 설정

browser.get("https://flight.naver.com/")
# browser.maximize_window() # 창 최대화 

# 스크롤 이동 (아래로 500px)
browser.execute_script("window.scrollTo(0, 500)")

# 가는날 선택
browser.find_element(By.CLASS_NAME, 'tabContent_option__2y4c6').click()

# class 이름이 'sc-dIsUp' element가 모두 등장할때 까지 기다림 (15초 이내에서 수행되면 다음 동작 진행 / 15초 초과시 에러 발생)
wait = WebDriverWait(browser, 15)
elements = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'sc-dIsUp')))

# 이번달 24일, 27일 선택
browser.find_elements(By.CLASS_NAME, 'sc-dIsUp')[23].click()
browser.find_elements(By.CLASS_NAME, 'sc-dIsUp')[26].click()

# 도착지 버튼 누르기
browser.find_elements(By.CLASS_NAME, 'tabContent_route__1GI8F')[1].click() 
browser.find_elements(By.CLASS_NAME, 'autocomplete_Collapse__tP3pM')[1].click() # 일본
browser.find_elements(By.CLASS_NAME, 'autocomplete_Airport__3_dRP')[1].click() # 도쿄
browser.find_element(By.CLASS_NAME, 'searchBox_search__2KFn3').click() # 항공권 검색 버튼 누르기

wait = WebDriverWait(browser, 20)
element = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'result')))
    
elems = browser.find_elements(By.CLASS_NAME, 'result')
for elem in elems:
    print(elem.text)
    
browser.quit()

 

** explicit wait 할 때 try catch로 에러 났을 시, 브라우저가 꺼지게 하려고 했는데...

에러가 계속 나는데.. 무엇이 문제일까?.. 연결 거부?  

혹시 지나가다 바보 같은 짓을 지적해주시면 감사하겠습니다 흑흑 ㅠㅠ

try:
    wait = WebDriverWait(browser, 15)
    elements = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'sc-dIsUp')))
finally:
    browser.quit()
    
browser.find_elements(By.CLASS_NAME, 'sc-dIsUp')[23].click()
browser.find_elements(By.CLASS_NAME, 'sc-dIsUp')[26].click()

 

5. Headless : 크롬 브라우저를 띄우지 않고 크롤링할 수 있습니다.
주의 ) user agent 설정해주어야 한다. 

from selenium import webdriver

options = webdriver.ChromeOptions()
options.headless = True 
options.add_argument("user-agent= ~~~ ")

browser = webdriver.Chrome("./chromedriver", options=options)

 

어쩌다 보니, class name으로 element들을 가져오는 게 많았습니다. 핳ㅎ핳ㅎㅎ

Selenium은 확실히 숨겨진 화면이 있을 시, 드래그해서 찾을 수도 있고, 로그인 시도 등.. 여러 동작을 진행하고 나서 웹 크롤링을 할 수 있다는 장점이 있는 것 같습니다. 근데 뭔가 text 뽑고 표면적으로 나타난 필요한 정보들을 크롤링할 때는 BeautifulSoup가 더 쉽게 느껴졌습니다. 먼저 학습해서 그런가...? 크롤링... 은 예외나 웹이 바뀌게 되면 대응을 해줘야 하니까 그게 좀 걸리는 부분인 것 같습니다.