[웹크롤링] 주식정보 크롤링 & DB적재 스케줄링

Jonie Kwon·2022년 6월 13일
0
post-thumbnail

목표

  1. https://comp.fnguide.com/에서 주식 데이터 크롤링
  2. 크롤링 데이터 데이터베이스에 저장
  3. Slack연동 후 에러 시 알람
  4. 매일 장이 끝나면 자동으로 DB에 저장하도록 작업 스케줄링 설정

1. 주식 데이터 크롤링

from urllib.request import urlopen
from bs4 import BeautifulSoup

url = "https://comp.fnguide.com/"
html = urlopen(url)
bs_obj = BeautifulSoup(html, "html.parser")

urlopen 함수로 웹 페이지를 열고 html 내용 파싱

개발자도구를 이용하여 크롤링하려는 데이터의 태그를 확인하고 .find() 또는 .find_all을 이용해서 필요한 정보를 추출합니다.

# 날짜
date = date.text[1:-1].replace('/', '-')

# 기업명
corp_name = bs_obj.find_all("h1", {"id":"giName"})

# 종목 코드
code = bs_obj.find_all("div", {"class":"corp_group1"})
code = code[0].find("h2")
code = code.text


...


# 우상단 테이블
upper_right_list = bs_obj.find("div", {"class":"corp_group2"})
dd = upper_right_list.find_all('dd')

per = float(dd[1].text)
per_12m = float(dd[3].text)
per_ind = float(dd[5].text)
pbr = float(dd[7].text)
div_yid = dd[9].text
div_yid = float(div_yid.replace("%", ""))

2. 데이터 적재

MySQL DB 및 테이블 생성

MySQL에서 stock 이라는 DB를 생성해 주고 daily_market이라는 테이블을 생성합니다.

create table stock.daily_market(
    seq int not null auto_increment,
    dt date,
    item_name varchar(100),
    item_code varchar(100),
    price bigint,
    foreign_ownership_ratio float,
    rel_return float,
    per float,
    per_12m float,
    per_ind float,
    pbr float,
    dividend_yield float,
    volume bigint,
    trans_price bigint,
    market_capital_prefer bigint,
    market_capital_common bigint,
    reg_date date,
    primary key(seq)
);

파이썬으로 MySQL에 데이터 추가하기

pymysql.connect()을 이용해 mysql서버에 접속합니다.
cursor는 쿼리문에 의해 반환되는 결괏값이 저장되는 메모리 공간을 의미합니다.
cursor를 생성하고 execute 메서드에 쿼리문을 넣어서 실행할 수 있습니다.

import pymysql
conn = pymysql.connect(host='localhost', user='root', password='1234', db='stock', charset='utf8')

sql_state = """INSERT INTO stock.daily_market(dt, item_name, item_code, price, foreign_ownership_ratio, rel_return, per, per_12m, per_ind, pbr, dividend_yield, volume, trans_price, market_capital_prefer, market_capital_common, reg_date) 
VALUES ('%s', '%s', '%s', %d, %f, %f, %f, %f, %f, %f, %f, %d, %d, %d, %d, NOW())"""%(tuple([date, corp_name, code, stock_price, fgn_own_ratio, rel_return, per, per_12m, per_ind, pbr, div_yid, volume, trans_price, mk_cpt_pfr, mk_cpt_cm]))

# 커서 생성
db = conn.cursor()
# 쿼리 실행
db.execute(sql_state)
conn.commit()
# 연결 종료
conn.close()

데이터가 잘 들어갔는지 mysql에서 확인

SELECT * FROM stock.daily_market;

3. Slack 알람 설정

slack API 봇 생성

슬랙 API에서 create an app을 눌러 앱을 생성합니다

From scratch를 누르면 App Name과 알람이 갈 슬랙 workspace를 선택할 수 있습니다.

Add features and functionality에서 Bots, Permissions를 체크,
Install your app을 눌러서 슬랙에 app을 추가해 줍니다

OAuth & Permissions을 누르고 스크롤을 조금 내려보면 Scopes란이 있는데, Bot Token Scopes에 chat:write 기능을 추가해 줍니다.

그리고 슬랙 workspace 채팅 창에 @봇이름을 입력해서 채팅창에 봇을 추가합니다.

xoxb-로 시작하는 Bot User OAuth Token을 copy해 줍니다.

파이썬으로 슬랙에 메시지 보내기

파이썬으로 돌아와서 복사한 token을 입력하고, 알람을 보낼 slack채널명, 알람 메시지를 입력하고 requests.post() 메서드를 이용해 메시지를 보냅니다.

import requests
token = "xoxb-토큰"
channel = "#stock_alarm01"
text = "Check your stock crawler."
requests.post("https://slack.com/api/chat.postMessage", headers={"Authorization": "Bearer " + token}, data={"channel": channel, "text":text})

4. 윈도우 스케줄러 설정

conda 가상환경 경로 확인

아나콘다 프롬프트에 conda env list를 입력해서 현재 사용하고있는 가상 환경의 경로를 확인

main.py 작성

윈도우 스케줄러에서 실행할 메인 실행 파일을 작성합니다.

from urllib.request import urlopen
from bs4 import BeautifulSoup
import pymysql
import time
import requests

def stock_crawling(item):
    url = "https://comp.fnguide.com/SVO2/ASP/SVD_Main.asp?pGB=1&gicode=A" + item + "&cID=&MenuYn=Y&ReportGB=&NewMenuID=11&stkGb=701"
    html = urlopen(url)
    bs_obj = BeautifulSoup(html, "html.parser")

    # 날짜
    date = bs_obj.find("span", {"class": "date"})
    date = date.text[1:-1].replace('/', '-')

    # 회사명
    corp_name = bs_obj.find_all("h1", {"id": "giName"})
    corp_name = corp_name[0].text

    # 종목 코드
    code = bs_obj.find_all("div", {"class": "corp_group1"})
    code = code[0].find("h2")
    code = code.text

    # 주가
    stock_price = bs_obj.find("span", {"id": "svdMainChartTxt11"})
    stock_price = int(stock_price.text.replace(",", ""))

    # 외국인 보유 비중
    fgn_own_ratio = bs_obj.find("span", {"id": "svdMainChartTxt12"})
    fgn_own_ratio = float(fgn_own_ratio.text)

    # 상대 수익률
    rel_return = bs_obj.find("span", {"id": "svdMainChartTxt13"})
    rel_return = float(rel_return.text)

    # 상단 테이블
    upper_right_list = bs_obj.find("div", {"class": "corp_group2"})
    dd = upper_right_list.find_all('dd')

    per = float(dd[1].text)
    per_12m = float(dd[3].text)
    per_ind = float(dd[5].text)
    pbr = float(dd[7].text)
    div_yid = dd[9].text
    div_yid = float(div_yid.replace("%", ""))

    # 시세현황 테이블
    table = bs_obj.find("div", {"class": "ul_wrap", "id": "div1"})
    table_td = table.find_all("td")

    volume = table_td[1].text
    volume = int(volume.replace(",", ""))
    trans_price = table_td[3].text
    trans_price = int(trans_price.replace(",", ""))
    mk_cpt_pfr = table_td[3].text
    mk_cpt_pfr = int(mk_cpt_pfr.replace(",", ""))
    mk_cpt_cm = table_td[3].text
    mk_cpt_cm = int(mk_cpt_cm.replace(",", ""))

    return [date, corp_name, code, stock_price, fgn_own_ratio, rel_return, per, per_12m, per_ind, pbr, div_yid, volume,
            trans_price, mk_cpt_pfr, mk_cpt_cm]

def db_insert(res):

    try:
        conn = pymysql.connect(host='localhost', user='root', password='1234', db='stock', charset='utf8')
        sql_state = """INSERT INTO stock.daily_market(dt, item_name, item_code, price, foreign_ownership_ratio, rel_return, per, per_12m, per_ind, pbr, dividend_yield, volume, trans_price, market_capital_prefer, market_capital_common, reg_date) 
VALUES ('%s', '%s', '%s', %d, %f, %f, %f, %f, %f, %f, %f, %d, %d, %d, %d, NOW())"""% (tuple(res))
        db = conn.cursor()
        db.execute(sql_state)
        conn.commit()
    except:
        token = "xoxb-토큰"
        channel = "#stock_alarm01"
        text = "[DB Insert Error] Check your stock crawler."
        requests.post("https://slack.com/api/chat.postMessage", headers={"Authorization": "Bearer " + token},
                      data={"channel": channel, "text": text})
    finally:
        conn.close()

if __name__ == '__main__':
    # 크롤링 할 종목코드
    item_list = ['005930', '112040']

    for item in item_list:
        res = stock_crawling(item)
        db_insert(res)
        time.sleep(3)

작업 스케줄러 작업 만들기

윈도우 작업 스케줄러 에서 작업 만들기 클릭

이름과 설명 입력하고, 구성 대상-Windows10 선택

트리거 탭으로 이동해서 새 트리거를 추가해 줍니다.

동작탭으로 이동해서 프로그램 시작하는 작업을 추가해 줍니다.
프로그램은 가상환경 경로에 있는 python으로 입력
인수 추가 옵션에는 크롤러 파이썬 파일 경로와 파이썬 프로그램명
시작 위치는 파일 경로까지만 입력해줍니다.

추가된 데이터 확인

스케줄러로 2, 3번 데이터가 잘 추가된걸 볼 수 있습니다.
삼전 7x층 주민은 그럼 이만..😭😇

profile
메모하는 습관

0개의 댓글