Created
March 9, 2017 00:04
Revisions
-
verystrongjoe created this gist
Mar 9, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,232 @@ from bs4 import BeautifulSoup import requests import urllib import datetime, time from prettytable import PrettyTable ## resilience 주식의 회복 탄력성을 계산해주는 로직 class Resilience : # 1~ 513 페이지를 네비게이션하면서 1996년도에서 오늘까지의 일일 종가 데이터를 가져온다. domainUrl = 'http://finance.naver.com/item/sise_day.nhn?code=' pageUrl = '&page=' threshold_DroppedPersent = 5 threshold_MaxDayToCountupRecoveryTime = 1000 def main(self, code): prices = Resilience.getPricesFromWeb(self, code) dropPrices = Resilience.getDropBadlyList(self,prices) dropPrices = Resilience.calculateDaysToBeRecovered(self,prices,dropPrices) Resilience.printRecoveryReport(self,dropPrices) newsList = Resilience.getNewsList(self,code) dropPrices = Resilience.appendRelatedNewsOnDroppedDay(self,dropPrices,newsList) Resilience.printResultWithNews(self,dropPrices) def getPricesFromWeb(self, code): # last page 구하는 로직 구현 last_page_index = 50 list = [] for page in range(1, last_page_index): url = Resilience.domainUrl + code + str(Resilience.pageUrl) + str(page) source_code = requests.get(url, timeout=None) soup = BeautifulSoup(source_code.text, 'lxml') tableSoup = soup.find('table', attrs={'class', 'type2'}) trSoup = tableSoup.find_all('tr') i = 0 rowcount = 0; for tr in trSoup: i = i + 1 if i > 2 and i < 16 and i <= len(tr): if i == 8 or i == 9 or i == 10: continue j = 0 dic = {} for td in tr: j = j + 1 if j == 2: date_str = str(td.span.text) date_str = date_str.replace(".", "") dic['date'] = datetime.date(int(date_str[0:4]), int(date_str[4:6]), int(date_str[6:8])) if j == 4: price = str(td.span.text) dic['price'] = int(price.replace(',', '')) if j == 6: change = str(td.span.text).strip() if change != '0': if td.img['src'].endswith('ico_up.gif') or td.img['src'].endswith('ico_up2.gif'): dic['change'] = int(change.replace(',', '')) else: dic['change'] = -1 * int(change.replace(',', '')) else: dic['change'] = 0 list.append(dic) return list def getDropBadlyList(self, list): # 하루 등락률이 10프로 하락하는 지점을 찾는다. 하락을 했다면 그날의 시가를 가지고 향후 언제 그 가격을 넘어서는지를 찾을 것이다. # 전날 종가를 기준으로 등락률을 매기는게 맞는데 그냥 당일 종가와 등락 가격을 가지고 퍼센티지를 계산함. drop_badly_list = [] for day in list : #print(day['date'] + " : " + str(day['price']) + " : " + str(day['change'])) percent = ( day['price'] + day['change'] ) / day['price'] * 100 - 100 #print(day['date'] + " : " + str(percent)) if percent < -1 * Resilience.threshold_DroppedPersent : drop_badly_list.append(day) # 그래서 우선 list를 filter해서 가지고 있고 그 시가를 가지고 있는 list를 만들 것이다. 그리고 이 filtered_list를 가지고 다시 원래의 list return drop_badly_list # 우선 특정 % 이상 떨어진 일자들을 얻고 각각 일자에 대해 전날 종가 가격으로의 회복 기간이 얼마 소요되었는지 하고 그것에 대한 평균도 구하도록 한다. # threshold 한계값 정해서 이 값을 넘을 경우는 실제 계산에서 배제를 하도록 한다. : 추가 기능 def calculateDaysToBeRecovered(self, list, drop_badly_list): # 날짜 오름차순으로 변경 list.reverse() recovery = [] for drop_day in drop_badly_list: change = drop_day['change'] yesterdayPrice = drop_day['price'] d = drop_day['date'] counting = 0 isCounting = False element = {} for day in list: if day['date'] == d: isCounting = True yesterdayPrice -= change theDay = d if isCounting: if yesterdayPrice < day['price']: break else: counting = counting + 1 # print(day['date'],day['price']) element['theDay'] = theDay element['counting'] = counting element['yesterdayPrice'] = yesterdayPrice recovery.append(element) return recovery def printRecoveryReport(self, recovery): t = PrettyTable(['5% 이상 떨어진 일자','회복하는데 걸린 일수', '회복해야하는 주가']) for ele in recovery: t.add_row([ele['theDay'], ele['counting'], ele['yesterdayPrice']]) print(t) # for ele in recovery : # print('----------------------------') # print('5% 이상 떨어진 일자 : ', ele['theDay']) # print('회복하는데 걸린 일수 : ', ele['counting']) # print('회복해야하는 주가 : ', ele['yesterdayPrice']) sum = 0 for ele in recovery : sum = sum + ele['counting'] print('The average of days to recover is ' , sum/len(recovery)) def getNewsList(self, code): # 그다음 이시기에 어떤 뉴스가 있었는지를 찾기 위해서 네이버 증권의 뉴스데이터를 이용한다. news_domain = 'http://finance.naver.com/item/news_news.nhn?code='+ code news_domain_with_pageNo = 'http://finance.naver.com/item/news_news.nhn?code=' + code + '&page=' source_code = requests.get(news_domain, timeout=None) soup = BeautifulSoup(source_code.text, 'lxml') tableSoup = soup.find('table', attrs={'class', 'Nnavi'} ) td = tableSoup.find('td', attrs={'class','pgRR'}).a['href'] last_page_index = int(td[td.index('page=') + 5:]) last_page_index = 300 news_list = [] # for page in range(1,last_page_index) : for page in range(600, 900): url = news_domain_with_pageNo + str(page) source_code = requests.get(url, timeout=None) soup = BeautifulSoup(source_code.text, 'lxml') newsTabelSoup = soup.find('table', attrs={'class', 'type2'}) trSoup = newsTabelSoup.find_all('tr') i = 0 rowcount = 0; for tr in trSoup: i = i + 1 if i > 2 and i < 16: if i == 8 or i == 9: continue j = 0 dic = {} for td in tr: j = j + 1 if j == 2: strDate = str(td.span.text) # print(strDate) yyyy = int(strDate[0:4]) mm = int(strDate[5:7]) dd = int(strDate[8:10]) # 나중에 시간이 오후 3시 30분 이후에 있는건 제외를 하자. 다음날 영향 변수 hh = int(strDate[11:13]) minutes = int(strDate[14:16]) # dic['date'] = str(td.span.text) dic['date'] = datetime.date(int(yyyy), int(mm), int(dd)) if j == 4: dic['title'] = td.a.text if j == 6: dic['publish'] = td.text news_list.append(dic) return news_list def appendRelatedNewsOnDroppedDay(self, recovery, news_list): for recv in recovery: d = recv['theDay'] news_list2 = [] for news in news_list: if news.get('date') == d: # print(news['title']) news_list2.append(news['title']) recv['news_list'] = news_list2 return recovery def printResultWithNews(self, recovery): import pprint pprint.pprint(recovery) #print(recovery) # t = PrettyTable(['Date','Original Price', 'DaysToBeRecovered', 'NewsList']) # # for recv in recovery: # t.add_row([recv['theDay'], recv['yesterdayPrice'], recv['counting'], recv['news_list']]) # # print(t)