저번 글 이후, 두 달이 넘어서 다시 공모주 알리미 개발 포스팅을 하게 됐다.
개발은 열심히 해서 약 30명에게 서비스 중이다. 개발할 때 그때그때 글을 썼으면 더 좋았으련만.ㅎㅎ
글 쓰는데 시간이 오래 걸리는 탓도 있고, 게으른것도 조금 있고.. 그래서 어느 정도 구현이 된 상황에서 글을 다시 쓰려고 한다.
저번 글 회고와 같이, 확장성 면에서 매우 좋지 않은 코드를 짰기 때문에 다시 작성하였다.
2달 전과 비교해서 전체적으로 리팩토링을 하여서,
클래스 전체 구조를 적기엔 너무 길 것 같아 여러 메서드들을 풀어서 그냥 쓰려고 한다.
<공모 청약일정 url 가져오기 : 청약 마감, 청약 시작, 청약 하루 전 순서로 저장>
아래 더보기는 소스코드이다.
import requests
from enum import IntEnum
from datetime import datetime
from bs4 import BeautifulSoup
def check_bidding_status(date_diff_bidding_start, date_diff_bidding_finish):
if date_diff_bidding_finish > 0:
return BiddingStatus.ALREADY_FINISHED
elif date_diff_bidding_start == -1:
return BiddingStatus.START_TOMORROW
elif date_diff_bidding_start == 0:
return BiddingStatus.START_TODAY
elif date_diff_bidding_start >= 1:
if date_diff_bidding_finish == 0:
return BiddingStatus.FINISH_TODAY
else:
return BiddingStatus.PROCEEDING
else:
return BiddingStatus.START_MORE_THAN_TWO_DAY_AFTER
class BiddingStatus(IntEnum):
FINISH_TODAY = 0
START_TODAY = 1
START_TOMORROW = 2
START_MORE_THAN_TWO_DAY_AFTER = 3
PROCEEDING = 1
ALREADY_FINISHED = 5
class BiddingUrlList:
def __init__(self):
self.start_tomorrow = []
self.start_today = []
self.finish_today = []
def __getitem__(self, index):
if index == BiddingStatus.START_TOMORROW:
return self.start_tomorrow
elif index == BiddingStatus.START_TODAY:
return self.start_today
elif index == BiddingStatus.PROCEEDING: # REITs Exception(REITS bidding for 3 days)
return self.start_today
elif index == BiddingStatus.FINISH_TODAY:
return self.finish_today
def parsing_html(url):
response = requests.get(url)
html = response.content.decode('euc-kr', 'replace')
return BeautifulSoup(html, 'lxml')
def get_company_tr_list(data_type, soup):
if data_type == 'bid':
company_tr_list = soup.find('table', {'summary': '공모주 청약일정'})
else:
company_tr_list = soup.find('table', {'summary': '신규상장종목'})
company_tr_list = company_tr_list.find('tbody').find_all('tr')
return company_tr_list
def convert_bidding_td_to_datetime(td, time):
temp_date_list = td.text.strip().replace(' ', '').split('~')
year = temp_date_list[0][:4]
if time == 'start':
return datetime.strptime(temp_date_list[0], "%Y.%m.%d")
elif time == 'finish':
return datetime.strptime(str(year) + '.' + temp_date_list[1], "%Y.%m.%d")
def get_bidding_url_list(target_date: datetime):
base_bidding_url = 'http://www.38.co.kr/html/fund/index.htm?o=k'
bidding_url_list = BiddingUrlList()
soup = parsing_html(base_bidding_url)
company_tr_list = get_company_tr_list('bid', soup)
for idx in range(-1, -len(company_tr_list) - 1, -1):
company_td_list = company_tr_list[idx].find_all('td')
company_a_tag = company_td_list[0].select('a')
company_href = company_a_tag[0].get('href')
bidding_start = convert_bidding_td_to_datetime(company_td_list[1], 'start')
bidding_finish = convert_bidding_td_to_datetime(company_td_list[1], 'finish')
date_diff_bidding_start = (target_date - bidding_start).days
date_diff_bidding_finish = (target_date - bidding_finish).days
result_url = 'http://www.38.co.kr' + company_href
bidding_status = check_bidding_status(date_diff_bidding_start, date_diff_bidding_finish)
if bidding_status == BiddingStatus.ALREADY_FINISHED:
continue
elif bidding_status == BiddingStatus.START_MORE_THAN_TWO_DAY_AFTER:
break
else:
bidding_url_list[bidding_status].append(result_url)
return bidding_url_list
공모 청약일정은, http://www.38.co.kr/html/fund/index.htm?o=k에서 가져올 수 있다.
공모주일정 - 공모청약일정, 공모주청약, 공모주분석, 기업공개, 상장, 공모일정, 공모주청약일
전체종목 청구종목 승인종목 기업IR일정 수요예측일정 수요예측결과 공모청약일정 신규상장 종목명 공모주일정 확정공모가 희망공모가 청약경쟁률 주간사 분석 하나금융
www.38.co.kr
가져올 정보는 청약 마감, 청약 시작, 청약 하루 전 종목들이며, target_date를 기준으로 정한다.
check_bidding_status 메서드에서,
- 청약 시작일 까지와의 차(date_diff_bidding_start)
- 청약 마감일 까지와의 차(date_diff_bidding_finish)
두 가지 parameter를 통해 얻고자 하는 데이터를 선별해낼 수 있다.
(리츠 종목의 경우 청약일이 3일이기 때문에, 이틀 차도 청약 시작 종목에 포함시켰다.)
이미 청약 마감된 종목(ALREADY_FINISHED), 아직 청약 시작까지 이틀 이상 남은 종목(START_MORE_THAN_TWO_DAY_AFTER)들도 혹시 언젠가 사용할 수 있을 것 같아서, 일단은 정의해두었다.
사소하지만 페이지 내에서 내가 원하는 조건 내 데이터는 적고, 이미 청약 마감했거나 청약까지 이틀 이상 남은 종목들이 더 많기 때문에 조건문 상단에 위치시켰다.
페이지 가장 아래에서부터 크롤링하기 때문에,
- 이미 청약이 마감된 종목을 만났을 시 넘기며
- 아직 청약 시작까지 이틀 이상 남은 종목을 만나면, 반복문을 종료한다.
- 이 두 조건문 사이(else)에 있는 종목들은 청약 마감, 청약 시작, 청약 하루 전 종목들이기 때문에 해당되는 index에 맞게 저장해준다.
<신규상장일정 url 가져오기 : 상장 당일, 상장 하루전 순서로 저장>
아래 더보기는 소스코드이다.
import requests
from enum import IntEnum
from datetime import datetime
from bs4 import BeautifulSoup
def check_ipo_status(date_diff_ipo_start):
if date_diff_ipo_start > 0:
return IpoStatus.ALREADY_FINISHED
elif date_diff_ipo_start == 0:
return IpoStatus.START_TODAY
elif date_diff_ipo_start == -1:
return IpoStatus.START_TOMORROW
else:
return IpoStatus.START_MORE_THAN_TWO_DAY_AFTER
class IpoStatus(IntEnum):
START_TODAY = 0
START_TOMORROW = 1
ALREADY_FINISHED = 2
START_MORE_THAN_TWO_DAY_AFTER = 3
class IpoUrlList:
def __init__(self):
self.start_tomorrow = []
self.start_today = []
def __getitem__(self, index):
if index == IpoStatus.START_TOMORROW:
return self.start_tomorrow
elif index == IpoStatus.START_TODAY:
return self.start_today
def parsing_html(url):
response = requests.get(url)
html = response.content.decode('euc-kr', 'replace')
return BeautifulSoup(html, 'lxml')
def get_company_tr_list(data_type, soup):
if data_type == 'bid':
company_tr_list = soup.find('table', {'summary': '공모주 청약일정'})
else:
company_tr_list = soup.find('table', {'summary': '신규상장종목'})
company_tr_list = company_tr_list.find('tbody').find_all('tr')
return company_tr_list
def convert_ipo_td_to_datetime(td):
temp_datetime = td.text.strip().replace(' ', '')
return datetime.strptime(temp_datetime, "%Y/%m/%d")
def get_ipo_url_list(target_date: datetime):
base_ipo_url = 'http://www.38.co.kr/html/fund/index.htm?o=nw'
ipo_url_list = IpoUrlList()
soup = parsing_html(base_ipo_url)
company_tr_list = get_company_tr_list('ipo', soup)
for idx in range(-1, -len(company_tr_list) - 1, -1):
company_td_list = company_tr_list[idx].find_all('td')
company_a_tag = company_td_list[0].select('a')
company_href = company_a_tag[0].get('href')
ipo_start_date = convert_ipo_td_to_datetime(company_td_list[1])
date_diff_ipo_start = (target_date - ipo_start_date).days
result_url = 'http://www.38.co.kr' + '/html/fund' + company_href[1:]
ipo_status = check_ipo_status(date_diff_ipo_start)
if ipo_status == IpoStatus.ALREADY_FINISHED:
continue
elif ipo_status == IpoStatus.START_MORE_THAN_TWO_DAY_AFTER:
break
else:
ipo_url_list[ipo_status].append(result_url)
신규상장일정은, http://www.38.co.kr/html/fund/index.htm?o=nw 에서 가져올 수 있다.
공모주일정 - 신규상장, 공모주청약, 공모주분석, 기업공개, 상장, 공모일정, 공모주청약일정,
전체종목 청구종목 승인종목 기업IR일정 수요예측일정 수요예측결과 공모청약일정 신규상장 기업명 신규상장일 현재가(원) 전일비(%) 공모가(원) 공모가대비등락률(%) 시초
www.38.co.kr
가져올 정보는 상장 당일, 상장 하루 전 종목들이며, target_date를 기준으로 정한다.
check_bidding_status 메서드에서,
- 상장일 까지와의 차(date_diff_bidding_start) parameter를 통해 얻고자 하는 데이터를 선별해낼 수 있다.
이미 상장된 종목(ALREADY_FINISHED), 아직 상장까지 이틀 이상 남은 종목(START_MORE_THAN_TWO_DAY_AFTER)들도 혹시 언젠가 사용할 수 있을 것 같아서, 일단은 정의해두었다.
마찬가지로,
사소하지만 페이지 내에서 내가 원하는 조건 내 데이터는 적고, 이미 상장했거나 상장까지 이틀 이상 남은 종목들이 더 많기 때문에 조건문 상단에 위치시켰다.
페이지 가장 아래에서부터 크롤링하기 때문에,
- 이미 상장된 종목을 만났을 시 넘기며
- 아직 상장 시작까지 이틀 이상 남은 종목을 만나면, 반복문을 종료한다.
- 이 두 조건문 사이(else)에 있는 종목들은 상장 당일, 상장 하루 전 종목들이기 때문에 해당되는 index에 맞게 저장해준다.
'Side Projects > 공모주 알리미' 카테고리의 다른 글
[공모주 알리미 개발] 2-4. 38커뮤니케이션 크롤링 : 기업 개요, 공모 정보, 청약 일정 가져오기 (0) | 2021.11.23 |
---|---|
[공모주 알리미 개발] 2-3. 38커뮤니케이션 크롤링 : 종목별 url 추출하기 (0) | 2021.09.09 |
[공모주 알리미 개발] 2-2. ipostock 크롤링 : 주주구성, 공모정보, 수요예측 정보 가져오기 (0) | 2021.09.06 |
[공모주 알리미 개발] 2-1. ipostock 크롤링 : 종목별 url 추출하기 (0) | 2021.08.30 |
[공모주 알리미 개발] 1. 개요 (3) | 2021.08.26 |