[dart api 3] 기업공시시스템 open api로 다수 기업의 매출총이익률 구하기

목차

    2018. 2. 6. 06:00

    이전 글에서 기업공시시스템의 open api를 이용하여 재무재표 정보를 가져오고, 매출총이익률을 구해 보았습니다. 오늘은 앞에서 1개의 기업에 대해 구한 방법을 함수를 통해서 모듈화하려고 합니다. 그리고 for문을 통해 다수 기업의 매출총이익률을 구해 비교하고자 합니다. 저는 전문적으로 프로그래밍을 배우진 않았기 때문에, 실제 프로그래머분들은 더 전문적인 방법들을 사용하실 거라고 생각되지만 제가 하는 방법으로 작업을 해보았습니다.

    * 기업공시시스템 open api 관련 이전 글들은 아래 링크를 참조해 주시기 바랍니다.
    (참조: 기업공시시스템 open api 사용하기기업공시시스템 open api로 매출총이익률 계산하기)


    제목



    우선 전에 작성한 코드를 함수 형태로 만들어야 합니다. 

    전체 코드를 input과 output의 개념으로 나눕니다. 그에 따라 인풋을 변수로 넣고, 아웃풋에 리턴값을 넣습니다. 코드를 나누어 놓는 게 중간에 나온 결과값을 활용하기도 좋고, 디버깅할 때도 편하더라고요.


    # coding=utf-8

    #

    # 기업 open_api 이용하기

    #


    from urllib.request import urlopen

    import pandas as pd

    from bs4 import BeautifulSoup

    import webbrowser

    from html_table_parser import parser_functions as parser


    API_KEY="(이전에 발급받은 api코드를 넣어줍니다.)"


    회사 코드를 넣으면 rcpno값을 출력해주는 부분을 함수로 만들었습니다.

    def make_report(company_code):


        url = "http://dart.fss.or.kr/api/search.xml?auth="+API_KEY+"&crp_cd="+company_code+"&start_dt=19990101&bsn_tp=A001&bsn_tp=A002&bsn_tp=A003"

        # resultXML=urlopen(url.encode("UTF-8").decode("ASCII"))

        resultXML=urlopen(url)

        result=resultXML.read()


        xmlsoup=BeautifulSoup(result,'html.parser')


        data = pd.DataFrame()


        te=xmlsoup.findAll("list")


        for t in te:

            temp=pd.DataFrame(([[t.crp_cls.string,t.crp_nm.string,t.crp_cd.string,t.rpt_nm.string,

                            t.rcp_no.string,t.flr_nm.string,t.rcp_dt.string, t.rmk.string]]),

                              columns=["crp_cls","crp_nm","crp_cd","rpt_nm","rcp_no","flr_nm","rcp_dt","rmk"])

            data=pd.concat([data,temp])



        data=data.reset_index(drop=True)

        url2="http://dart.fss.or.kr/dsaf001/main.do?rcpNo="+data['rcp_no'][0]


        # webbrowser.open(url2)


        return url2, data['rcp_no'][0]


    추천포스트


    다음으로 해당 정보를 가지고, 재무제표를 찾는 부분을 함수로 만들었습니다. 중간에 몇 개의 기업을 해 보니 매출액 부분을 수익(매출액)이라고 기록한 기업들이 있어서 이 부분을 매출액으로 바꾸는 코드를 추가하였습니다. 분기표시도 각 기업에 맞게 가져오도록 일부 내용을 수정하였습니다.

    def find_table(url2,rcpno):

        temp=urlopen(url2)

        r=temp.read()

        xmlsoup=BeautifulSoup(r,'html.parser')

        temp=xmlsoup.find_all("script",attrs={"type":"text/javascript"})

        txt=temp[7]

        a=txt.text


        b=str.find(a,"4. 재무제표")

        c=a[b:b+200]

        d=c.split(",")[4]

        e=d.replace("\"","")

        e=e.replace("\'","")

        dcmo=int(e)


        # 매출 정보 등을 가져오기


        url3="http://dart.fss.or.kr/report/viewer.do?rcpNo="+rcpno+"&dcmNo="+str(dcmo)+"&eleId=15&offset=297450&length=378975&dtd=dart3.xsd"



        # http://dart.fss.or.kr/report/viewer.do?rcpNo=20170811001153&dcmNo=5746981&eleId=15


        report=urlopen(url3)

        r=report.read()

        xmlsoup=BeautifulSoup(r,'html.parser')

        body=xmlsoup.find("body")

        table=body.find_all("table")

        p = parser.make2d(table[3])


        name_list=list()

        value_list=list()


        name_list.append("구분")



        for i in range(1,len(p[0])):

            name=p[0][i]+"_"+p[1][i]

            name=name.replace(" ","")

            name_list.append(name)

            value_list.append(name)


        sheet = pd.DataFrame(p[2:], columns=name_list)

        sheet.ix[sheet["구분"]=="수익(매출액)",["구분"]]="매출액"


        return sheet, name_list, value_list


    마지막으로 분기별 매출총이익률을 구해서, dataframe으로 리턴해 주는 함수를 만들었습니다.

    def make_profit(sheet,name_list,value_list):

        # 매출총이익률 = 매출총이익 / 매출액 * 100

        # 매출총이익 = 매출액 - 매출원가



        #숫자로 바꾸기

        for time in value_list:

            sheet[time]=sheet[time].str.replace(",","")

            sheet["temp"]=sheet[time].str[0]


            sheet.ix[sheet["temp"]=="(",time]=sheet[time].str.replace("(","-")

            sheet[time]=sheet[time].str.split(")").str[0]

            sheet.ix[sheet[time]=="",time]="0"

            sheet[time]=sheet[time].astype(int)



        temp_list=list()

        temp_list.append("매출총이익률")


        for time in range(len(value_list)):

            sale = sheet[sheet["구분"]=="매출액"].iloc[0,time+1]

            sale_cost = sheet[sheet["구분"]=="매출원가"].iloc[0,time+1]

            sale_profit_ratio=(sale-sale_cost)/sale*100

            sale_profit_ratio = round(sale_profit_ratio, 1)

            temp_list.append(sale_profit_ratio)


        output=pd.DataFrame([temp_list],columns=name_list)


        return output


    마지막으로 기업코드를 list로 만들고, for문을 돌려서 다수 기업의 매출총이익률을 한 테이블로 정리하려고 합니다. 기업마다 재무제표 상의 분기표시가 다 달라서, 일괄적으로 합치기가 어렵더라고요. (기업이 생기고 나서부터 1기, 2기, 3기 등으로 표현이 되어서, 같은 기간이라도 기업마다 기수가 다 다릅니다.) 그래도 최근 기수가 앞에 있으므로, 칼럼명을 통일해서 하나의 데이터 프레임으로 넣기로 하였습니다.


    company_list=list(["000400","004990","005930","014680","214370","271560","217270","280360"])

    company_name=list(["롯데손해보험","롯데지주","삼성전자","한솔케미칼","케어젠","오리온","넵튠","롯데제과"])


    output_last=pd.DataFrame(columns=["구분", "최근_분기", "최근_분기_누적","이전_분기","이전_분기_누적"])



    for i in range(len(company_list)):

        try:

            url2, rcpno=make_report(company_list[i])

            sheet, name_list, value_list = find_table(url2, rcpno)

            output = make_profit(sheet, name_list, value_list)


            if len(output.columns)==3:

                output.columns = ["구분", "최근_분기", "최근_분기_누적"]

            elif len(output.columns)==5:

                output.columns = ["구분", "최근_분기", "최근_분기_누적","이전_분기","이전_분기_누적"]


            output["company_code"]=company_list[i]

            output["company_name"] = company_name[i]

            output["url"] = url2


            output_last=pd.concat([output_last,output])

        except Exception as e:

            print(company_name[i]+" is error")

            print(e)


        output_last.to_csv("output_last.csv")


    마지막에 출력결과를 output_last.csv파일에 저장합니다. 실행하면 아래와 같이 실행됩니다.

    결과1

    실행결과에 대해 간략히 설명해 드리고자 합니다.

    제가 쓰는 명령어 중에 ix라는 게 있는데, 이게 곧 없어질 것이라고 경고합니다. loc, iloc을 쓰라고 하는데 ix가 편해서 없어질 때 까지는 쓰려고 생각중입니다.

    다음으로 롯데손해보험과 넵튠, 롯데제과에서 에러가 발생했다고 나오는데요. 롯데손해보험은 금융회사라 그런지 매출액 부분이 없더라고요. 넵튠도 동일하고요. 롯데제과는 분기 보고서가 없었습니다. 해당 사유로 에러가 발생한 기업들은 패스하기 위해 try~except 구문을 이용하여 예외처리를 하였습니다.

    이렇게 에러가 발생한 기업들말고는 잘 실행이 되었습니다. 


    output_last 데이터프레임을 보면 아래와 같이 값이 저장되어 있는 것을 볼 수 있습니다.

    결과2


    오리온은 작년에 기업 분할을 해서 값이 최근 것밖에 없습니다. 케어젠이라는 기업이 생명과학 쪽인데 매출총이익률이 거의 80%를 육박하네요. 업종의 특성도 있겠지만 소규모 기업인 탓도 있는 것 같습니다. 삼성전자가 38.1%로 이전 분기에 비해서 많이 상승했네요. 주가도 최근에 많이 오른 것으로 알고 있습니다. 이렇게 하나의 지표를 구하고 나니 다른 지표들도 해 보고 싶은 욕심이 나네요.


    파이썬을 이용하면 주식 관련 다양한 데이터를 크롤링할 수 있다. 배당주 데이터를 크롤링하는 방법이 궁금하다면, 아래 포스팅을 참조해보자.
    ( 참조: 파이썬으로 배당주 데이터 수집하기 )