/ PROJECT

나라장터-수집(1)-OPENAPI

나라장터 낙찰가를 예측하고 자동으로 입찰내용 메일 보내기

나라장터-수집(1)-OPENAPI

나라장터에의 낙찰하는 분석을 하게 되는 상황이 생겼는데 통계, 컴공으로서 근거 없는 찍는 것을 믿지 못하고 찍신이 아닌 나 자신을 믿을 수가 없었다. 따라서 이때다 싶어 나라장터 분석 및 예측을 해보기로 했다.

공공데이터포털 OPENAPI 활용신청

  • 활용신청 : 안에 내용은 본인의 의도에 맞게 적어 제출하면 등록이 되어 사용가능하다.(바로 사용이 안되면 어느정도 기다렸다가 하면된다.) 다른 데이터는 기관에서 인증을 해주고 나서 해주는 경우도 있다.

  • 참고문서 : open API 사용법 및 입출력 코드와 설명

OPENAPI URL 만들기

EndPoint = "http://apis.data.go.kr/1230000/PubDataOpnStdService"

ServiceKey ="" # 공공데이터포털에서 받은 인코딩 인증키

PageNo = 1 # 페이지번호
NumOfRows = 100 # 한 페이지 결과 수
Datatype = "json" # 오픈API 리턴 타입을 JSON으로 받고 싶을 경우 'json' 으로 지정함
bidNtceBgnDt = 202207240000 # 검색하고자하는 입찰공고일시범위 시작 'YYYYMMDDHHMM' (입찰공고일시 범위는 1개월 로 제한)
bidNtceEndDt = 202207312359 # 검색하고자하는 입찰공고일시범위 종료 'YYYYMMDDHHMM' (입찰공고일시 범위는 1개월 로 제한)

def Info_Version(info_version) : # 데이터셋 개방표준에 따른 입찰공고정보
    if info_version == "입찰":
        return "getDataSetOpnStdBidPblancInfo"
    elif info_version == "낙찰":
        return "getDataSetOpnStdScsbidInfo"
    else : # 계약
        return "getDataSetOpnStdCntrctInfo"    
  • 테스트 : 결과물로 나오는 URL을 클릭하면 json 파일이 열린다.
info_version = "입찰"
URL = f"{EndPoint}/{Info_Version(info_version)}?numOfRows={NumOfRows}&pageNo={PageNo}&bidNtceBgnDt={bidNtceBgnDt}&bidNtceEndDt={bidNtceEndDt}&ServiceKey={ServiceKey}&type={Datatype}"

데이터 수집 코드

  • 본 블로그는 투찰가능업종명 : 산림사업법인(숲가꾸기 및 병해충방제), 산림사업법인(도시숲등 조성, 관리) 관련으로 분석 및 예측한다.
import requests
import pandas as pd
import datetime   
    
def Get_Bid_df(info_version, bidNtceBgnDt, bidNtceEndDt, ServiceKey): # 원하는 기간, 버전에 따른 공고정보 얻기
    
    # default setting
    PageNo = 1 # 페이지번호
    NumOfRows = 999 # 한 페이지 결과 수 , 최대 999개 이다.
    EndPoint = "http://apis.data.go.kr/1230000/PubDataOpnStdService"
    Datatype = "json" # 오픈API 리턴 타입을 JSON으로 받고 싶을 경우 'json' 으로 지정함
    
    if info_version == "입찰": # 데이터셋 개방표준에 따른 입찰공고정보
        info_version_text = "getDataSetOpnStdBidPblancInfo"
    elif info_version == "낙찰":
        info_version_text = "getDataSetOpnStdScsbidInfo"
    else : # 계약
        info_version_text = "getDataSetOpnStdCntrctInfo"
    
    
    Bid_df =pd.DataFrame()
    nnn = 0
    while True:
        URL = f"{EndPoint}/{info_version_text}?numOfRows={NumOfRows}&pageNo={PageNo}&bidNtceBgnDt={bidNtceBgnDt}&bidNtceEndDt={bidNtceEndDt}&ServiceKey={ServiceKey}&type={Datatype}"
        response = requests.get(URL)
        
        # 총 데이터 개수
        TotalCount = response.json()["response"]["body"]["totalCount"]

        # 나라장터 입찰공고 DataFrame 생성
        bid_df = pd.DataFrame(response.json()["response"]["body"]["items"])
        
        # 읽은 데이터의 개수를 확인해서 데이터의 끝인지 확인
        if len(bid_df) == 0 : break
        
        # 목적에 필요한 열을 가져온다. 다운받은 참고문헌을 참조한다.
        # 본인의 목적에 따라 수정해야할 부분
        bid_df = bid_df.loc[:,["bidNtceNm","bidBeginDate","bidBeginTm","bidClseDate","bidClseTm","opengDate","opengTm","asignBdgtAmt","presmptPrce","rgnLmtYn","prtcptPsblRgnNm","bidprcPsblIndstrytyNm"]]
        bid_df = bid_df.rename( columns  = {"bidNtceNm":"입찰공고명","bidBeginDate":"입찰개시일자","bidBeginTm":"입찰개시시각","bidClseDate":"입찰마감일자","bidClseTm":"입찰마감시각","opengDate":"개찰일자","opengTm":"개찰시각","asignBdgtAmt":"배정예산금액(설계금액)","presmptPrce":"추정가격","rgnLmtYn":"지역제한여부","prtcptPsblRgnNm":"참가가능지역명","bidprcPsblIndstrytyNm":"투찰가능업종명"})

        # 데이터 프레임 병합
        Bid_df = pd.concat([Bid_df,bid_df],axis=0)
        Bid_df.reset_index(drop=True,inplace=True)

        # 페이지 증가
        PageNo=str(int(PageNo)+1)
    
    print("----------------------------------")
    print(f"{info_version} \n{str(bidNtceBgnDt)[:4]}{str(bidNtceBgnDt)[4:6]}{str(bidNtceBgnDt)[6:8]}일 - {str(bidNtceEndDt)[:4]}{str(bidNtceEndDt)[4:6]}{str(bidNtceEndDt)[6:8]}일")
    print("----------------------------------")
    
    return Bid_df
ServiceKey ="" # 공공데이터포털에서 받은 인코딩 인증키
bidNtceBgnDt = 202207260000 # 검색하고자하는 입찰공고일시범위 시작 'YYYYMMDDHHMM' (입찰공고일시 범위는 1개월 로 제한)
bidNtceEndDt = 202207312359 # 검색하고자하는 입찰공고일시범위 종료 'YYYYMMDDHHMM' (입찰공고일시 범위는 1개월 로 제한)
info_version = "입찰"

Bid_df = Get_Bid_df(info_version, bidNtceBgnDt, bidNtceEndDt, ServiceKey)
display(Bid_df.head())

Savefile_path = "./2022-07-25-나라장터-수집(1)-OPENAPI" # 저장할 파일 경로
Bid_df.to_csv(f"{Savefile_path}/{info_version}_{bidNtceBgnDt}_{bidNtceEndDt}.csv",index=False, encoding="cp949") # 인덱스를 없애고 저장한다.


입찰공고 확인_v2

  • 매일 본인의 목적에 필요한 공고만 확인하기 위한 필터

  • 투찰가능업종명, 기간, 참가가능지역, 지역제한 을 기준으로 적용

    • 투찰가능업종명 : “산림사업법인(숲가꾸기 및 병해충방제)”, “산림사업법인(도시숲등 조성, 관리)”
    • 참가가능지역명 : “고흥”, “보성”, “장흥”, “여수”, “순천”
    • 기간 : 프로그램 실행시에 입찰 가능한 공고가 있을 시, 크롤링 기간은 29일 전까지의 기간으로 한다.
# 기간 : 프로그램 실행시에 입찰 가능한 공고가 있을 시,YYYYMMDDHHMM 형식으로 변환
bidNtceBgnDt = datetime.datetime.now()-datetime.timedelta(days=3)
bidNtceBgnDt = int(bidNtceBgnDt.strftime("%Y%m%d%H%M")) # 검색하고자하는 입찰공고일시범위 시작 'YYYYMMDDHHMM' (입찰공고일시 범위는 1개월 로 제한)
bidNtceEndDt = int(datetime.datetime.now().strftime("%Y%m%d%H%M")) # 검색하고자하는 입찰공고일시범위 종료 'YYYYMMDDHHMM' (입찰공고일시 범위는 1개월 로 제한)

info_version = "입찰"

Bid_df = Get_Bid_df(info_version, bidNtceBgnDt, bidNtceEndDt, ServiceKey)
----------------------------------
입찰 
2022년 08월 01일 - 2022년 08월 04일
----------------------------------
# 투찰가능업종명 : ["산림사업법인(숲가꾸기 및 병해충방제)", "산림사업법인(도시숲등 조성, 관리)"]
Active_name = ["산림사업법인(숲가꾸기 및 병해충방제)", "산림사업법인(도시숲등 조성, 관리)"]

# 참가가능지역명 : 고흥
Active_local = ["고흥""순천"]

def Filter(Bid_df, bidNtceEndDt, Active_name, Active_local):
    # Active_date_list : 입찰 마감 기간에 프로그램 실행 후에 있는지 확인 "입찰마감일자", "입찰마감시각"
    Active_date_list = []
    for i in range(len(Bid_df)):
        Active_date_list.append(Bid_df.loc[i,"입찰마감일자"].replace("-","")+Bid_df.loc[i,"입찰마감시각"].replace(":","")>=str(bidNtceEndDt))
    Bid_df = Bid_df.loc[Active_date_list,:].reset_index(drop=True)
            
    # Active_name : 투찰가능업종명 제한
    Active_name_list = []

    for Check_name in Bid_df["투찰가능업종명"]:
        if [1 for x in Active_name if x in Check_name]:
            Active_name_list.append(True)
        else:
            Active_name_list.append(False)
    Bid_df = Bid_df.loc[Active_name_list,:].reset_index(drop=True)        
    
    
    # Active_local : 참가가능지역명
    Active_local_list = []

    for Check_local in Bid_df["참가가능지역명"]:
        if [1 for x in Active_local if x in Check_local]:
            Active_local_list.append(True)
        else:
            Active_local_list.append(False)
    Bid_df = Bid_df.loc[Active_local_list,:].reset_index(drop=True)
    
    return Bid_df
# 투찰가능업종명 : ["산림사업법인(숲가꾸기 및 병해충방제)", "산림사업법인(도시숲등 조성, 관리)"]
Active_name = ["산림사업법인(숲가꾸기 및 병해충방제)", "산림사업법인(도시숲등 조성, 관리)", "제작자"]

# 참가가능지역명 : 고흥
Active_local = ["고흥", "보성", "장흥", "여수", "순천"]

def Filter(Bid_df, bidNtceEndDt, Active_name, Active_local):
    # Active_date_list : 입찰 마감 기간에 프로그램 실행 후에 있는지 확인 "입찰마감일자", "입찰마감시각"
    Active_date_list = []
    for i in range(len(Bid_df)):
        Active_date_list.append(Bid_df.loc[i,"입찰마감일자"].replace("-","")+Bid_df.loc[i,"입찰마감시각"].replace(":","")>=str(bidNtceEndDt))
    Bid_df = Bid_df.loc[Active_date_list,:].reset_index(drop=True)
            
    # Active_name : 투찰가능업종명 제한
    Active_name_list = []

    for Check_name in Bid_df["투찰가능업종명"]:
        if [1 for x in Active_name if x in Check_name]:
            Active_name_list.append(True)
        else:
            Active_name_list.append(False)
    Bid_df = Bid_df.loc[Active_name_list,:].reset_index(drop=True)        
    
    
    # Active_local : 참가가능지역명
    Active_local_list = []

    for Check_local in Bid_df["참가가능지역명"]:
        if [1 for x in Active_local if x in Check_local]:
            Active_local_list.append(True)
        else:
            Active_local_list.append(False)
    Bid_df = Bid_df.loc[Active_local_list,:].reset_index(drop=True)
    
    return Bid_df
Bid_df_filter = Filter(Bid_df, bidNtceEndDt, Active_name, Active_local)
Bid_df_filter