셀레니움
Selenium은 웹 애플리케이션을 자동화하기 위한 오픈 소스 툴로, 브라우저를 프로그래밍적으로 제어하여 사람처럼 웹을 탐색하거나 상호작용할 수 있게 합니다. 주로 웹 테스트 자동화와 크롤링에 사용되며, 동적인 콘텐츠나 자바스크립트 렌더링이 필요한 웹 페이지에서도 효과적으로 동작합니다. Selenium WebDriver를 사용하면 Python, Java, C# 등 다양한 프로그래밍 언어로 브라우저를 제어할 수 있으며, Chrome, Firefox, Edge 등 여러 브라우저에서 작업이 가능합니다. 이를 통해 로그인, 폼 제출, 버튼 클릭, 데이터 스크랩과 같은 작업을 자동화할 수 있습니다.
라이브러리 설치
! pip install selenium
Selenium: 동적 웹 페이지 탐색과 상호작용을 위해 사용
pip install beautifulsoup4
BeautifulSoup (bs4): HTML 문서를 파싱하여 데이터 추출.
추가적으로 사용된 라이브러리
#조건이 충족될 떄 까지 대기
from selenium.webdriver.support.ui import WebDriverWait
#특정 조건을 기다릴 때 사용
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
#예외 처리 할것 import
from selenium.common.exceptions import NoSuchElementException, TimeoutException, ElementNotInteractableException
- time: 딜레이를 추가하여 안정적인 크롤링을 지원.
- WebDriverWait & expected_conditions: Selenium의 대기 기능으로, 특정 요소가 로드되거나 클릭 가능할 때까지 기다림.
- By: HTML 요소를 검색할 때 사용.
- 예외 처리: NoSuchElementException, TimeoutException, ElementNotInteractableException 등.
셀레니움을 이용한 크롤링 코드
1. 크롤링할 URL 설정
BASE_URL = 'https://www.yogiyo.co.kr/mobile/#/'
URL = [
'https://www.yogiyo.co.kr/mobile/#/546259/',
'https://www.yogiyo.co.kr/mobile/#/1289963/',
'https://www.yogiyo.co.kr/mobile/#/1211076/'
]
- BASE_URL: 요기요 메인 페이지 URL.
- URL: 크롤링할 가게의 상세 페이지 URL 리스트. 예를 들어, 각 URL은 특정 가게를 나타냄.
- 이 리스트에 원하는 가게 URL을 추가하여 크롤링할 대상을 확장할 수 있습니다.
2. 웹 드라이버 설정
chrome_options = webdriver.ChromeOptions()
prefs = {'profile.default_content_setting_values.geolocation': 2}
chrome_options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(options=chrome_options)
- webdriver.ChromeOptions: 크롬 드라이버의 설정을 정의합니다.
- prefs: 위치 권한을 비활성화(geolocation: 2)하여 위치 허용 팝업을 방지.
- webdriver.Chrome(options=chrome_options): 크롬 드라이버 객체 생성.
3. 지역 검색
driver.get(BASE_URL)
time.sleep(2)
search_box = WebDriverWait(driver, 5).until(
EC.visibility_of_element_located((By.XPATH, '//*[@id="search"]/div/form/input')))
search_box.send_keys('역삼동')
search_btn = WebDriverWait(driver, 5).until(
EC.visibility_of_element_located((By.XPATH, '//*[@id="button_search_address"]/button[2]')))
search_btn.click()
time.sleep(2)
first_address = WebDriverWait(driver, 5).until(
EC.visibility_of_element_located((By.XPATH, '//*[@id="search"]/div/form/ul/li[3]/a')))
first_address.click()
time.sleep(2)
- BASE_URL로 이동 후 역삼동 지역을 검색합니다.
- 검색 결과에서 첫 번째 주소를 선택하여 해당 지역의 요기요 데이터를 불러옵니다.
- WebDriverWait: 특정 요소가 나타날 때까지 대기합니다.
- time.sleep: 로딩 시간을 보장.
4. 가게 상세 페이지로 이동
driver.get(url)
time.sleep(2)
- 입력된 URL(url)로 이동하여 가게의 상세 페이지를 로드합니다.
5. 클린 리뷰 탭 클릭
clean_review_btn = driver.find_element(By.XPATH, '//*[@id="content"]/div[2]/div[1]/ul/li[2]/a')
clean_review_btn.click()
- 클린 리뷰 탭의 버튼을 클릭하여 클린 리뷰를 불러옵니다.
6. 모든 리뷰 로드
while True:
try:
more_btn = WebDriverWait(driver, 3).until(
EC.element_to_be_clickable((By.XPATH, '//*[@id="review"]/li/a')))
more_btn.click()
driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
time.sleep(1)
except (NoSuchElementException, TimeoutException, ElementNotInteractableException):
break
- "더보기" 버튼이 존재할 때까지 클릭하여 모든 리뷰를 불러옵니다.
- driver.execute_script: 화면을 아래로 스크롤.
- 더 이상 버튼이 없으면 반복문을 종료합니다.
7. HTML 파싱 및 데이터 추출
soup = BeautifulSoup(driver.page_source, 'html.parser')
restaurant_name = soup.select_one(
'#content > div.restaurant-detail.row.ng-scope > div.col-sm-8 > div.restaurant-info > div.restaurant-title > span'
).get_text(strip=True)
reviews = soup.select('#review > li')
review_texts = [review.get_text(strip=True) for review in reviews][1:]
menus = soup.select('#review > li > div.order-items.default.ng-binding')
all_menu = [menu.get_text(strip=True) for menu in menus]
- soup.select_one: 가게 이름을 추출.
- soup.select: 리뷰(#review > li)와 메뉴 정보를 추출.
- get_text(strip=True): 텍스트만 추출하며, 양 끝 공백 제거.
8. 데이터 구조화
document = {
"restaurant": restaurant_name,
"url": url,
"reviews": []
}
for menu, text in zip(all_menu, review_texts):
document['reviews'].append({
"menus": menu,
"review_text": text
})
- restaurant_name, url, reviews 데이터를 구조화하여 저장.
- 메뉴와 리뷰를 한 쌍으로 묶어 document['reviews']에 저장.
9. 출력 예시
{'restaurant': '삼첩분식-논현점', 'url': 'https://www.yogiyo.co.kr/mobile/#/1357527/',
'reviews':
[{'menus': '[삼첩] 떡볶이/1(사이즈 선택(1~2인),
맵기 선택(쓰읍 (1단계)),떡 선택(떡/어묵 반반),감자 선택((시그니처) 감자폭탄 X)),
누드순대/1,어묵탕/1,순대튀김 6개/1,김말이튀김 1개/1',
'review_text':
'pr**님2일 전신고★★★★★맛★5양★5배달★0[삼첩] 떡볶이/1(사이즈 선택(1~2인),
맵기 선택(쓰읍 (1단계)),떡 선택(떡/어묵 반반),감자 선택((시그니처) 감자폭탄 X)),
누드순대/1,어묵탕/1,순대튀김 6개/1,김말이튀김 1개/1맛있어요!\n감사합니다사장님15시간 전신고pr**님,
감사합니다! 주문해 주셔서 감사드려요. 맛있게 드실 수 있어서 감사합니다.
다양한 메뉴를 시킴으로써 다양한 맛을 즐기셨군요. 저희 매장의 대표 메뉴를 주문해주셔서 감사합니다.
항상 더 나은 맛과 서비스로 보답하겠습니다. 앞으로도 많은 이용 부탁 드려요! 🌟🍲🍢'},
{'menus': '일첩 세트/1(떡볶이 선택(삼첩 떡볶이),맵기 선택(바질크림은 적용 불가합니다)
(쓰으읍 (2단계)),떡 선택 (마라로제, 바질은 적용 불가합니다)(떡/어묵 반반),
기본 구성(튀김어묵 4 + 당면만두 4),사이드 선택([꼬마] 새우마요김밥 2줄),
더하다 추가선택(닭껍질튀김))',
'review_text': 'wj**님2024년 11월 17일신고★★★★★맛★5양★5배달★0일첩 세트/1(떡볶이 선택(삼첩 떡볶이),
맵기 선택(바질크림은 적용 불가합니다)(쓰으읍 (2단계)),
떡 선택 (마라로제, 바질은 적용 불가합니다)(떡/어묵 반반),
기본 구성(튀김어묵 4 + 당면만두 4),사이드 선택([꼬마] 새우마요김밥 2줄),
더하다 추가선택(닭껍질튀김)).사장님2024년 11월 19일신고wj**님, 이용해주셔서 감사합니다.
세트 메뉴를 주문해주셔서 감사드리며,
즐거운 식사시간이었길 바랍니다. 맛있는 음식과 함께 즐거운 서비스를 제공할 수 있어 감사합니다.
리뷰를 남겨주셔서 진심으로 감사드리며,
다음에도 맛있는 음식으로 모시기를 기대하겠습니다. 🌟🙏🍜🍤'}
'인공지능 > LLM 서비스' 카테고리의 다른 글
Gradio (0) | 2025.01.12 |
---|---|
프롬프트 엔지니어링 (0) | 2025.01.12 |
생성형 AI에 대해서 - GPT API (0) | 2025.01.12 |
예스 24, 교보문고 크롤링(mongoDB,Excel 저장) (0) | 2025.01.12 |
크롤링 (0) | 2025.01.12 |