본문 바로가기
코딩 공부/python

기업 목록 내 DB에 저장하기

by Camel_coding_food 2022. 2. 21.
반응형

 

맞는 말이죠.

 

이번에는 우리나라 상장기업 목록을 한국 기업 공시 채널에서 -> 제 데이터베이스로 가져와보겠습니다.

 

 

이번 코드는 좀 길지만 끊어서 올리는 것보다

한번에 올리는게 이해에 도움이 될 것 같아 한 글에 올립니다.

 

 

작성해봅시다.

import pymysql
import pandas as pd
from datetime import datetime

일단 이번 글에서 필요한 모듈 설치 파트입니다.

이제 익숙하죠?

 

 

 

다시 작성합시다.

class DBUpdater:
    def __init__(self):
        """생성자: MariaDB 연결 및 종목코드 딕셔너리 생성"""

    
        self.conn = pymysql.connect(host='127.0.0.1', user='root',password='각자 설정했던 비밀번호', db='investar', charset='utf8')
        #pymysql모듈 속 connect 함수를 이용합니다. 
        #host에는 로컬호스트가 와야합니다. localhost, 아니면 로컬호스트의 주소를 넣어주면 됩니다. 보통은 127.0.0.1 입니다.
        #user에는 mariaDB를 켰을 때 설정한 아이디를 넣어주면 됩니다.
        #db에는 데이터베이스를 만들때 정했던 이름, charset='utf8'은 기업명이 한글이기 때문에 깨지지 않은 글씨를 받기 위해서 옵니다.
        
        
        with self.conn.cursor() as curs:
            sql ="""
            CREATE TABLE IF NOT EXISTS company_info (
                code VARCHAR(20),
                company VARCHAR(40),
                last_update DATE,
                PRIMARY KEY (code))
            """
            curs.execute(sql)
            sql="""
            CREATE TABLE IF NOT EXISTS daily_price (
                code VARCHAR(20),
                date DATE,
                open BIGINT(20),
                high BIGINT(20),
                low BIGINT(20),
                close BIGINT(20),
                diff BIGINT(20),
                volume BIGINT(20),
                PRIMARY KEY (code, date))
            """
            #IF NOT EXISTS 를 넣어 테이블이 존재하지 않을때 테이블을 만들도록 한다.
            
            #BIGINT 는 큰 정수를 범위로 지정해준다. 대신 저장공간 차지 많이한다.
            #NOT NULL은 공백을 허용하지 않는다는 뜻이다.
            #PRIMARY KEY는 괄호 안의 칼럼 내용들이 중복되면 안된다는걸 지정해준다.
            curs.execute(sql)
        self.conn.commit()
        self.codes =dict()
        self.update_comp_info()

 

 

 

 

 

class 지정은 처음에만 해주면 됩니다.

 

다음 코드부터는 def으로 함수만 지정해주면 됩니다.

    def __del__(self):
        """소멸자: MariaDB 연결 해제"""
        self.conn.close()


    def read_krx_code(self):
        url = 'https://kind.krx.co.kr/corpgeneral/corpList.do?method='\
        'download&searchTpye=13'

        krx = pd.read_html(url, header=0)[0]
        #html 파일을 읽어준다.
        
        krx = krx[['종목코드', '회사명']]
        #데이터프레임을 이용하여 원하는 칼럼만 뽑는다.
        
        krx = krx.rename(columns={'종목코드':'code','회사명':'company'})
        #영어 칼럼을 한글 칼럼으로 바꿔준다. 꼭 필요하지는 않은 코드이다.
        
        krx.code = krx.code.map('{:06d}'.format)
        #종목코드형식을 조정해준다.
        return krx

 

 

 

 

세부 설명은 코드 밑에 한줄씩 달아 놓겠습니다.

 def update_comp_info(self):
        sql = "SELECT * FROM company_info"
        #SQL문법을 이용해 sql 변수에 company_info 테이블을 저장해준다.
        
        df = pd.read_sql(sql, self.conn)
        #판다스 모듈의 read_sql 함수를 이용하여 company_info 테이블을 읽어준다.
        
        for idx in range(len(df)):
            self.codes[df['code'].values[idx]]=df['company'].values[idx]
            #읽어온 테이블을 이용해 codes 딕셔너리를 만든다.
            
        with self.conn.cursor() as curs:
        #with문을 이용해 conn.cursor()를 curs로 객체화 시킨다.
            
            sql ="SELECT max(last_update) FROM company_info"
            #SQL문법을 이용해 last_update 테이블의 가장 최근 업데이트 날짜를 읽도록 할당한다.
            
            curs.execute(sql)
            #curs로 객체화된 cursor()을 이용하여 sql에 저장된 문장을 excute() 메소드를 이용해 DB에 쿼리문을 보낸다.            
            
            rs = curs.fetchone()
            #DB에서 가장 최근 업데이트 날짜를 가져와 rs변수에 저장한다.
            today = datetime.today().strftime('%Y-%m-%d')
            #오늘 날짜를 today 변수에 저장해준다.

        
            if rs[0] == None or rs[0].strftime('%Y-%m-%d') < today:
            #위에서 추출한 rs가 없거나, 오늘보다 옛날일때 업데이트를 해준다.
            
                krx = self.read_krx_code()
                #krx 상장기업을 읽어와 krx 프레임에 저장한다.
                
                for idx in range(len(krx)):     
                    code = krx.code.values[idx]
                    company = krx.company.values[idx]
                    sql = f"REPLACE INTO company_info (code, company, last_update) VALUES ('{code}','{company}','{today}')"
                    curs.execute(sql)
                    #curs로 객체화된 cursor()을 이용하여 sql에 저장된 문장을 excute() 메소드를 이용해 DB에 쿼리문을 보낸다. (업데이트)
                   
                    self.codes[code] = company
                    tmnow = datetime.now().strftime('%Y-%m-%d %H:%M')
                    print(f"[{tmnow}] {idx:04d} REPLACE INTO company_info VALUES ({code},{company},{today})")
                        
                self.conn.commit()
                print('')

if __name__ == '__main__':
    dbu = DBUpdater()
    dbu.update_comp_info()

 

이 코드를 입력한 후 실행하시면

전에 만들어 둔 investar 데이터베이스에 

 

스크린샷이 좀 깨졌네요.

이런식으로 저장됩니다.

 

코드를 잘보시면 아직 기업 목록을 가져오는 코드만 존재한다는걸 알 수 있습니다.

 

그러므로 daily_price 테이블이 비어있는게 당연합니다.

 

 

 


겪은 오류

 

SQL 카테고리 글을 보시면 알 수 있듯이

저는 아직 SQL, 데이터 분야에 초보입니다.

 

나머지 분야도 사실 마찬가지긴 하죠.

 

그래서 정말 어이없는 실수로 4시간 가까이 날렸습니다.

 

 

MySQL을 설치하지 않았던겁니다.

 

 

제 글을 보신분들은 이런 말씀을 하실겁니다.

 

그럼 MySQL 없이 테이블을 어떻게 생성했고,

VScode에서 데이터베이스 관련 코드를 작성했는가.

 

 

가능합니다.

 

 

mariaDB와 VScode를 사용하면 SQL 문법을 작성할 수 있으며,

MySQL Client 창을 이용해 직접 코드를 작성해 테이블을 만들 수 있습니다.

 

대신 VScode와 같은 IDLE에서 작성한 코드와

데이터베이스를 연결할 수 없죠.

 

그래서 파이썬 파일 속 코드에서 로컬 호스트로 데이터베이스에 접근해도

자꾸 접근 거부 당했습니다.

 

검색해보니 컴퓨터가 자신의 로컬호스트로 접근해도 

접근 거부 당하는 오류가 있긴 했습니다.

 

그래서 제가 사용하려는 포트의 사용을 관리자 권한으로 모두 사용 정지 시켜보기도하고,

포트를 바꿔보기도하고,

정말 해볼 수 있는건 다해봤습니다.

 

 

그러던 와중에 MySQL을 재시작해보라는 글을 찾아,

제어판 속 서비스에 들어가서 MySQL을 찾던 도중,

MySQL이 없다는걸 깨달았습니다.

 

 

정말 황당한 실수였습니다.

 

어려운 코드가 아니였는데도 스스로 어렵게 만드는 제 재주에 감탄했습니다.

 

 

이 책을 보시는 분들이나, 처음 SQL을 배우시는 분들은

혹시 자꾸 로컬호스트 접근이 안된다거나

알 수 없는 오류가 발생한다면

MySQL이 깔려있는지 서비스에 들아가서 확인해보시길 바랍니다.

 

 

그래도 해결하여 다음 진도를 진행할 수 있다는 사실에 안도했습니다.

 

 

다음번에는 남은 테이블을 종목별 주가로 채워보겠습니다.

반응형

댓글