Python
crawling 1 - Selenium
retill28
2024. 7. 10. 20:20
1. 웹 크롤링 (Crawling)
크롤링(Crawling)이란 기어다니다라는 뜻이 있다.
그렇다면 웹 크롤링이란, 웹사이트를 돌아다니면서 정보를 탐색하고 수집하는 작업을 말한다.
즉, 웹을 기어다니며 데이터를 긁어 모은다고 생각하면 된다.
2. 사용한 툴
크롤링은 다루는 코드언어에 따라 다양한 방법으로 할 수 있다.
그 중에서도 파이썬, Selenium 라이브러리를 사용했다.
3. 시작 코드 - 기본 환경 설정
#설치
!pip install selenium
!pip install webdriver-manager
from webdriver_manager.chrome import ChromeDriverManager
from selenium import webdriver
browser = webdriver.Chrome() #크롬 웹드라이버 사용
browser.get('http://weather.naver.com') #브라우저 이동
4. 기본 코드
크롤링의 방법은 다음과 같다.
- 웹 HTML 문서에서 찾고자 하는 요소의 이름을 찾는다.
- 여기서 요소란 홈페이지에서 Ctrl+Shift+C를 사용하거나 마우스우클릭 후 검사를 통해 볼 수 있다.
- 아래의 사진에서 class부분, <strong class="current ">를 예로 들 수 있다.
- 셀레니움 함수를 사용해 찾은 요소를 가져오도록 한다.
- 아래의 browser.find_element(By.CLASS_NAME, 'current') 부분이 이에 해당한다.
이동한 현재 웹사이트의 HTML문서에서, class name이 current인 요소를 찾아서 그 값을 갖고오라는 뜻. -
from selenium.webdriver.common.by import By data = browser.find_element(By.CLASS_NAME, 'current').text data.split('\n')[1] # 22.2°
5. 사용 예시
- 네이버 부동산 실거래 데이터
#요소를 찾을 웹사이트로 이동 # browser = webdriver.Chrome() url = 'https://new.land.naver.com/complexes/111515?ms=37.497624,127.107268,17&a=APT:ABYG:JGC:PRE&e=RETAIL' browser.get(url) # 찾은 요소를 갖고 오게 한다. data = browser.find_element(By.CLASS_NAME, 'complex_price--trade').text data.split('\n')[1] #출력 결과 : '21억 8,000'
- 네이버 부동산 호가 데이터
browser.find_element(By.CLASS_NAME, 'item').text # 실행 결과 # '헬리오시티 516동\n월세7억 5,000/120\n아파트109E/84m², 22/29층, 남동향\n33 빠른입주가능,초역세권,거실넓은구조,파크밴드뷰\n부동산뱅크 제공\n엘리트(482-7117)공인중개사사무소\n확인24.07.05.'
- 하지만 item이라는 클래스는 아래와 같이 생겼는데, 그 아래 데이터 박스도, 그 아래도 전부 클래스 이름은 item이다.
- 그럼 class 이름이 'item'인 모든 요소를 가져오려면?
아래와 같이 find_elements()를 사용한다.
# class 이름이 item인 것을 전부다 가져오세요. datas = browser.find_elements(By.CLASS_NAME, 'item') len(datas) #260
- 위의 데이터는 긴 리스트로 반환이 되는데, find_element().text() 때처럼 바로 텍스트 전환이 불가능하다.
- 따라서 for 반복문을 사용한다.
# 데이터들을 담을 새로운 리스트 선언 data_list = [] # for문으로 datas를 받아 find_element로 각 항목을 받아오기 # 이때는 find_element이므로 .text() 사용 가능 for i in datas: 동정보 = i.find_element(By.CLASS_NAME, 'item_title').text 가격 = i.find_element(By.CLASS_NAME, 'price_line').text 매물정보 = i.find_element(By.CLASS_NAME, 'info_area').text 평형 = 매물정보.split('\n')[0] # 예외 처리 - 매물 정보가 없는 항목들에 대해서 예외처리 try: 소개글 = 매물정보.split('\n')[1] except: 소개글 = '없음.' # data_list에 각 항목들을 저장 - 딕셔너리형태 data_list.append({ '동정보' : 동정보, '가격' : 가격, '평형' : 평형, '소개글' : 소개글 })
- 하지만 item이라는 클래스는 아래와 같이 생겼는데, 그 아래 데이터 박스도, 그 아래도 전부 클래스 이름은 item이다.
- 구글 뉴스 수집
- 'DX도입'을 검색했을 때 뉴스란에 뜨는 헤드라인 데이터들을 수집
- 첫번째 헤드라인 데이터 수집하는 코드는 아래와 같다.
결과는 아래에.from selenium import webdriver from selenium.webdriver.common.by import By # 홈페이지 이동 browser = webdriver.Chrome() url = 'https://www.google.com/search?q=DX%EB%8F%84%EC%9E%85&newwindow=1&sca_esv=f339d8688030613e&tbm=nws&sxsrf=ADLYWIIE-oi9k3DZPSs-oud7R1slWqivLQ:1720152263345&tbas=0&source=lnt&sa=X&ved=2ahUKEwjf0_bEgo-HAxU7qlYBHV8rClIQpwV6BAgCEAY&biw=1146&bih=664&dpr=3' browser.get(url) # 요소 하나 가져오기 # 1. 첫 번째 뉴스의 (1)제목 (2)내용 (3)언론사 (4)작성일 (5)링크 title = browser.find_element(By.CLASS_NAME, 'n0jPhd').text content = browser.find_element(By.CLASS_NAME, 'GI74Re').text media = browser.find_element(By.CLASS_NAME, 'MgUUmf').text date = browser.find_element(By.CLASS_NAME, 'rbYSKb').text link = browser.find_element(By.CLASS_NAME, 'WlydOe').get_attribute('href')
- 다음으로, 위 코드를 응용해 요소 하나가 아니라 그 페이지의 모든 헤드라인 뉴스를 가져온다.
# 2. 1페이지 뉴스의 (1)제목 (2)내용 (3)언론사 (4)작성일 (5)링크 # browser.find_element(By.CLASS_NAME, 'SoaBEf').text datas = browser.find_elements(By.CLASS_NAME, 'SoaBEf') data_list = [] for i in datas: # i => container 1개를 의미 title = i.find_element(By.CLASS_NAME, 'n0jPhd').text content = i.find_element(By.CLASS_NAME, 'GI74Re').text media = i.find_element(By.CLASS_NAME, 'MgUUmf').text date = i.find_element(By.CLASS_NAME, 'rbYSKb').text link = i.find_element(By.CLASS_NAME, 'WlydOe').get_attribute('href') data_list.append({ '제목':title, '내용':content, '언론사':media, '작성일자':date, '링크':link })
- 이렇게 만든 data_list를 파일로 저장한다.
import pandas as pd df = pd.DataFrame(data_list) df.to_csv('google_news.csv', encoding='utf-8-sig')
- 1페이지만이 아니라 3페이지까지 데이터를 수집하려면 어떻게 해야할까.
여기서, 3페이지는 사용자에게 '몇 페이지까지 수집할것인지' 물어서 답변을 받게끔 한다.
# 3. N페이지까지의 전체 뉴스의 (1)제목 (2)내용 (3)언론사 (4)작성일 (5)링크 import time # 사용자에게 입력받기 page = int(input('몇 페이지까지 수집하시겠습니까? ')) data_list = [] num = 0 for i in range(0, page*10, 10): # 웹페이지 이동 url = f'https://www.google.com/search?q=DX%EB%8F%84%EC%9E%85&newwindow=1&sca_esv=f339d8688030613e&tbas=0&tbm=nws&sxsrf=ADLYWIJ_ZPLYmgAM1wihiA8rxSAvup_1RA:1720158160451&ei=0IeHZtyPG_am2roP7eShmAY&start={i}&sa=N&ved=2ahUKEwjct_HAmI-HAxV2k1YBHW1yCGM4ChDy0wN6BAgEEAQ&biw=798&bih=664&dpr=3' browser.get(url) time.sleep(1) # 2초 정도 쉬었다가 데이터 수집해줘 num += 1 # 요소 호출, 데이터 수집, 리스트에 저장 datas = browser.find_elements(By.CLASS_NAME, 'SoaBEf') for i in datas: # i => container 1개를 의미 title = i.find_element(By.CLASS_NAME, 'n0jPhd').text content = i.find_element(By.CLASS_NAME, 'GI74Re').text media = i.find_element(By.CLASS_NAME, 'MgUUmf').text date = i.find_element(By.CLASS_NAME, 'rbYSKb').text link = i.find_element(By.CLASS_NAME, 'WlydOe').get_attribute('href') data_list.append({ '제목':title, '내용':content, '언론사':media, '작성일자':date, '링크':link }) print(f'{num} 페이지 수집 완료되었습니다.')
- 여기서 첫번째 for문을 보면, 범위가 이렇다.
for i in range(0, page*10, 10):
범위를 이렇게 지정한 이유는 url과 관련이 있다.
이동하려는 페이지에 들어가 뉴스 1페이지, 2페이지, 3페이지의 url을 비교한다.
그럼 페이지에 따라 start=10 부분이 10의 배수로 변한다.
따라서, 5페이지는 start = 50이 되므로 위와 같은 반복문이 나온다.
https://www.google.com/search?q=DX%EB%8F%84%EC%9E%85&newwindow=1&sca_esv=f339d8688030613e&tbas=0&tbm=nws&sxsrf=ADLYWIJ_ZPLYmgAM1wihiA8rxSAvup_1RA:1720158160451&ei=0IeHZtyPG_am2roP7eShmAY&start=10&sa=N&ved=2ahUKEwjct_HAmI-HAxV2k1YBHW1yCGM4ChDy0wN6BAgEEAQ&biw=798&bih=664&dpr=3 - 위 데이터를 데이터프레임으로 만들어서 출력하면 아래와 같다.
- 'DX도입'을 검색했을 때 뉴스란에 뜨는 헤드라인 데이터들을 수집