반응형

저번 포스팅에서 셀레니움을 이용해서, 필요한 frame으로 이동하고~ 원하는 버튼 클릭하고

보이는 화면의 데이터들을 수집하고, 필터링하는 방법에 대해 알아보았는데요

 

https://rogios-story.tistory.com/entry/selenium-g2b-Crawling-2-4 (저번 포스팅)

 

셀레니움(selenium) 나라장터 데이터 수집하기 2/4 (DataFrame 다루기 및 HTML 파싱)

저번 포스팅에서 다중 frame 으로 구성된 HTML에서 HTML 이동하는 방법에 대해 알아봤는데요 이 다음 부분 부터는 설명하기 보다는 따라하기 방식으로 진행하도록 하겠습니다 https://rogios-story.tistory.

rogios-story.tistory.com

 

이번 포스팅에서는 requests를 이용해서 조금 더 빠르고 쉽게 진행해 보도록 하겠습니다.

 

현재 화면에서, 원하는 내용을 설정하고, '검색' 버튼을 누르면

아래 결과가 쭈욱~ 나타나는데요? ㅎㅎ

 

 

 

검색 버튼을 누르기 전으로 돌아가서, 네트워크를 열고 검색 버튼을 눌러보겠습니다!

(검색 버튼을 눌렀을 때, 어떤 네트워크 로그들이 남는지 확인하려는 거예요~)

 

두 번째로 나타난 저 tbidLIst라는 게 조금 수상하죠? 이름에도 list가 들어간 모습이...

우리가 보고 싶은 목록이 보일 것 같은 느낌이 오시나요?

 

 

네트워크의 preview를 눌러보시면 비록, 한글이 깨져서 나오지만, 우리가 보고 싶은 모습이 그대로 담겨있을 것 같은 느낌이 더 들어요!!

 

그럼 일단 저 친구를 파이썬에서 불러서 확인해 봐야겠어요! ㅎㅎ

 

제 방법을 따라 해 보세요

 

파이썬으로 requests 라이브러리 이용해서 데이터 불러오는 방법

 

1.  Headers 탭에서 Request Method 방법 알아오기

먼저 헤더스 텝에서, requests 방법을 어떤 걸 쓰는지 확인해야 해요, 이번 포스팅에서는 GET 방식을 이용했네요

참고로 request 방식에는 GET 방식과 POST 방식이 있습니다

 

2.  payload 검토하기

GET 방식인 경우에는, POST 방식보다 훨씬 편하게 payload를 확인할 수 있어요

저는 혹시 몰라서 url을 새 탭에 불러와보기도 했습니다

 

그다음 payload를 살펴보아요

 

3.  headers 복사하기

Headers 탭에서, Request Headers 내용을 모두 복사해서 변수에 넣어줄 예정이에요

 

4.  파이썬에서 requests 코드 작성하기

 

아래와 같은 코드가 나오는데요

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 29 21:12:23 2023

@author: 진연녹
"""

import pandas as pd
import requests
from bs4 import BeautifulSoup

#%% 
# 처음 URL에서 ? << 물음표 뒷 부분은 모두 제거하고 남은 url
url = "https://www.g2b.go.kr:8101/ep/tbid/tbidList.do?"

headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
    "Connection": "keep-alive",
    "Cookie": "ccsession=2023100518303100000ad00ad07afe; ccguid=2023100518303100000ad00ad07afe; ipmsperf_uuid=-480776048976768909; _KONEPS_PAGE=%3C%21%23%25%3EtbidListUrl%3C%40%25%7E%3E%2Fep%2Ftbid%2FtbidList.do%3Farea%3D%26areaNm%3D%26bidNm%3D%26bidSearchType%3D1%26budgetCompare%3D%26detailPrdnm%3D%26detailPrdnmNo%3D%26downBudget%3D%26fromBidDt%3D2023%252F04%252F04%26fromOpenBidDt%3D%26industry%3D%26industryCd%3D%26instNm%3D%26instSearchRangeType%3D%26intbidYn%3D%26orgArea%3D%26procmntReqNo%3D%26radOrgan%3D1%26recordCountPerPage%3D100%26refNo%3D%26regYn%3DY%26searchDtType%3D1%26searchType%3D1%26setMonth1%3D3%26strArea%3D%26taskClCds%3D5%26toBidDt%3D2023%252F10%252F05%26toOpenBidDt%3D%26upBudget%3D; JSESSIONID=MGpvlpGJdvZpbvgg1ZKrFJJcXpdpckfGqypy6hqJK1zv6tNqQFMx!71603225",
    "Host": "www.g2b.go.kr:8101",
    "Referer": "https://www.g2b.go.kr:8101/ep/tbid/tbidList.do?searchType=1&bidSearchType=1&taskClCds=5&bidNm=&searchDtType=1&fromBidDt=2023%2F04%2F04&toBidDt=2023%2F10%2F05&setMonth1=3&fromOpenBidDt=&toOpenBidDt=&radOrgan=1&instNm=&instSearchRangeType=&refNo=&area=&areaNm=&strArea=&orgArea=&industry=&industryCd=&upBudget=&downBudget=&budgetCompare=&detailPrdnmNo=&detailPrdnm=&procmntReqNo=&intbidYn=&regYn=Y&recordCountPerPage=100",
    "Sec-Ch-Ua": "\"Google Chrome\";v=\"117\", \"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"117\"",
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": "\"Windows\"",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
}


# 
payload = {
    "area": "",
    "areaNm": "",
    "bidNm": "",
    "bidSearchType": "1",
    "budgetCompare": "",
    "detailPrdnm": "",
    "detailPrdnmNo": "",
    "downBudget": "",
    "fromBidDt": "2023/04/04",
    "fromOpenBidDt": "",
    "industry": "",
    "industryCd": "",
    "instNm": "",
    "instSearchRangeType": "",
    "intbidYn": "",
    "orgArea": "",
    "procmntReqNo": "",
    "radOrgan": "1",
    "recordCountPerPage": "100",
    "refNo": "",
    "regYn": "Y",
    "searchDtType": "1",
    "searchType": "1",
    "setMonth1": "3",
    "strArea": "",
    "taskClCds": "5",
    "toBidDt": "2023/10/05",
    "toOpenBidDt": "",
    "upBudget": "",
    "currentPageNo": "1",
    "maxPageViewNoByWshan": "2"
}

res = requests.get(url, params = payload)

res.text

사실 headers가 없어도 잘 작동됩니다!!!

간혹 여러 이유로 headers가 꼭 필요할 때가 있는데, 그 부분은 나중에 다루도록 하고이번에는 headers를 지우고 이용하도록 하겠습니다

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 29 21:12:23 2023

@author: 진연녹
"""

import pandas as pd
import requests
from bs4 import BeautifulSoup

#%% 
# 처음 URL에서 ? << 물음표 뒷 부분은 모두 제거하고 남은 url
url = "https://www.g2b.go.kr:8101/ep/tbid/tbidList.do?"

# 
payload = {
    "area": "",
    "areaNm": "",
    "bidNm": "",
    "bidSearchType": "1",
    "budgetCompare": "",
    "detailPrdnm": "",
    "detailPrdnmNo": "",
    "downBudget": "",
    "fromBidDt": "2023/04/04",
    "fromOpenBidDt": "",
    "industry": "",
    "industryCd": "",
    "instNm": "",
    "instSearchRangeType": "",
    "intbidYn": "",
    "orgArea": "",
    "procmntReqNo": "",
    "radOrgan": "1",
    "recordCountPerPage": "100",
    "refNo": "",
    "regYn": "Y",
    "searchDtType": "1",
    "searchType": "1",
    "setMonth1": "3",
    "strArea": "",
    "taskClCds": "5",
    "toBidDt": "2023/10/05",
    "toOpenBidDt": "",
    "upBudget": "",
    "currentPageNo": "1",
    "maxPageViewNoByWshan": "2"
}

res = requests.get(url, params = payload)

res.text

지금 코드에서도, payload 내용 중 값이 비어있는 애들이 불필요해 보이시죠?불필요해 보이는 친구들 다 보내버리고 다시 작성해 볼게요~

 

 

우왕~ 다 지우고 나니 훨씬 짧아졌어요!!

 

코드에 필요해 보이는 주석들은 입력했더니 우리가 수정해야 할 부분이 확실하게 보이네요?

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 29 21:12:23 2023

@author: 진연녹
"""

import pandas as pd
import requests
from bs4 import BeautifulSoup

#%% 
# 처음 URL에서 ? << 물음표 뒷 부분은 모두 제거하고 남은 url
url = "https://www.g2b.go.kr:8101/ep/tbid/tbidList.do?"

# 
payload = {
    "bidSearchType": "1",
    "fromBidDt": "2023/04/04",
    "radOrgan": "1",
    "recordCountPerPage": "100",    # 한 페이지에 몇개 노출인가
    "regYn": "Y",
    "searchDtType": "1",
    "searchType": "1",              # 몰라도 되는 듯
    "setMonth1": "3",               # 최근1달 : 1, 최근2달:2, 최근6달:3
    "taskClCds": "5",               # 물품:1, 공사:3, 용역:5, 리스:6, 외자:2, 비축:11, 기타:4, 민간:20
    "toBidDt": "2023/10/05",        
    "currentPageNo": "1",           # 현재 페이지 번호
    "maxPageViewNoByWshan": "2"
}

res = requests.get(url, params = payload)

res.text

 

일단 이전 포스팅 내용을 참고해서 테이블화 해보았어요

 

잘 불러와지는군요 ^^

이렇게 잘 될 때에는 자기 자신과 컴퓨터를 쓰담쓰담해주면서

세 번 칭찬해 주세요...

반드시 그래야 해요

 

5.  반복해서 수집 후 필터링 하기

 

# 나중에 쓸 변수 미리 생성
입찰공고목록_합 = pd.DataFrame()

# 더보기 10회 진행하기
i = 1
반복횟수 = 10
while i <= 반복횟수:
    payload['currentPageNo'] = i
    res = requests.get(url, params = payload)
    if res.status_code  == 200:
        print(payload['currentPageNo'], '불러옴')
        html = res.text
        soup = BeautifulSoup(html, 'html.parser')
        입찰공고목록_요소 = soup.find('table')
        입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]
        입찰공고목록_합 = pd.concat([입찰공고목록_합,입찰공고목록_table])
    else:
        print(i,' 번째 페이지 에러 확인해주세요')
    i = i+1



# 필터링 하기 (공고명에 "건설관리", "실시설계", "기술진단" 이 포함된 내용만 추출)
keywords = ["건설관리", "실시설계", "기술진단"]
입찰공고목록_최종 = 입찰공고목록_합[입찰공고목록_합['공고명'].str.contains('|'.join(keywords))]

위 코드를 이용해서, 반복 + 데이터 수집 + 필터링까지 완료하면

총 1000 공고 중 96개가 남은 모습을 확인할 수 있네요~

 

가끔 보고 지나가는 님들아!!!!

아무 댓글 좀 달아줘요...

힘난단 말이에요

#전체 코드

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 29 21:12:23 2023

@author: 진연녹
"""
import pandas as pd
import requests
from bs4 import BeautifulSoup

#%% 
# 처음 URL에서 ? << 물음표 뒷 부분은 모두 제거하고 남은 url
url = "https://www.g2b.go.kr:8101/ep/tbid/tbidList.do?"

payload = {
    "bidSearchType": "1",
    "fromBidDt": "2023/04/04",
    "radOrgan": "1",
    "recordCountPerPage": "100",    # 한 페이지에 몇개 노출인가
    "regYn": "Y",
    "searchDtType": "1",
    "searchType": "1",              # 몰라도 되는 듯
    "setMonth1": "3",               # 최근1달 : 1, 최근2달:2, 최근6달:3
    "taskClCds": "5",               # 물품:1, 공사:3, 용역:5, 리스:6, 외자:2, 비축:11, 기타:4, 민간:20
    "toBidDt": "2023/10/05",        
    "currentPageNo": "1",           # 현재 페이지 번호
    "maxPageViewNoByWshan": "2"
}
res = requests.get(url, params = payload)

html = res.text
soup = BeautifulSoup(html, 'html.parser')
입찰공고목록_요소 = soup.find('table')
입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]

#%%

# 나중에 쓸 변수 미리 생성
입찰공고목록_합 = pd.DataFrame()

# 더보기 10회 진행하기
i = 1
반복횟수 = 10
while i <= 반복횟수:
    payload['currentPageNo'] = i
    res = requests.get(url, params = payload)
    if res.status_code  == 200:
        print(payload['currentPageNo'], '불러옴')
        html = res.text
        soup = BeautifulSoup(html, 'html.parser')
        입찰공고목록_요소 = soup.find('table')
        입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]
        입찰공고목록_합 = pd.concat([입찰공고목록_합,입찰공고목록_table])
    else:
        print(i,' 번째 페이지 에러 확인해주세요')
    i = i+1



# 필터링 하기 (공고명에 "건설관리", "실시설계", "기술진단" 이 포함된 내용만 추출)
keywords = ["건설관리", "실시설계", "기술진단"]
입찰공고목록_최종 = 입찰공고목록_합[입찰공고목록_합['공고명'].str.contains('|'.join(keywords))]
반응형

+ Recent posts