본문 바로가기
Experience/- KT AIVLE School

KT AIVLE School 3주차 정리 - 크롤링

by Yoojacha 2023. 2. 16.

중국 정원사진 모음 사이트와 인스타그램 크롤링 경험으로 사실 크롤링을 배울 땐 다른 학습을 하려고 했었습니다! 하지만 강사님께서 정말 고수의 향기가 느껴지시고, 설명을 잘해주셔서 강의에 집중을 할 때 도 있었습니다!

크롤링을 했던 적이 1년이 넘어가다보니, 1년사이에 웹개발을 해보면서 저의 식견이 넓어진 것이 느껴졌습니다. 분명 강사님께서는 아주 간략하게 설명을 해주시고 빠르게 진도를 나가시지만 저는 그 외의 지식도 점점 더 생기니 풍부하게 이해를 해서 좋은 것 같아요. 역시 공부는 꾸준히 해야하나 봅니다!


프로토콜 : 통신 규약, 약속 ex) udp, http, https
포트번호 : 하나의 서버 안에 데이터가 들어오고 나가는 통로 주소
dns 서버: 아이피 주소 대신으로 나타내주는 것
referer : 해당 url로 오기전의 url이 적혀있음. -> 어느 웹페이지에서 해당 웹페이지로 넘어왔는지 알 수 있다.
user-agent : WAS가 cilent의 요청이 어떤방식으로 하는지 파악할 때 확인
robot.txt : 해당 웹사이트의 크롤링 정책
쿠키, 세션, 캐시
상태코드: 200, 300, 400, 500 번대 구분


  • 정적 웹페이지와 동적 웹페이지에 따라 크롤링 방법이 다르다.
  • 개발자모드(f12)로 모바일 버전 웹을 크롤링 하는 것이 비교적 쉽다.
  • 아래는 GET 요청 후 응답 받고, str -> json -> dataframe으로 자료구조를 변경하는 것은 함수로 묶은 것이다.
# url get response > str > json > DataFrame
def req_df(url):
    """This function is making dataframe from url

    Args:
        url (string)
    return:
        type (DateFrame)
    """

    # 1. get response > str data > json
    response = requests.get(url).json()

    # 2. json(str) > list, dict > Dataframe
    data = response.json()
    df = pd.DataFrame(data)
    display(df)
    return df

Requests

GET 요청

# 요청을 보낼 url
url = 'https://domain.com/document'
# 헤더에 브라우저 정보와 이전 페이지의 정보를 담아서 요청을 보낸다.
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
    'referer': 'https://domain.com',
}

response = requests.get(url, headers=headers)

POST 요청

data = '서버에 보내고 싶은 내용을 여기다 적는다.'
url = 'https://domain.com/search'
headers = {
    'Content-Type': 'application/json', # POST 요청은 json 형식으로 보통 많이 쓴다.
    '~~~ -ID': CLIENT_ID, # 특정 API를 많이 활용하면 API의 정책에 따라 비밀키와 아이디를 헤더에 넣는 경우가 있다.
    '~~~~ -Secret': CLIENT_SECRET,
    'domain': 'domain',  # 서버에 따라 도메인을 요구하기도 한다.
    'withCoalition': 'true', # 서버에 따라서 특정키의 설정을 요구하기도 한다.
    'item_ids': ids[:900], # 서버에서 1 번 요청 당 999개의 데이터만 보여주도록 limit 이 있는 경우도 있다.
}
params = {'pageNo': 2, 'items': 10, 'language': '한글'} # 쿼리 스트링 설정용

# params 에 한글이 있다면 json.dumps()를 사용하여 영어로 변환해주어야 한다.
response = requests.post(url, json.dumps(params), headers=headers)

geohash

import geohash2

# precision : 클수록 영역이 작아짐 
geohash = geohash2.encode(lat, lng, precision=2)

BeautifulSoup4

from bs4 import BeautifulSoup
import pandas as pd 
import requests 

# 1. html 받아오기
dom = BeautifulSoup(response.text, 'html.parser') # type은 bs object 

# 2. css selector 방식으로 element들 받아오기
elements = dom.select('div > div.related_srch > ul#card > li') 

# 3-1. 반복문으로 css selector 방식으로 element 하나씩 받아오기 + 리스트 컴프리헨션
authors = [element.select_one('span.author').text for element in elements]

# 3-2. 반복문을 통해 json 형태로 element를 하나씩 받아오기
data = []
for element in elements:
	data.append({
                'title': element.select_one('.itemname').text,
                'link': element.select_one('a').get('href'), 
                'img': 'http:' + element.select_one('img').get('data-original'),
                'description': element.select_one('.description').text, 
    			})

# 4. 받아온 데이터를 DataFrame으로 변환
df = pd.DataFrame(data, columns=authors)

이미지 크롤링 + Pillow

from PIL import Image as pil

filename = 'data/test.png'
pil.open(filename) # 콘솔에 이미지 출력
foldername = 'images'

for indx, data in df[:5].iterrows(): # enumerate()와 같은 방식
    filename = '0' * (2 - len(str(indx))) + str(indx) # 일의 자리 숫자인경우 0 포함
    filename = f'{foldername}/{filename}.jpg' # jpg 파일로 파일명 생성
    response = requests.get(data['img']) # GET 요청 보내서 image 응답 받기
    with open(filename, 'wb') as file: # write binary 형식으로 파일 생성
        file.write(response.data)

Selenium

import pandas as pd 
from selenium import webdriver 
from selenium.webdriver.common.by import By

# 크롬 웹드라이버 실행
driver = webdriver.Chrome()

# 크롬 웹드라이버 headless 방식으로 실행 (크롬 브라우저 창 실행 x)
options = webdriver.ChromeOptions()
options.add_argument('headless')
driver = webdriver.Chrome(options=options)

# 드라이버가 해당 url 에 GET 요청을 보내서 화면 출력
driver.get('https://daum.net')

# input 태그에 텍스트 입력
selector = '#q'
driver.find_element(By.CSS_SELECTOR, selector).send_keys('아이스크림')

# 검색 아이콘 클릭
selector = '.inner_search > .btn_search' 
driver.find_element(By.CSS_SELECTOR, selector).click()

# 원하는 데이터를 elements 에 저장
selector = '#card_list > .title' 
elements = driver.find_elements(By.CSS_SELECTOR, selector) 

# XPATH 방식으로 elements 에 저장
elements = driver.find_element(By.XPATH, selector).text

# 스크롤 시키는 자바스크립트 코드 실행
driver.execute_script('window.scrollTo(200, 500);')

# 현재 브러우저 종료
driver.quit()

댓글