이번 내용은 앞에서 했던 두가지 내용을 합치는 내용입니다.
database 는 이전의 내용과 비슷하나 MarketInfoDb 하나의 클래스가 추가 되었습니다.
이전 내용은 아래 링크를 참고 하시기 바랍니다.
Python 에서 sqlite3 사용하기
https://swlock.blogspot.com/2019/02/python-sqlite3-dataframe.html
아래는 전체소스 입니다.
database.py
import os import sqlite3 import datetime import pandas as pd from pandas import Series, DataFrame #print(str(sqlite3.version)) class SqliteDb(): def __init__(self): super().__init__() def connect(self, name): self.con = sqlite3.connect(name) self.cursor = self.con.cursor() return self.cursor def make_table(self, table ): self.cursor.execute("CREATE TABLE "+ table + "(idx INTEGER PRIMARY KEY)") def exists_table(self, table): try : self.cursor.execute("SELECT * FROM " + table) return True except : return False def exists_table_column(self, table, coulumn) : try : self.cursor.execute("SELECT %s FROM %s "%(coulumn, table)) return True except : return False def add_column(self, table, column_name_type) : # add column https://www.sqlite.org/datatype3.html # add_column(TABLE_NAME,'column_name float') sql = "ALTER TABLE %s ADD COLUMN %s" % (table, column_name_type) self.cursor.execute(sql) def insert_data(self, table, values): # column 순서 대로 입력됨 #insert_data(TABLE_NAME,"'2018-01-01',1000") sql = "INSERT INTO %s VALUES(%s)" % (table, values) self.cursor.execute(sql) def insert_data_with_cols(self, table, cols, values): # 원하는 column 에 원하는 값을 넣을때 사용 #insert_data_with_cols("table_name","column_name1,column_name2","value1,value2") sql = "INSERT INTO %s(%s) VALUES(%s)" % (table, cols, values) self.cursor.execute(sql) def get_value(self, table, cols, condition): #value = get_value("table_name","colname","idx=value") sql = "SELECT %s FROM %s WHERE %s" % (cols, table, condition) cursor = self.cursor.execute(sql) row = cursor.fetchone() if row==None : return None if len(row)==0 : return None return row[0] def update_value(self, table, setvalue, condition): #update_value("table_name","colname=value","idx=value") sql = "UPDATE %s SET %s WHERE %s" % (table, setvalue, condition) self.cursor.execute(sql) def get_dataframe(self, table): df = pd.read_sql_query("SELECT * FROM %s" % table, self.con) return df def close(self): self.con.commit() self.con.close() class MarketInfoDb(SqliteDb): def __init__(self): super().__init__() self.table_name = "market_info" self.col_name_date = "date" def connect(self, name): super().connect(name) if super().exists_table(self.table_name) == False : super().make_table(self.table_name) super().add_column(self.table_name, " %s text " % self.col_name_date) def insert_base(self, datetime, values, colname, force=False): if super().exists_table_column(self.table_name, colname) == False : super().add_column(self.table_name, " %s float " % colname) #이미 값이 있는지 확인 #인덱스 획득 idx = super().get_value(self.table_name,"idx","%s='%s'"%(self.col_name_date,datetime.date())) if( idx == None ): # 빈상태이다 추가함 super().insert_data_with_cols(self.table_name,"%s,%s"%(self.col_name_date,colname),"'%s',%f"%(datetime.date(), values)) else: # date는 존재함 # 값이 있는지 재확인 value = super().get_value(self.table_name,colname,'idx=%d'%(idx)) if( value == None ): #값이 없는 경우 super().update_value(self.table_name,"%s=%f"%(colname,values),'idx=%d'%(idx)) else: #값이 있음 if force==True : #강제 update super().update_value(self.table_name,"%s=%f"%(colname,values),'idx=%d'%(idx)) else : #변경 못함 return False return True def insert_with_external_column_name(self, datetime, values, colname, force=False): return self.insert_base(datetime, values, colname, force) def get_dataframe_fromdb(self): return super().get_dataframe(self.table_name)
기본적으로 db에 값을 입력하는것은 insert_with_external_column_name 함수를 이용하게 됩니다. 내부적으로는 insert_base 함수를 호출하게 되는데 하는 역할은 날짜에 주식 값이 있는 확인해보고 없으면 추가하고 있다면 flase를 리턴하게 됩니다. 문제는 db특성상 날짜에 해당 값이 있는지 확인하는 과정이 복잡합니다. 날짜가 존재하는 경우가 있고 날짜가 있으나 특정 주식 값만 존재하지 않을 가능성이 있기 때문입니다.
다음으로는 웹에서 데이터를 읽어서 db에 넣는 과정입니다. 이것은 이전 소스와 다르지 않습니다.
네이버 주식 데이터 읽기
https://swlock.blogspot.com/2019/03/naver-with-python.html
test.py
#getstockdata import requests as re from bs4 import BeautifulSoup import datetime as date import datetime import time import os import database PAGE_TEST = False def naver_stock_crawling(db, code, name): # 코스피 NAME ='종목 %s %s' % (code, name) print("%s Start crawling"%(NAME)) url = 'https://finance.naver.com/item/sise_day.nhn?code=%s&page=%d' key_prefix = 'K%s_' % (code) count = 0 need_to_break = False date_list = [] endpage = 100000 if PAGE_TEST==True: endpage = 2 for i in range(1,endpage): url_ = re.get(url % (code,i)) url_ = url_.content html = BeautifulSoup(url_,'html.parser') add_data = False tds = html.find_all('td') index = 100 for td in tds : try : text = td.text.strip() try : datetime.datetime.strptime(text, '%Y.%m.%d') get_date = True except : get_date = False if get_date==True : index = 0 date_ = td.text.strip().replace('.','-') if not date_ in date_list: date_list.append(date_) else: #마지막 페이지 print("%s %d End page Done"%(NAME, count)) return if(index == 1): #종가 add_data = True d = td.text.strip().replace(',','') d = float(d) if PAGE_TEST==True: print("%s %f %s close"%(date_,d,key_prefix)) else: if db.insert_with_external_column_name(datetime.datetime.strptime(date_, '%Y-%m-%d'),d,key_prefix+'close')==False: need_to_break = True if(index == 3): #시가 add_data = True d = td.text.strip().replace(',','') d = float(d) if PAGE_TEST==True: print("%s %f %s open"%(date_,d,key_prefix)) else: if db.insert_with_external_column_name(datetime.datetime.strptime(date_, '%Y-%m-%d'),d,key_prefix+'open')==False: need_to_break = True if(index == 4): #고가 add_data = True d = td.text.strip().replace(',','') d = float(d) if PAGE_TEST==True: print("%s %f %s high"%(date_,d,key_prefix)) else: if db.insert_with_external_column_name(datetime.datetime.strptime(date_, '%Y-%m-%d'),d,key_prefix+'high')==False: need_to_break = True if(index == 5): #저가 add_data = True d = td.text.strip().replace(',','') d = float(d) if PAGE_TEST==True: print("%s %f %s low"%(date_,d,key_prefix)) else: if db.insert_with_external_column_name(datetime.datetime.strptime(date_, '%Y-%m-%d'),d,key_prefix+'low')==False: need_to_break = True if(index == 6): #거래량 add_data = True d = td.text.strip().replace(',','') d = float(d) if PAGE_TEST==True: print("%s %f %s vol"%(date_,d,key_prefix)) count = count + 1 else: if db.insert_with_external_column_name(datetime.datetime.strptime(date_, '%Y-%m-%d'),d,key_prefix+'vol')==False: need_to_break = True else: count = count + 1 except: pass index += 1 if add_data == False: # 마지막 페이지 print("%s %d End page Done"%(NAME, count)) return if need_to_break == True : print("%s %d Done"%(NAME, count)) return db = database.MarketInfoDb() db.connect("stockdata.db") if PAGE_TEST==True : db = None naver_stock_crawling(db,'005930','삼성전자') naver_stock_crawling(db,'035420','NAVER') if PAGE_TEST!=True : db.close() #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dbstock = database.MarketInfoDb() dbstock.connect("stockdata.db") df = dbstock.get_dataframe_fromdb() print(df.head()) print(df.shape)
결과
종목 005930 삼성전자 Start crawling 종목 005930 삼성전자 5712 End page Done 종목 035420 NAVER Start crawling 종목 035420 NAVER 4046 End page Done idx date K005930_close K005930_open ... K035420_open K035420_high K035420_low K035420_vol 0 1 2019-03-08 43800.0 44450.0 ... 135500.0 136000.0 131500.0 303950.0 1 2 2019-03-07 44450.0 43400.0 ... 139500.0 139500.0 136500.0 254573.0 2 3 2019-03-06 44000.0 44000.0 ... 136500.0 139000.0 134500.0 403724.0 3 4 2019-03-05 44250.0 44600.0 ... 140000.0 140000.0 135000.0 387063.0 4 5 2019-03-04 44850.0 46000.0 ... 135000.0 139500.0 134000.0 743644.0 [5 rows x 12 columns] (5712, 12)
댓글 없음:
댓글 쓰기