파이썬으로 나라장터 입찰공고 크롤링하기

회사 보스가 조달청 나라장터에 올라오는 입찰공고를 주기적으로 확인하고 싶다는 얘기를 했다. 담당자를 정해서 매번 손으로 검색해서 그 결과를 정리해서 보여주는 것은 너무 비효율적인 방식이라고 생각했다.

그래서 selenium(셀레니움)이라는 파이썬 라이브러리로 크롤링하는 코드를 짜봤다.

사실 이런 스크립트는 다른 블로그나 아래와 같은 깃헙에서도 소스코드를 좀 확인할 수 있었다. 다만 너무 복잡한 방식으로 되어 있고 필요 없는 정보들도 너무 많이 가져오는 것처럼 보였다.

이번에는 필요한 정보만 소식지처럼 받아보는 것이 주된 목적이었기 때문에 나처럼 프로그래밍에 대해 잘 모르는 문과생, 코딩 초보도 이해할 수 있는 방식으로 최대한 가볍고 단순하게 코드를 짜는 것에 중점을 두었다.


준비

1) selenium 설치

대표적인 파이썬 웹 크롤링 라이브러리로 selenium과 beautifulsoup이 있다. beautifulsoup을 선호하는 사람들도 있는 것 같은데, 나는 처음부터 selenium으로 입문했고, 이게 편해서 계속 이걸 쓴다.

selenium 설치는 아래와 같이 하면 된다.

pip install selenium

2) 웹 드라이버 다운로드 (크롬)

selenium 라이브러리에서 다양한 브라우저의 드라이버를 다룰 수 있는데, 내가 평소에 사용하는 크롬 드라이버를 선택했다. 다운은 이곳에서 받을 수 있다.

https://sites.google.com/a/chromium.org/chromedriver/downloads

다운받은 크롬 드라이버 exe 파일은 파이썬 파일과 같은 경로에 두면 된다.

이제 준비는 끝났다.


나라장터 입찰공고 검색 웹페이지 확인

일단 웹페이지를 살펴보자. 입찰공고를 검색하는 웹페이지 url은 아래와 같이 생겼다.

http://www.g2b.go.kr:8101/ep/tbid/tbidFwd.do

검색어를 넣는 것뿐만 아니라 체크박스를 클릭하거나, 드롭다운 메뉴를 선택하는 등의 동작을 해야 한다.

그리고 검색 버튼을 눌렀을 때 나오는 화면은 아래와 같다.

표 형태로 공고 결과가 나오는 걸 알 수 있다.

나라장터 입찰공고 크롤링 소스코드 (예제)

아래와 같이 짜봤다.

# 크롬 브라우저를 띄우기 위해, 웹드라이버를 가져오기
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select

# 크롬 드라이버로 크롬을 실행한다.
driver = webdriver.Chrome('./chromedriver')

try:
    # 입찰정보 검색 페이지로 이동
    driver.get('http://www.g2b.go.kr:8101/ep/tbid/tbidFwd.do')
    
    # 업무 종류 체크
    task_dict = {'용역': 'taskClCds5', '민간': 'taskClCds20', '기타': 'taskClCds4'}
    for task in task_dict.values():
        checkbox = driver.find_element_by_id(task)
        checkbox.click()
    
    # 검색어
    query = '채용'
    # id값이 bidNm인 태그 가져오기
    bidNm = driver.find_element_by_id('bidNm')
    # 내용을 삭제 (버릇처럼 사용할 것!)
    bidNm.clear()
    # 검색어 입력후 엔터
    bidNm.send_keys(query)
    bidNm.send_keys(Keys.RETURN)

    # 검색 조건 체크
    option_dict = {'검색기간 1달': 'setMonth1_1', '입찰마감건 제외': 'exceptEnd', '검색건수 표시': 'useTotalCount'}
    for option in option_dict.values():
        checkbox = driver.find_element_by_id(option)
        checkbox.click()

    # 목록수 100건 선택 (드롭다운)
    recordcountperpage = driver.find_element_by_name('recordCountPerPage')
    selector = Select(recordcountperpage)
    selector.select_by_value('100')

    # 검색 버튼 클릭
    search_button = driver.find_element_by_class_name('btn_mdl')
    search_button.click()

    # 검색 결과 확인
    elem = driver.find_element_by_class_name('results')
    div_list = elem.find_elements_by_tag_name('div')

    # 검색 결과 모두 긁어서 리스트로 저장
    results = []
    for div in div_list:
        results.append(div.text)
        a_tags = div.find_elements_by_tag_name('a')
        if a_tags:
            for a_tag in a_tags:
                link = a_tag.get_attribute('href')
                results.append(link)

    # 검색결과 모음 리스트를 12개씩 분할하여 새로운 리스트로 저장 
    result = [results[i * 12:(i + 1) * 12] for i in range((len(results) + 12 - 1) // 12 )]

    # 결과 출력
    print(result)

except Exception as e:
    # 위 코드에서 에러가 발생한 경우 출력
    print(e)
finally:
    # 에러와 관계없이 실행되고, 크롬 드라이버를 종료
    driver.quit()

일단 나는 리스트의 리스트 형태로 검색 결과를 저장했다. 필요에 따라 필요한 항목만 꺼내 쓰거나, 엑셀로 저장하기 편하기 때문이다.

리스트 묶음을 엑셀로 정리하는 건 openpyxl 라이브러리를 활용하길 추천한다. openpyxl 사용과 관련해서는 아래 포스팅을 참고해도 좋을 것 같다.

파이썬으로 여러개의 엑셀 파일에서 필요한 값들만 한 번에 가져오기 (일명 엑셀 크롤링)

어쨌든 나는 이렇게 수집한 결과를 이메일로 보내는 스크립트를 뒷 부분에 완성하고, 그 파이썬 파일을 crontab을 통해 매주 같은 시간에 실행되도록 스케줄링해놨다. 수집된 결과를 정리하거나 이메일로 작성하는 것, 파이썬 스크립트 자동실행 스케줄링 등은 별도의 긴 설명이 필요하므로 본 포스팅에서는 생략한다.

아무튼 반복적이고 단순한 작업은
최대한 컴퓨터를 시켜놓고
우리는 그 시간에 다른 걸 하자!

추천 글

“파이썬으로 나라장터 입찰공고 크롤링하기”의 2개의 댓글

  1. 안녕하세요…프로그램 초보 입니다. 나라장터 크롤링에 대해 알아보다 웨라벨님 사이트까지 들어오게됐습니다..제가 나라장터 크롤링을 만들어 보려다 거의 완벽히 제가 만들고 싶은 파이썬 프로그램 코드를 만드신걸 보고 놀라웠고 고마웠습니다. 그래서 구동을 했는데 잘 돼었지만 엑셀저장 기능이 않돼어서 이렇게 댓글을 남기네요…어떻게 하면 엑셀에다 저장을 할수 있는지 알수 있을까요? 어떻게 찾을수 있을까요?….

    1. 저는 파이썬으로 엑셀을 다룰 때 openpyxl이라는 라이브러리를 많이 사용하는데요,
      아래 포스팅에서 어느정도 소개했으니 확인해보시면 될 것 같고요.
      http://hleecaster.com/excel-crawling-with-python/

      아래와 같이 쓰시면 될 거예요!
      —————————

      from openpyxl import Workbook

      wb = Workbook()
      ws = wb.active
      for i in results:
        ws.append(i)
      wb.save(“results.xlsx”)

댓글 남기기