멋사 AISCOOL 7기 Python/INPUT

[크롤링] requests, BeautifulSoup, Json

dundunee 2022. 9. 29. 00:22

# 웹 데이터를 수집하는 방법

  • Web Scraping vs API
  • 데이터 수집 과정은 reverse engineering 과정이다

# 네이버 금융 개별 종목 수집#

# tqdm: 진행상황을 보여주는 라이브러리, trange라고 하면 범위내에서 진행상황을 알려줌

# pd.read_html의 오류

  • 테이블테그가 없거나, 테이블코드가 있어도 url을 불러오지 못함
  • 접근 권한을 막아놨기때문에, 브라우저를 정상적으로 요청하지 않았기 때문에
  • 이런 경우 셀리니움으로 수집하기도 하나, 시간이 오래걸리는 단점이 있음.

# requests

  • 사람을 위해서 만들어진 http 통신 도구(HTTP for Humans), 크롬과 달리 소스코드만 보여줌
  • 라이브러리, 작은 브라우저로 웹사이트를 읽어오는 목적
  • header에서 requets method를 확인할 수 있음: get 방식(쿼리를 통해서 전송하느냐), post 방식(폼을 통해서 전송하느냐)
  • post 는 회원 가입할 때 적은 정보 폼, 물건이나 음식 주문할 때 메시지 입력하고 버튼 누를 때, 검색어를 입력하고 버튼을 눌렀을 때

# requests를 통한 HTTP요청

  • http 상태코드: 2xx(성공)
  • url은 제대로 불러오나 정상요청이 아니라고 출력되는 경우? header = {user-agent: }, 이는 브라우저가 보내는 요청임을 의미함
# 라이브러리 로드
import pandas as pd
import numpy as np
import requests

# 종목번호와 상장사 이름을 item_code와 item_name으로 설정
item_code = "005930"
item_name = "삼성전자"
page_no = 1

# 종목 URL 만들기
url = f"<https://finance.naver.com/item/sise_day.naver?code={item_code}&page={page_no}>"

# requests를 통한 HTTP 요청
response = requests.get(url, headers={'user-agent' : 'Mozilla/5.0'})
response
# 결과로 <response[200]> 이 출력욈, 이는 http상태코드

response.text

</response[200]>

# BeautifulSoup 을 통한 table 태그 찾기

  • 읽어온 웹 사이트의 HTML 문서를 해석하는 목적으로 사용
  • 데이터를 수집하는 도구가 아니라 html 페이지를 parsing하는 용도르 쓰임
  • 즉 html에서 원하는 정보를 찾아오는 도구
from bs4 import BeautifulSoup as bs
html = bs(response.text)
html.title
html.a #링크를 의미함, 잘 안씀
html.find_all('a') #링크를 모두 가져옴
html.select('a') #a태그에 있는 기능을 모두 가져움

html.select('body > table') #html.table
html.select(" table > tr > td")
html.select("body > table.type2") #일별시세 테이블

 

#판다스 코드 한줄로 네이버 금융 일자별 시세를 페이지별로 수집하기

def get_day_list(item_code, page_no):
    """
    일자별 시세를 페이지별로 수집
    1) url을 만든다.
    2) requests를 통해서 html 문서를 받아온다
    3) read_html을 통해 table 태그를 읽어온다. pd.read_html(response.text) 하면 html내에 있는 테이블 태그만 불러옴
    4) 결측행을 제거
    5) 데이터 프레임 반환
    """
    url =  f"<https://finance.naver.com/item/sise_day.naver?code={item_code}&page={page_no}>"
    response = requests.get(url, headers={'user-agent' : 'Mozilla/5.0'})

    table = pd.read_html(response.text)
    tmp = table[0]

    df = tmp.dropna()
    df = df.reset_index(drop=True)
    
    return df

#반복문을 통한 전체 일자 및 페이지에 대한 데이터 수집하기

def get_item_list(item_code, item_name):
    """
    일별 시세를 수집하는 함수
    """
    page_no = 1

    # 데이터를 저장할 빈 변수 선언
    item_list = []

    prev_day = ""

    while True:
        df_item = get_day_list(item_code, page_no)
        last_day = df_item.iloc[-1]["날짜"]

        if last_day == prev_day:
            break

        prev_day = last_day
        item_list.append(df_item)
        page_no = page_no + 1
        #서버에 부담을 주지 않기 위해서
        time.sleep(0.01)
    
    #데이터프레임 수정
    df = pd.concat(item_list)
    df["종목코드"] = item_code
    df["종목명"] = item_name
    #컬럼 위치 변환
    cols = ['종목코드', '종목명', '날짜', '종가', '전일비', '시가', '고가', '저가', '거래량']
    df = df[cols]

    df = df.drop_duplicates()
    df = df.reset_index(drop=True)

    #파일에 저장 후 파일명 반환
    date = df.iloc[0]["날짜"] #최근날짜 가져오기
    file_name = f"{item_name}_{item_code}_{date}.csv"
    df.to_csv(file_name, index=False)

    return file_name

pd.read(file_name)
return file_name

#크롬브라우저의 네트워크정보를 통한 네이버금융 ETF 데이터 수집#

# JSON

  • 데이터포맷
  • API 형태로 제공하고 있는 데이터를 json 형태로 받아옴
  • 데이터프레임으로 변환: df = pd.DataFrame(etfItemList)
  • request.get으로 받아오는 것 보다 데이터프레임으로의 변환이 쉬움
# 라이브러리를 불러옵니다.
import pandas as pd
import numpy as np
import requests

#requests를 통한 HTTP요청
url = '<https://finance.naver.com/api/sise/etfItemList.nhn?etfType=0&targetColumn=market_sum&sortOrder=desc>'
response = requests.get(url)

#JSOON타입으로 데이터 받기
etf_json = response.json()

#JSON에서 원하는 데이터 찾기
#JSON View를 통해서 확인: result > etfItemList 의 하위 구조로 목록을 찾고자 하는 데이터
etfItemList = etf_json["result"]["etfItemList"]

#데이터 프레임 변환
# 키-값 형태의 데이터를 데이터프레임으로 만듭니다.
df = pd.DataFrame(etfItemList)

#오늘날짜로 파일명 저장
from datetime import datetime

today = datetime.today().strftime("%Y-%m-%d")
file_name = f"etf_{today}_raw.csv"

#파일 저장하고 불러오기
# itemcode 숫자 앞의 0 이 지워진다면 dtype={"itemcode": np.object} 로 타입을 지정해 주면 문자형태로 읽어옵니다.
df.to_csv(file_name, index=False)
pd.read_csv(file_name, dtype={"itemcode":"object"})