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({
              '동정보' : 동정보,
              '가격' : 가격,
              '평형' : 평형,
              '소개글' : 소개글
          })

 

 

  • 구글 뉴스 수집 
    • '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   

    • 위 데이터를 데이터프레임으로 만들어서 출력하면 아래와 같다.