본문 바로가기

Data Science/Data Collection

[02. 웹크롤링] 004. 38커뮤니케이션 – IPO 데이터

728x90

38커뮤니케이션은 장외주식, IPO 등 다양한 정보를 제공한다. 이 사이트를 통해서 IPO 예정인 기업들을 크롤링해보도록 하자.

 

 

 

비상장주식,장외주식시장 NO.1 38커뮤니케이션

종목명 청구일 자본금(백만) 매출액(백만) 순이익(백만) 심사청구가(원) 위더스제약 12/19 1,550 51,732 8,661 에이비온 12/18 6,917 800 -7,789 캠시스글로벌 12/18 10,001 0 0 엘에스이브이코리아 12/16 18,313 56,055 2,296 신도기연 12/12 3,361 48,854 3,189 종목명 승인일 자본금(백만) 순이익(백만) 주요제품 센코어테크 01/09 2,919 11,029 철근선조립기둥, 강구조

www.38.co.kr

 

IPO/공모 탭을 클릭해보면 승인종목, IR일정, 수요예측일정, 수요예측결과, 공모청약일정, 신규상장 등 다양한 정보들이 있다.

 

[그림 2.4] 38커뮤니케이션의 IPO관련 정보

 

승인종목 탭의 내용을 크롤링해보자. 크게 어렵지 않으므로 주석은 생략한다.

 

import requests
from bs4 import BeautifulSoup
import pandas as pd

def get_IPO_approval_data_from_38():
    fullUrl = 'http://www.38.co.kr/html/ipo/ipo.htm?key=1'
    response = requests.get(fullUrl, headers={'User-Agent': 'Mozilla/5.0'})
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')
    data = soup.find('table', {'summary': '승인종목'})

    approval_date_list = []
    company_list = []
    requisition_date_list = []
    capital_list = []
    sales_list = []
    net_income_list = []
    underwriter_list = []
    industry_list = []

    data = data.find_all('tr')[2:]
    for row in range(0, len(data)):
        data_list = data[row].text.replace('\xa0\xa0', '').split('\n')[1:-1]
        if len(data_list) < 8:
            continue

        approval_date_list.append(data_list[0].strip())
        company_list.append(data_list[1].replace('(유가)', '').strip())
        requisition_date_list.append(data_list[2].strip())
        capital_list.append(data_list[4].strip())
        sales_list.append(data_list[5].strip())
        net_income_list.append(data_list[6].strip())
        underwriter_list.append(data_list[7].strip())
        industry_list.append(data_list[8].strip())

    approval = pd.DataFrame({'approval_date': approval_date_list,
                             'company': company_list,
                             'requisition_date': requisition_date_list,
                             'capital': capital_list,
                             'sales': sales_list,
                             'net_income': net_income_list,
                             'underwriter': underwriter_list,
                             'industry': industry_list})

    return approval

if __name__ == '__main__':
    approval = get_IPO_approval_data_from_38()
    print(approval)


결과 값
   approval_date capital  ...    sales      underwriter
0     2020/01/09   2,919  ...   94,382             삼성증권
1     2020/01/09   6,900  ...  259,266            유안타증권
2     2019/12/30  32,500  ...    1,069  한국투자증권,엔에이치투자증권
3     2019/12/26  15,200  ...   31,438           미래에셋대우
4     2019/12/26   3,296  ...   40,933           미래에셋대우
5     2019/12/20      10  ...        0             신영증권
6     2019/12/13      50  ...        0             KB증권
7     2019/12/12   8,380  ...    4,854           한국투자증권
8     2019/12/12  18,081  ...  368,194             KB증권
9     2019/12/05   1,700  ...   16,549             교보증권
10    2019/11/26      21  ...        0           하나금융투자
11    2019/11/12      21  ...        0             SK증권
12    2019/11/07   4,513  ...   34,711             KB증권
13    2019/11/07     711  ...   24,046             삼성증권
14    2019/10/24       0  ...        0           미래에셋대우
15    2019/10/17   4,481  ...      891    엔에이치투자증권,삼성증권
16    2019/10/15   9,713  ...    2,527           미래에셋대우
17    2019/09/05  25,924  ...  229,357    신한금융투자,유진투자증권

 

다음으로 IR일정의 내용을 크롤링해보자. IR일정은 여러 페이지로 구성되어있다. 따라서 함수에 페이지 수를 변수로 받아 몇 번째 페이지까지 크롤링할지를 정할 수 있게 하였다.

 

import requests
from bs4 import BeautifulSoup
import pandas as pd

def get_IPO_IR_schedule_data_from_38(page=1):
    total_data = []
    for p in range(1, page + 1):
        fullUrl = 'http://www.38.co.kr/html/fund/index.htm?o=ir&page=%s' % p
        response = requests.get(fullUrl, headers={'User-Agent': 'Mozilla/5.0'})
        html = response.text
        soup = BeautifulSoup(html, 'lxml')
        data = soup.find('table', {'summary': '기업IR일정'})
        data = data.find_all('tr')[2:]
        total_data = total_data + data

    company_list = []
    ir_date_list = []
    location_list = []
    band_list = []
    underwriter_list = []

    for row in range(0, len(total_data)):
        data_list = total_data[row].text.replace('\xa0\xa0', '').replace('\t\t', '').split('\n')[1:-1]
        if len(data_list) < 5:
            continue

        company_list.append(data_list[0].replace('(유가)', '').strip())
        ir_date_list.append(data_list[1].strip())
        location_list.append(data_list[3].strip() + ' / ' + data_list[4].strip())
        band_list.append(data_list[5].strip())
        underwriter_list.append(data_list[6].strip())

    schedule = pd.DataFrame({'company': company_list,
                             'ir_date': ir_date_list,
                             'location': location_list,
                             'band': band_list,
                             'underwriter': underwriter_list})

    return schedule

if __name__ == '__main__':
    IR_schedule = get_IPO_IR_schedule_data_from_38()
    print(IR_schedule)


결과 값
             band  ...                      underwriter
0   10,000~11,200  ...                             교보증권
1   63,000~78,000  ...                           한국투자증권
2     6,000~7,000  ...                           미래에셋대우
3   10,500~13,000  ...                           한국투자증권
4   70,000~80,000  ...                        대신증권,KB증권
5   34,000~43,000  ...                             삼성증권
6   15,000~19,000  ...                            케이비증권
7   11,000~14,500  ...                           한국투자증권
8     3,700~4,500  ...                아이비케이투자증권,BNK투자증권
9   14,500~16,500  ...                           한국투자증권
10  24,000~27,200  ...               NH투자증권,신한금융투자,삼성증권
11    5,000~5,000  ...        NH투자증권,키움증권,하나금융투자,한국투자증권
12  17,000~20,000  ...                             대신증권
13    5,000~6,000  ...                   한국투자증권,BNK투자증권
14    3,800~4,200  ...                           미래에셋대우
15  16,000~20,000  ...                        키움증권,삼성증권
16  24,000~28,000  ...  한국투자증권,하나금융투자,KB증권,하이투자증권,유안타증권
17    7,400~8,400  ...                           한국투자증권
18   8,000~10,000  ...                             신영증권
19  36,000~48,000  ...                    한국투자증권,DB금융투자

 

수요예측일정의 내용을 크롤링해보자. 이 탭도 여러 페이지로 구성되어있다. 따라서 함수에 페이지 수를 변수로 받아 몇 번째 페이지까지 크롤링할지를 정할 수 있게 하였다.

 

import requests
from bs4 import BeautifulSoup
import pandas as pd

def get_IPO_demand_schedule_data_from_38(page=1):
    total_data = []
    for p in range(1, page + 1):
        fullUrl = 'http://www.38.co.kr/html/fund/index.htm?o=r&page=%s' % p
        response = requests.get(fullUrl, headers={'User-Agent': 'Mozilla/5.0'})
        html = response.text
        soup = BeautifulSoup(html, 'lxml')
        data = soup.find('table', {'summary': '수요예측일정'})
        data = data.find_all('tr')[2:]
        total_data = total_data + data

    company_list = []
    demand_date_list = []
    band_list = []
    price_list = []
    ipo_amount_list = []
    underwriter_list = []
    link_list = []

    for row in range(0, len(total_data)):
        data_list = total_data[row].text.replace('\xa0', '').replace('\t\t', '').split('\n')[1:-1]

        if len(data_list) < 6:
            continue

        company_list.append(data_list[0].replace('(유가)', '').strip())
        demand_date_list.append(data_list[1].strip())
        band_list.append(data_list[2].strip())
        price_list.append(data_list[3].strip())
        ipo_amount_list.append(data_list[4].strip())
        underwriter_list.append(data_list[5].strip())
        link_list.append('http://www.38.co.kr/html/fund/' +
                         str(total_data[row].find('a')).replace('amp;', '').split('href=".')[1].split('=&')[0])

    schedule = pd.DataFrame({'company': company_list,
                             'demand_date': demand_date_list,
                             'band': band_list,
                             'price': price_list,
                             'ipo_amount': ipo_amount_list,
                             'underwriter': underwriter_list,
                             'link': link_list})

    return schedule

if __name__ == '__main__':
    demand_schedule = get_IPO_demand_schedule_data_from_38()
    print(demand_schedule)


결과 값
             band      company  ...   price        underwriter
0     2,700~3,100           서남  ...       -             한국투자증권
1     2,000~2,000       신영스팩6호  ...       -               신영증권
2   10,000~11,200        위세아이텍  ...       -               교보증권
3     2,000~2,000     케이비스팩20호  ...       -               KB증권
4     2,000~2,000    하나금융스팩15호  ...       -             하나금융투자
5   63,000~78,000           천랩  ...  40,000             한국투자증권
6     2,000~2,000    한화플러스스팩1호  ...   2,000             한화투자증권
7     6,000~7,000         피피아이  ...   7,000             미래에셋대우
8   70,000~80,000  브릿지바이오테라퓨틱스  ...  60,000          대신증권,KB증권
9     2,000~2,000    엔에이치스팩15호  ...   2,000             NH투자증권
10  10,500~13,000        메탈라이프  ...  13,000             한국투자증권
11  34,000~43,000         메드팩토  ...  40,000               삼성증권
12    2,000~2,000       하이스팩5호  ...   2,000             하이투자증권
13    2,000~2,000    대신밸런스스팩8호  ...   2,000               대신증권
14    2,000~2,000      유안타스팩6호  ...   2,000              유안타증권
15  15,000~19,000       신테카바이오  ...  12,000              케이비증권
16  11,000~14,500    제이엘케이인스펙션  ...   9,000             한국투자증권
17    2,000~2,000    IBKS스팩12호  ...   2,000          아이비케이투자증권
18    3,700~4,500        태웅로직스  ...   4,500  아이비케이투자증권,BNK투자증권
19    2,000~2,000     에스케이스팩5호  ...   2,000               SK증권

 

수요예측결과의 내용을 크롤링해보자. 이 탭도 여러 페이지로 구성되어있다. 따라서 함수에 페이지 수를 변수로 받아 몇 번째 페이지까지 크롤링할지를 정할 수 있게 하였다.

 

import requests
from bs4 import BeautifulSoup
import pandas as pd

def get_IPO_demand_result_data_from_38(page=1):
    total_data = []
    for p in range(1, page + 1):
        fullUrl = 'http://www.38.co.kr/html/fund/index.htm?o=r1&page=%s' % p
        response = requests.get(fullUrl, headers={'User-Agent': 'Mozilla/5.0'})
        html = response.text
        soup = BeautifulSoup(html, 'lxml')
        data = soup.find('table', {'summary': '수요예측결과'})
        data = data.find_all('tr')[2:]
        total_data = total_data + data

    company_list = []
    demand_date_list = []
    band_list = []
    price_list = []
    ipo_amount_list = []
    competition_rate_list = []
    commitment_list = []
    underwriter_list = []

    for row in range(0, len(total_data)):
        data_list = total_data[row].text.replace('\xa0', '').replace('\t\t', '').split('\n')[1:-1]
        if len(data_list) < 8:
            continue

        company_list.append(data_list[0].replace('(유가)', '').strip())
        demand_date_list.append(data_list[1].strip())
        band_list.append(data_list[2].strip())
        price_list.append(data_list[3].strip())
        ipo_amount_list.append(data_list[4].strip())
        competition_rate_list.append(data_list[5].strip())
        commitment_list.append(data_list[6].strip())
        underwriter_list.append(data_list[7].strip())

    result = pd.DataFrame({'company': company_list,
                           'demand_date': demand_date_list,
                           'band': band_list,
                           'price': price_list,
                           'ipo_amount': ipo_amount_list,
                           'competition_rate': competition_rate_list,
                           'commitment': commitment_list,
                           'underwriter': underwriter_list})

    return result

if __name__ == '__main__':
    demand_result = get_IPO_demand_result_data_from_38()
    print(demand_result)


결과 값
             band commitment  ...   price                underwriter
0   63,000~78,000          -  ...  40,000                     한국투자증권
1     2,000~2,000          -  ...   2,000                     한화투자증권
2     6,000~7,000      2.47%  ...   7,000                     미래에셋대우
3   70,000~80,000      0.06%  ...  60,000                  대신증권,KB증권
4     2,000~2,000          -  ...   2,000                     NH투자증권
5   10,500~13,000     22.46%  ...  13,000                     한국투자증권
6   34,000~43,000     13.83%  ...  40,000                       삼성증권
7     2,000~2,000          -  ...   2,000                     하이투자증권
8     2,000~2,000          -  ...   2,000                       대신증권
9     2,000~2,000          -  ...   2,000                      유안타증권
10  15,000~19,000      1.32%  ...  12,000                      케이비증권
11  11,000~14,500          -  ...   9,000                     한국투자증권
12    2,000~2,000          -  ...   2,000                  아이비케이투자증권
13    3,700~4,500      2.53%  ...   4,500          아이비케이투자증권,BNK투자증권
14    2,000~2,000          -  ...   2,000                       SK증권
15  14,500~16,500          -  ...  13,000                     한국투자증권
16  24,000~27,200      6.04%  ...  18,000         NH투자증권,신한금융투자,삼성증권
17    2,000~2,000          -  ...   2,000                  아이비케이투자증권
18    2,000~2,000          -  ...   2,000                      유안타증권
19    5,000~5,000     43.20%  ...   5,000  NH투자증권,키움증권,하나금융투자,한국투자증권

 

다음으로 공모청약일정의 내용을 크롤링해보자. 이 탭도 여러 페이지로 구성되어있다. 따라서 함수에 페이지 수를 변수로 받아 몇 번째 페이지까지 크롤링할지를 정할 수 있게 하였다.

 

import requests
from bs4 import BeautifulSoup
import pandas as pd

def get_IPO_public_schedule_data_from_38(page=1):
    total_data = []
    for p in range(1, page + 1):
        fullUrl = 'http://www.38.co.kr/html/fund/index.htm?o=k&page=%s' % p
        response = requests.get(fullUrl, headers={'User-Agent': 'Mozilla/5.0'})
        html = response.text
        soup = BeautifulSoup(html, 'lxml')
        data = soup.find('table', {'summary': '공모주 청약일정'})
        data = data.find_all('tr')[2:]
        total_data = total_data + data

    company_list = []
    public_date_list = []
    price_list = []
    band_list = []
    competition_rate_list = []
    underwriter_list = []

    for row in range(0, len(total_data)):
        data_list = total_data[row].text.replace('\xa0', '').replace('\t\t', '').split('\n')[1:-1]
        if len(data_list) < 6:
            continue

        company_list.append(data_list[0].replace('(유가)', '').strip())
        public_date_list.append(data_list[1].strip())
        price_list.append(data_list[2].strip())
        band_list.append(data_list[3].strip())
        competition_rate_list.append(data_list[4].strip())
        underwriter_list.append(data_list[5].strip())

    schedule = pd.DataFrame({'company': company_list,
                             'public_date': public_date_list,
                             'price': price_list,
                             'band': band_list,
                             'competition_rate': competition_rate_list,
                             'underwriter': underwriter_list})

    return schedule

if __name__ == '__main__':
    public_schedule = get_IPO_public_schedule_data_from_38()
    print(public_schedule)


결과 값
             band      company  ...       public_date                underwriter
0     2,700~3,100           서남  ...  2020.02.10~02.11                     한국투자증권
1     2,000~2,000       신영스팩6호  ...  2020.02.03~02.04                       신영증권
2   10,000~11,200        위세아이텍  ...  2020.01.29~01.30                       교보증권
3     2,000~2,000    하나금융스팩15호  ...  2020.01.16~01.17                     하나금융투자
4     2,000~2,000     케이비스팩20호  ...  2020.01.16~01.17                       KB증권
5   63,000~78,000           천랩  ...  2019.12.17~12.18                     한국투자증권
6     6,000~7,000         피피아이  ...  2019.12.16~12.17                     미래에셋대우
7     2,000~2,000    한화플러스스팩1호  ...  2019.12.16~12.17                     한화투자증권
8   70,000~80,000  브릿지바이오테라퓨틱스  ...  2019.12.12~12.13                  대신증권,KB증권
9     2,000~2,000    엔에이치스팩15호  ...  2019.12.12~12.13                     NH투자증권
10  10,500~13,000        메탈라이프  ...  2019.12.12~12.13                     한국투자증권
11    2,000~2,000       하이스팩5호  ...  2019.12.11~12.12                     하이투자증권
12  34,000~43,000         메드팩토  ...  2019.12.10~12.11                       삼성증권
13  15,000~19,000       신테카바이오  ...  2019.12.09~12.10                      케이비증권
14    2,000~2,000    대신밸런스스팩8호  ...  2019.12.09~12.10                       대신증권
15    2,000~2,000      유안타스팩6호  ...  2019.12.09~12.10                      유안타증권
16  11,000~14,500    제이엘케이인스펙션  ...  2019.12.02~12.03                     한국투자증권
17    2,000~2,000    IBKS스팩12호  ...  2019.11.28~11.29                  아이비케이투자증권
18    3,700~4,500        태웅로직스  ...  2019.11.26~11.27          아이비케이투자증권,BNK투자증권
19    2,000~2,000     에스케이스팩5호  ...  2019.11.25~11.26                       SK증권
20  14,500~16,500          리메드  ...  2019.11.25~11.26                     한국투자증권
21  24,000~27,200        코리아센터  ...  2019.11.21~11.22         NH투자증권,신한금융투자,삼성증권
22    2,000~2,000    IBKS스팩11호  ...  2019.11.21~11.22                  아이비케이투자증권
23    2,000~2,000      유안타스팩5호  ...  2019.11.18~11.19                      유안타증권
24    5,000~5,000    엔에이치프라임리츠  ...  2019.11.18~11.20  NH투자증권,키움증권,하나금융투자,한국투자증권

 

마지막으로 신규상장 탭의 내용을 크롤링해보자. 이 탭도 여러 페이지로 구성되어있다. 따라서 함수에 페이지 수를 변수로 받아 몇 번째 페이지까지 크롤링할지를 정할 수 있게 하였다.

 

import requests
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np

def get_IPO_list_performance_data_from_38(page=1):
    total_data = []
    for p in range(1, page + 1):
        fullUrl = 'http://www.38.co.kr/html/fund/index.htm?o=nw&page=%s' % p
        response = requests.get(fullUrl, headers={'User-Agent': 'Mozilla/5.0'})
        html = response.text
        soup = BeautifulSoup(html, 'lxml')
        data = soup.find('table', {'summary': '신규상장종목'})
        data = data.find_all('tr')[2:]
        total_data = total_data + data

    company_list = []
    list_date_list = []
    price_list = []
    open_price_list = []
    close_price_list = []

    for row in range(0, len(total_data)):
        data_list = total_data[row].text.replace('\xa0', '').replace('\t\t', '').split('\n')[1:-1]
        if len(data_list) < 9:
            continue

        company_list.append(data_list[0].replace('(유가)', '').strip())
        list_date_list.append(data_list[1].strip())
        price_list.append(data_list[4].strip())
        open_price_list.append(data_list[6].strip())
        close_price_list.append(data_list[8].strip())

    list_performance = pd.DataFrame({'company': company_list,
                                     'list_date': list_date_list,
                                     'price': price_list,
                                     'open_price': open_price_list,
                                     'close_price': close_price_list})

    list_performance['open_price'] = list_performance['open_price'].replace('-', np.nan)
    list_performance['return_open'] = list_performance['open_price'].str.replace(',', '').replace('-', 0).astype(float) / list_performance['price'].str.replace(',', '').replace('-', 0).astype(float) - 1
    list_performance['close_price'] = list_performance['close_price'].replace('-', np.nan)
    list_performance['return_close'] = list_performance['close_price'].str.replace(',', '').replace('예정', 0).replace('-', 0).astype(float) / list_performance['price'].str.replace(',', '').replace('-', 0).astype(float) - 1

    return list_performance

if __name__ == '__main__':
    list_performance = get_IPO_list_performance_data_from_38()
    print(list_performance)


결과 값
       close_price      company   list_date  ...   price return_open  return_close
0           예정        위세아이텍  2020/02/10  ...       -         NaN           NaN
1           예정    하나금융스팩15호  2020/01/30  ...       -         NaN           NaN
2           예정     케이비스팩20호  2020/01/30  ...       -         NaN           NaN
3        2,000    한화플러스스팩1호  2019/12/27  ...   2,000    0.002500      0.000000
4        9,630         피피아이  2019/12/26  ...   7,000    0.571429      0.375714
5       38,500           천랩  2019/12/26  ...  40,000    0.073750     -0.037500
6        2,000    엔에이치스팩15호  2019/12/24  ...   2,000    0.000000      0.000000
7       33,800        메탈라이프  2019/12/24  ...  13,000    1.000000      1.600000
8        2,005       하이스팩5호  2019/12/23  ...   2,000    0.000000      0.002500
9       54,300  브릿지바이오테라퓨틱스  2019/12/20  ...  60,000    0.040000     -0.095000
10      35,900         메드팩토  2019/12/19  ...  40,000    0.000000     -0.102500
11       2,005    대신밸런스스팩8호  2019/12/19  ...   2,000    0.002500      0.002500
12       2,000      유안타스팩6호  2019/12/19  ...   2,000    0.002500      0.000000
13      16,700       신테카바이오  2019/12/17  ...  12,000    0.245833      0.391667
14       9,000    제이엘케이인스펙션  2019/12/11  ...   9,000   -0.055556      0.000000
15       6,110        태웅로직스  2019/12/10  ...   4,500    0.815556      0.357778
16       2,050    IBKS스팩12호  2019/12/09  ...   2,000    0.020000      0.025000
17      13,450          리메드  2019/12/06  ...  13,000    0.084615      0.034615
18       2,010     에스케이스팩5호  2019/12/05  ...   2,000    0.005000      0.005000
19       6,500    엔에이치프라임리츠  2019/12/05  ...   5,000    0.000000      0.300000
728x90