동적 웹 페이지와의 만남
정적 웹사이트와 동적 웹사이트
- 웹 페이지는 어떻게 생성되느냐에 따라 크게 2가지로 구분
- HTML 내용이 고정된 정적(static) 웹 사이트
- 정적 웹사이트는 HTML 문서가 완전하게 응답된다.
- HTML 내용이 변하는 동적(dynamic) 웹 사이트
- 동적 웹 사이트는 응답 후 HTML이 렌더링 될 때까지의 지연시간이 존재
- HTML 내용이 고정된 정적(static) 웹 사이트
동적 웹사이트의 동장 방식
- 웹 브라우저에선 JavaScript라는 프로그래밍 언어가 동작한다.
- 비동기 처리를 통해서 필요한 데이터를 채운다,
- 동기처리: 요청에 따른 응답을 기다린다.
- 비동기처리: 요청에 따른 응답을 기다리지 않는다.
- 동기 처리된 경우, HTML 로딩에 문제가 없다.
- 비동기 처리된 경우, 상황에 따라서 데이터가 원전하지 않은 경우가 발생한다.
지금까지 스크래퍼의 문제점
- 위와 같이 녹색선 상에서 요청을 보내게 되면 불완전한 응답을 받게된다.
- 임의로 시간을 지연한 후, 데이터 처리가 끝난 후 정보를 가져오면 된다.
- 키보드 입력, 마우스 클릭 등을 requests로는 진행하기 어렵다.
- => Selenium을 통해 이를 실현시킬수 있음.
- UI와의 상호작용이 가능하다.
- 💥 동적 웹사이트는 응답 후 바로 정보를 추출하기 어렵다.
- 또한, 다양한 키보드 입력과 마우스 클릭 등의 상호작용이 존재한다.
- 이런 상황을 해결하기 위해, 웹 브라우저를 파이썬으로 조작하는 전략을 취하자
브라우저 자동화하기, Selenium
Selenium 설치 & 사용하기
- 나는 코랩환경에서 진행함.
!pip install selenium
- web driver 설치 - 웹 브라우저와의 연동을 위해서 필요하다고 함
!pip install webdriver-manager
- 컴퓨터에 크롬 브라우저가 깔려있어야 한다. 크롬 깔려있었는지 꼭 확인!
- Selenium 시작하기
# selenium으로부터 webdriver 모듈을 불러온다
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
- 음 코랩상에서 하니 문제가 발생. 그리고 다시 생각해보니 구글 서버를 거쳐 다시한번 셀레니움을 실행시키면 속도가 많이 느릴것이다 따라서 그냥 로컬상에서 실행시키기로 결정 환경 구현을 다시 해보도록 하겠다.
- 아나콘다 상를 로컬에 설치
- 가상환경 새로 구성
- 필요한 모듈 설치
- vscode 사용
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
- 이렇게 새 창이 뜨게 된다.
- 브라우저에 요청 보내보기
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://www.naver.com')
- 페이지 소스 코드 확인하기
# page_source
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://www.naver.com')
print(driver.page_source)
- with-as 구문을 이용해 페이지에서 필요한 작업을 하고 닫을 수 있다.
# with-as 구문을 이용해 페이지에서 필요한 내용 받고 닫기
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get('https://www.naver.com')
result = driver.page_source
- driver에서 특정 요소 추출하기
- 요소 하나 찾기
- .find_element(by, target)
- by: 대상을 찾는 기준:id, tag_name, class_name ...
- target: 대상의 속성
- 요소 여러개 찾기
- .find_elements(by, target)
- by: 대상을 찾는 기준:id, tag_name, class_name ...
- target: 대상의 속성
- by 호출
- 요소 하나 찾기
from selenium.webdriver.common.by import By
Wait and Call
- 인디스트릿 - 행사 리스트 가져오기(https://indistreet.com/live?sortOption=startDate%3AASC)
- Implicit/Explicit Wait
- Selenium은 동적 웹사이트에 대한 지원을 위해 명시적 기다림(Explicit wati)과 암묵적 기다림(Implicit wait)을 지원한다.
- Implicit Wati: 다 로딩이 될때까지 지정한 시간 동안 기다림
- Explicit Wait: 특정 요소에 대한 제약을 통한 기다림(ex. 태그 가져올수 있을떄까지 기다려)
Xpath?
- 요새 사이트는 class 이름을 랜덤하게 생성시켜 무분별한 스크래핑을 방지한다.
- 위치를 활용한 방법인 xpath를 활용할 수 있다.
- Xpath는 XML, HTML 문서 등의 요소의 위치를 경로로 표현하는 것을 의미한다.
- 예시 사이트에 요청을 보내고 예시 사이트의 첫 번째 이벤트의 제목을 가져와보자
- Implicit wait 적용
- from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.ui import WebDriverWait
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get('https://indistreet.com/live?sortOption=startDate%3AASC') # 로딩이 다 될때까지 기다려주기 위해 비동기 처리를 해줘야한다.
driver.implicitly_wait(5) # Implicit wait
result = driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')
print(result.text)
- Explicit wait
- until(): 인자의 조건이 만족될 때까지
- until_not(): 인자의 조건이 만족되지 않을 때까지
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support import expected_conditions as EC
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get('https://indistreet.com/live?sortOption=startDate%3AASC') # 로딩이 다 될때까지 기다려주기 위해 비동기 처리를 해줘야한다.
result = WebDriverWait(driver,10).until(EC.presence_of_element_located(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')) # Explicit wait
print(result.text)
- 여러개 공연목록 받아와보기
with webdriver.Chrome(service=Service(ChromeDriverManager().install())) as driver:
driver.get('https://indistreet.com/live?sortOption=startDate%3AASC')
driver.implicitly_wait(5) # Implicit wait
for i in range(1, 10):
result = driver.find_element(By.XPATH, f'//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[{i}]/div/a/div[2]/p[1]')
print(result.text)
마우스 이벤트 처리하기
- https://hashcode.co.kr/ 에서 실습 진행
- 목표: 로그인 창 접속하기
- 웹 페이지에서 일어나는 일들을 Event라고 한다.
- 마우스로 일어날 수 있는 대표적인 이벤트 예시
- 마우스 움직이기(move)
- 마우스 누르기(press down)
- 마우스 떼기(press up)
- 크게 세가지 단계로 요약될 수 있다.(예시)
- 입력하고자 하는 대상 요소를 찾는다.
- 입력하고자 하는 내용을 click을 통해 전달한다.
- .perform() 을 통해 전달한다.
- 필요 모듈 임포트
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get("https://hashcode.co.kr/")
driver.implicitly_wait(1)
button = driver.find_element(By.XPATH, '//*[@id="main-app-gnb-header"]/div/div/div[1]/div/div[1]/a')
ActionChains(driver).click(button).perform()
키보드 이벤트 처리하기
- 해쉬코드 로그인 진행하기
- 해쉬코드 로그인을 진행하게 되면 세션이 풀려서 다른 사이트 이용해봄
- 무신사 로그인을 진행해보자 - https://www.musinsa.com/app/contents/coupon_online?sort=coupon_rate&utm_source=google_keyword&utm_medium=sa&utm_campaign=SA_perf_main_CPC_musinsa_GOKEBRP905&utm_term=musinsa&source=GOKEBRP905&gclid=CjwKCAjwq-WgBhBMEiwAzKSH6Nf4C-9_GnE9lXSrpFzfULrWkayuI4PMb2Ib13AH00bxq1iyOXaOVxoCTRAQAvD_BwE
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get("https://www.musinsa.com/app/contents/coupon_online?sort=coupon_rate&utm_source=google_keyword&utm_medium=sa&utm_campaign=SA_perf_main_CPC_musinsa_GOKEBRP905&utm_term=musinsa&source=GOKEBRP905&gclid=CjwKCAjwq-WgBhBMEiwAzKSH6Nf4C-9_GnE9lXSrpFzfULrWkayuI4PMb2Ib13AH00bxq1iyOXaOVxoCTRAQAvD_BwE")
driver.implicitly_wait(1)
# 로그인 창 진입
button = driver.find_element(By.XPATH, '//*[@id="default_top"]/div[3]/button')
ActionChains(driver).click(button).perform()
# id 입력
input_id = driver.find_element(By.XPATH, '/html/body/div[1]/section/div[1]/form/div[1]/div[1]/div/input')
ActionChains(driver).send_keys_to_element(input_id, "본인 id").perform()
# pw 입력
pw = driver.find_element(By.XPATH, '/html/body/div[1]/section/div[1]/form/div[1]/div[2]/div/input')
ActionChains(driver).send_keys_to_element(pw, "본인 비밀번호#").perform()
# 로그인 버튼 클릭
login_button = driver.find_element(By.XPATH, '/html/body/div[1]/section/div[1]/form/div[2]/button')
ActionChains(driver).click(login_button).perform()
성공!
'프로그래머스 AI 데브코스 5기 > CS' 카테고리의 다른 글
Git & Github (0) | 2023.03.27 |
---|---|
Web Scraping 기초 - 3 (0) | 2023.03.23 |
Web Scraping 기초 (0) | 2023.03.21 |
양방향 연결 리스트(Doubly Linked List) (0) | 2023.03.20 |
연결 리스트(Linked Lists) (0) | 2023.03.20 |