[데이터분석] 데이터 크롤링 실습(1)

2024. 8. 14. 00:16데이터 사이언스

파이참에 환경 세팅

  • selenium 다운로드
pip install selenium
pip install --upgrade pip

  • homebrew 로 Mac에 chromedriver 설치
brew install chromedriber


BeautifulSoup

1. 라이브러리 가져오기

# beautifulSoup 라이브러리 가져오기
import requests
from bs4 import BeautifulSoup

 

2. robots.txt 읽어보기

  • robots.txt : 법적 효력이 없기 때문에, 수정사항이 있어도 반영되지 않을 수 있음
  • 모든 User-agent 에 대해 /user_report/, /elec/Management 에 대해 허용 안 함
  • HMSE_Robot 은 아무것도 허용하지 않고, bingbot은 크롤링 딜레이를 발생시킴
  • 아래의 유저들에 대해서 크롤링 딜레이를 1씩 발생시킴
User-agent: Mediapartners-Google
User-agent: Googlebot
User-agent: Googlebot-image
User-agent: NaverBot
User-agent: Yeti
User-agent: Daumoa
User-agent: Twitterbot

 

3. 태그의 종류를 확인하는 방법

  • chrome - 개발자 도구 - Elements → 아이콘 클릭 후, 원하는 태그에 마우스를 올리기


1. Header를 입력하지 않은 경우

# header를 입력하지 않은 경우
# requests 라이브러리를 통해서 가져오기
res = requests.get('<https://danawa.com/>')

# BeatufiulSoup으로 파싱
soup = BeautifulSoup(res.content, 'html.parser')
print(soup)
  • requests.get('...') : requests 라이브러리를 통해서 가져오기
  • soup = BeautifulSoup(res.content, 'html.parser')
    • requests 라이브러리 통해서 가져온 변수이름.content
    • 무엇으로 파싱하는지 넣어줘야함 -> 일반적으로 html을 파싱하고 지금 우리는 html을 파싱하니 html.parser를 넣어줌
  • print(soup) 결과 → Error 발생 → 다나와 사이트가 막아둔 것
    • beautifulSoup이 Selenium보다 너무 로봇같이 보여서 → 유저와 구분이 쉽기 때문에 막아둔 곳이 많음

 # p 태그를 가진 원소 모두 추출
 soup.select("p")
 
 # span 태그를 가진 title이 class인 원소 모두 추출 "." 입력
soup.select("span.title")

# select_one은 최초 한개만 추출
# get_text()를 통해 text만 가져올 수 있음
soup.select_one("span.title").get_text()

# a 태그를 가진 class명 text-elps2인 원소 모두 추출 "." 입력
soup.select("a.text-elps2")
  • select : 추출 → 추출한 내용이 list 형태
    • 따라서 list와 같은 방식으로 행을 선택하여 추출 가능
    • (ex) soup_select(”span.title”)[-1] : 마지막 행 추출
  • select_one : 최초 한 개만 추출
  • get_text() : text만 추출

2. Header를 입력한 경우

  • 봇이 아닌 사람 처럼 Header를 주는 경우, Header를 주지 않은 경우 보다 추출이 되는 경우가 더 있을 수 있지만, 이 역시 beautifulSoup은 탐지가 쉽기 때문에 Header를 입력해도 추출이 안 되는 경우가 많음
# beautifulSoup 라이브러리 가져오기
import requests
from bs4 import BeautifulSoup

#header 입력
headers = {
	"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
}

#requests 라이브러리를 통해서 가져오기 (header 사용)
res = requests.get('<https://prod.danawa.com/list/?cate=112758&15main_11_02=>', headers = headers)

#BeatufiulSoup으로 파싱
soup = BeautifulSoup(res.content, 'html.parser')
  • headers = { "User-Agent":"..."}
    • header 입력 → 사람같은 정보를 주는 것 (ex) “apple 사용하고 있고, chrome 유저야”
#a 태그 가진 prod_name을 클래스명으로 하는 원소 모두 추출
soup.select("a.prod_name")


Selenium

  • [파이참] ChromeDriver 기본 설정 - selenium driver 로드
import selenium
print(selenium.__version__)

from selenium import webdriver
from selenium.webdriver.common.by import By

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')  # ensure GUI is off
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')  # set path to chromedriver as per your configuration
chrome_options.add_argument('lang=ko_KR')  # 한국어
chrome_options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
# selenium driver 로드
driver = webdriver.Chrome(options=chrome_options)

# 링크 전달
driver.get("<https://prod.danawa.com/list/?cate=112758&15main_11_02=>")

# CSS_SELECTOR를 활용해서 원소들 갖고오기 (find_element 하면 한개만 가져옴)
elements = driver.find_elements(By.CSS_SELECTOR, "a.prod_name")

# elements의 모든 원소에 대해서
for elem in elements:
    # elem의 text만 뽑아서 print
    print(elem.text)

# driver 종료
driver.quit()
  • driver.get("https://...") : driver 라이브러리를 통해서 가져오기
  • elements = driver.find_elements(By.CSS_SELECTOR, "a.prod_name")
    • CSS_SELECTOR를 활용해서 원소들 갖고오기
    • find_elements 여러개 가져오기
    • find_element 하면 한개만 가져옴
    • [방법2] 우클릭 - Copy - Copt selector : CSS_SELECTOR 구문에 맞게 태그를 가져와줌
elements = driver.find_elements(By.CSS_SELECTOR, "#mainAdReader > ul > li:nth-child(1) > div > div.prod_info > p.prod_name > a")

  • .text : text만 뽑아서 print
#By.NAME을 활용해서 원소들 갖고오기 (find_element 하면 한개만 가져옴)
elements = driver.find_elements(By.NAME, "productName")
  • By.NAME : By. NAME을 활용하여 원소들 갖고 오기
#CSS_SELECTOR를 활용해서 p 태그를 갖는 모든 원소들 갖고오기 (find_element 하면 한개만 가져옴)
elements = driver.find_elements(By.CSS_SELECTOR, "p")
#CSS_SELECTOR를 활용해서 원소들 갖고오기 (find_element 하면 한개만 가져옴)
elements = driver.find_elements(By.CSS_SELECTOR, "a.text-elps2")

Selenium - BeautifulSoup과 연계

  • 많은 데이터를 가져오는 경우 : BeautifulSoup이 더 빠르기 때문에, 가져오는 것은 Selenium으로 가져오고 파싱을 BeautifulSoup으로 하면 속도가 좀 더 빨라질 수 있음
from selenium import webdriver
from bs4 import BeautifulSoup

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')  # ensure GUI is off
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')  # set path to chromedriver as per your configuration
chrome_options.add_argument('lang=ko_KR')  # 한국어
chrome_options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
driver = webdriver.Chrome(options=chrome_options)

driver.get("<https://prod.danawa.com/list/?cate=112758&15main_11_02=>")

# 페이지 소스 가져오기
html_source = driver.page_source

# BeautifulSoup으로 파싱
soup = BeautifulSoup(html_source, 'html.parser')

# 원하는 요소 찾기
items = soup.select('a[name="productName"]')

for item in items:
  print(item.text)

driver.quit()