select 태그 선택 테스트
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from bs4 import BeautifulSoup
from selenium.webdriver.support.ui import Select # select 태그 제어 클래스
SCROLL_PAUSE_TIME =1
url ='https://www.selenium.dev/selenium/web/formPage.html'
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options = webdriver.ChromeOptions())
driver.get(url)
select = Select(driver.find_element(By.NAME,'selectomatic'))
# 1. 인덱스 기준으로 선택하기
# select.select_by_index(1)
# 2. 보여지는 선택값 텍스트로 선택하기
# select.select_by_visible_text('Still learning how to count, apparently')
# 보여지는 텍스트는 앞글자가 대문자 'still learning how to count, apparently'
# 3. 옵션 요소의 값으로 선택하기
# select.select_by_value('four')
# select 태그에 onchange(화면변화 목적) 옵션이 있어서 Select 클래스를 사용할 수 없는 경우 -> click() 함수를 사용해야함
driver.find_element(By.CSS_SELECTOR,'option[value = "four"]').click()
select 태그는 동적인 페이지에서 사용된다. onchange 란 input이나 select 등의 데이터가 변경될 때 호출되는 이벤트를 가리킨다.

Select 태그를 설명한 이유: yes24의 홈페이지는 onchange를 사용하는 동적 홈페이지 이기 때문이다.
[실습] yes24에서 파이썬 도서 검색하기
yes24 사이트에서 파이썬 도서 검색 후 평점 9.6 이상인 도서 제목과 가격, 평점 가져오기
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from bs4 import BeautifulSoup
from selenium.webdriver.support.ui import Select # select 태그 제어 클래스
import requests
SCROLL_PAUSE_TIME =1
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options = webdriver.ChromeOptions())
# 파이썬 검색
driver.get('https://www.yes24.com/main/default.aspx')
ele = driver.find_element( By.NAME,'query')
ele.send_keys('파이썬')
ele.send_keys(Keys.ENTER)
# 20개 -> 120개씩 보기 변경
select = Select(driver.find_element(By.ID,'stat_gb'))
driver.find_element(By.CSS_SELECTOR, 'option[value = "120"]').click()
time.sleep(SCROLL_PAUSE_TIME)
# 가동성을 위해 Selenium 과 Beautifulsoup의 셀을 구분해서 만들었다.
from bs4 import BeautifulSoup
soup = BeautifulSoup(driver.page_source, 'lxml')
book_list = soup.find('ul',attrs={'id':'yesSchList'})
books = book_list.find_all('li')
# print(len(books))
# for i in range(2,11): # or while # 페이지 넘기기
for book in books:
title = book.find('a', attrs = {'class':'gd_name'})
price = book.find('strong',attrs = {'class':'txt_num'})
rating = book.find('span',attrs = {'class':'rating_grade'})
# <em class="yes_b"> 태그가 도서가격 등 다른 곳에서도 사용됨
# -> 상위에 있는 태그를 가져와 다시 범위를 좁혀 사용
# <em class="yes_b">19,800</em>
# <em class="yes_b">9.9</em>
if not rating: continue # 평점 없는 도서는 pass
cnt+=1
rating = rating.find('em', attrs = {'class':'yes_b'}).text
# 다시 범위를 좁혀 실제 평점 가져옴
if float(rating) < 9.6: continue
print(f'> {title.text} | {price.text} | {rating}')
price 와 rating의 사용하는 클래스 이름이 같다. 때문에 그들의 상위 태그를 먼저 가져온 후 다시 세분화를 진행한다.
평점이 없는 책이 존재하기에 try~except 구문을 사용하여 예외 처리 한다.
rating 문자열이니 9.6보다 크다는 조건문을 구하기 위해 float처리 후 구분한다.
[실습] 다음 영화 사이트에서 박스 오피스 1위 영화의 감상평 및 평점 수집
- 감상평을 수집하여 텍스트 파일로 저장하기
- 평점을 수집하여 csv 파일로 저장하기
import csv
with open('rating.csv','w) as f:
writer = csv.writer(f)
writer.writerow(ratings) # ratings: 평점을 모아놓은 리스트 객체
* 스크래핑 순서
selenium: 다음 영화 사이트에 접속(movie.daum.net) -> "랭킹" 클릭 -> "박스오피스 클릭" -> 1위 영화 클릭 -> "평점" 클릭 -> 마지막 평점까지 스크롤
BeautifulSoup : 사용자별 감상평 및 평점 수집 -> 리스트 저장 -> 파일 저장
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from bs4 import BeautifulSoup
from selenium.webdriver.support.ui import Select # select 태그 제어 클래스
PAUSE_TIME =1
url = 'https://movie.daum.net'
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options = webdriver.ChromeOptions())
driver.get(url)
elem = driver.find_element(By.LINK_TEXT,'랭킹')
elem.click()
elem = driver.find_element(By.LINK_TEXT,'박스오피스')
elem.click()
# 박스오피스 1위 영화 클릭
rank_1 = driver.find_element(By.CSS_SELECTOR,'#mainContent > div > div.box_boxoffice > ol > li:nth-child(1) > div > div.thumb_cont > strong > a')
rank_1.click()
# 평점탭 클릭
time.sleep(PAUSE_TIME)
driver.find_element(By.XPATH,'//*[@id="mainContent"]/div/div[2]/div[1]/ul/li[4]/a').click()
# 스크롤 횟수
scroll_cnt =1
while True:
# 윈도우 창의 스크롤 바를 0 ~ 가장 밑 (전체 길이 값 = scrollHEight)까지 이동
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') # 스크롤 시작
time.sleep(SCROLL_PAUSE_TIME)
new_height = driver.execute_script('return document.body.scrollHeight') # 변화된 스크롤 다시 기록
print(f'last height:{last_height}, new_height: {new_height}')
if last_height != new_height : # 계속해서 new_height값이 변경된다면
last_height = new_height
else: # 더이상 new_height 값에 변동이 없다면
try:
ele = driver.find_element(By.CSS_SELECTOR, '#alex-area > div > div > div > div.cmt_box > div.alex_more > button')
ele.click()
print('평점더보기 클릭')
except:
break
까먹고 있던 ' driver.find_element(By.LINK_TEXT,'랭킹')' 구문. 텍스트에 연결해 놓은 링크로 넘어간다.
박스오피스는 CSS_SELECTOR 로 빠르게 접근하고, 평점 탭은 CSS_SELECTOR 가 갑자기 안되서 XPATH로 대신했다.
스크롤 문은 구글 실습과 유사하며, 하나 다른 것이 있다면 try문이 반복문에서 조건식 안에 포함되는 것이다.
이 코드에서 가장 애 먹었던 것은 처음에 버벅거리는 click() 함수와 아직 익숙하지 못한 마우스 조작법이다.
soup = BeautifulSoup(driver.page_source, 'lxml')
ratings= []
comments = []
# 가장 큰 영역
ele = soup.find('ul',attrs={'class': 'list_comment'})
ele = ele.find_all('li') # 이미 범위 안이기 때문에, 태그만 검색해도 된다
for e in ele:
rating = e.select_one('div>div').text
ratings.append(int(rating))
# 감상평이 이모티콘으로 되어있는 (텍스트가 없는) 경우 예외 발생
try:
comment = e.select_one('div>p').text
except: continue
comment= comment.replace('\n',' ')
comments.append(comment)
# 수집 정확도 체크
print(f'네티즌 평점: {sum(ratings)/len(ratings):.1f}점')
import csv
import os
with open('rating.csv','w') as f:
writer = csv.writer(f)
writer.writerow(ratings) # ratings: 평점을 모아놓은 리스트 객체
print('평점 저장 완료')
with open('comments.txt','a',encoding='utf-8') as f:
for comment in comments:
f.write(comment+'\n')
print('감상평 저장 완료')
가장 큰 영역인 class = 'list_comment' 안에는 평점, 감상평, 작성자 등의 요소들이 존재한다.
거기서 범위를 좁히는 것이 가장 효율적인 방법이다. (처음 'list_comment' 를 조금더 크게 생각하면 어땠을까 라는 아쉬움이 든다.)
평점은 class의 이름이 'ratings rating_평점점수로' 비슷하다. 나는 이를 활용해 돌렸지만 교수님은 그것의 위치를 파악하여 추출하셨다.
감상평은 한글이므로 감상평 저장에 encodoing = 'utf-8' 사용
이 코드에서 애먹은 점은 처음엔 감상평과 별점이 함께 반복문을 돌아 나와야 한다고 생각되어 계속 같이 나오는 태그를 찾으려고 한 것이다.
교수님의 설명과 함께 for문을 따로 돌려야 한다고 설명을 해주셨고 for문 2 개를 사용하여 값을 추출하는데에는 성공했다.
하지만, text를 사용하여 태그를 벗기고 추출하여 append 하는 것이 안되었고, 교수님의 코드를 보며 좀 더 쉬운 방법이 존재했다는 걸 깨달았다.
iframe을 이용한 웹 페이지 스크랩 하기
iframe 독립된 html을 따로 만들어 필요한 페이지에 삽입시키는 것( 예: 네이버 지도 )
selenium을 이용해서도 동적인 페이지를 읽지 못한 상황
해결 : 프레임 초점을 이동시켜 외부 -> 내부 -> 외부 로 바꿔야함.
- iframe 태그의 id값을 찾는다.
frame = driver.find_element(By.ID, 'entryIFrame')
- 해당 iframe 으로 switch
driver.switch_to.frame(frame)
- 이후 iframe 내의 element를 검색하여 데이터를 스크래핑한다.
iframe내의 스크래핑 작업이 끝난후 기본 프레임의 내용을 스크래핑하기 위해 기본프레임으로 전환한다.
driver.switch_to.default_content()
'풀스택 개발 학습 과정 > 데이터' 카테고리의 다른 글
[데이터 시각화] matplotlib - 1 (0) | 2023.11.04 |
---|---|
[데이터 수집] Auto Crawler (0) | 2023.11.04 |
[데이터 수집] 셀레니움 - 2 (구글 이미지 실습) (0) | 2023.11.02 |
[데이터 수집] 셀레니움 -1 (0) | 2023.11.01 |