반응형

저번 포스팅에서 다중 frame 으로 구성된 HTML에서 HTML 이동하는 방법에 대해 알아봤는데요

이 다음 부분 부터는 설명하기 보다는 따라하기 방식으로 진행하도록 하겠습니다

 

 

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

 

셀레니움(selenium) 나라장터 데이터 수집하기 1/4 (HTML frame 이동)

이번에는, 셀레니움을 이용해서 간단하게 나라장터 데이터를 수집하는 프로그램을 제작해 볼 계획이에요 총 네 단계 포스팅으로 나누어 진행할 계획이고요 첫 번째 포스팅에서는 여러 개의 fram

rogios-story.tistory.com

 

이전 포스팅에서 표시된 용역 버튼을 클릭하는 부분 까지 다루었는데요

 

<이전 포스팅에서 필요한 부분만 가져옴>

from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
import requests
from bs4 import BeautifulSoup

# 셀레니움 웹드라이브 열기
driver = webdriver.Chrome()

# 나라장터  URL 접속
url = "https://www.g2b.go.kr/pt/menu/selectSubFrame.do?framesrc=/pt/menu/frameTgong.do?url=https://www.g2b.go.kr:8101/ep/tbid/tbidFwd.do"
driver.get(url)

driver.switch_to.frame('sub') #frame id or name을 이용하여 이동하는 코드 저도 확실하지 않아서 검토 해 보아야함
driver.switch_to.frame('left') #frame id or name을 이용하여 이동하는 코드 저도 확실하지 않아서 검토 해 보아야함

용역버튼 = driver.find_element(By.XPATH, '//*[@id="000019"]/a')  
용역버튼.click()

 

그 다음 공고현황을 클릭해요

driver.find_element(By.XPATH,'//*[@id="000022"]/a').click() # 공고현황 클릭하기

우리가 컨트롤해야 하는 frame는 'main'이라는 것을 알 수 있어요

 

프레임 이동 등에 대해서 이미 설명 했으니, 자세한 설명 없이 페이지 자동으로 필터링 까지 하는 코드를 추가해볼게요

 

driver.switch_to.default_content()  # 다시 기본 문서로 돌아가기

driver.switch_to.frame('sub') # 다음 frame로 들어가기

driver.switch_to.frame('main') # 입찰정보 검색 frame로 들어가기

driver.find_element(By.XPATH,'//*[@id="setMonth1_3"]').click()  #최근 6개월 항목 클릭

# 목록수 100으로 변경하는 코드
from selenium.webdriver.support.select import Select
select_element = driver.find_element(By.CSS_SELECTOR,"#recordCountPerPage")
select = Select(select_element)
select.select_by_value("100")

driver.find_element(By.XPATH,'//*[@id="buttonwrap"]/div/a[1]').click() #검색하기 클릭

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

# 첫 번째 검색
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
입찰공고목록_요소 = soup.find('table')
입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]
입찰공고목록_합 = 입찰공고목록_table

# 더 보기 버튼 클릭
driver.find_element(By.CLASS_NAME,'default').click()

# 첫 번째 검색 결과에 2 번째 검색 결과 합치기
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
입찰공고목록_요소 = soup.find('table')
입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]

입찰공고목록_합 = pd.concat([입찰공고목록_합,입찰공고목록_table])

# 더보기 10회 진행하기
i = 0
반복횟수 = 100
while i < 반복횟수:
    try:
        driver.find_element(By.CLASS_NAME,'default').click()
    except:
        print('에러 있는듯... 검토 필요')
        break
    
    # 첫 번째 검색 결과에 2 번째 검색 결과 합치기
    html = driver.page_source
    soup = BeautifulSoup(html, 'html.parser')
    입찰공고목록_요소 = soup.find('table')
    입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]
    
    입찰공고목록_합 = pd.concat([입찰공고목록_합,입찰공고목록_table])
    
    현재페이지 = driver.find_element(By.XPATH,"//span[@title='현재페이지']").text

    print('현재 페이지 번호 : ',현재페이지 )

    i = i+1



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

위 코드들을 실행하시면 '입찰공고목록_최종' 이라는 변수 안에 필터링된 정보들만 남아있는 모습을 볼 수 있어요

 

사실 이 방법 보다 더 빠르게 하는 방법이 있는데!!!!

requests 라는 라이브러리를 이용하는 방법입니다!!

다음 포스팅에서는 requests 라는 라이브러리를 이용해서 데이터를 수집하는 방법에 대해 알아볼게요~

 

#전체코드

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

@author: 진연녹
"""

from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
import requests
from bs4 import BeautifulSoup

#%% 
# 셀레니움 웹드라이브 열기
driver = webdriver.Chrome()

# 나라장터  URL
url = "https://www.g2b.go.kr/pt/menu/selectSubFrame.do?framesrc=/pt/menu/frameTgong.do?url=https://www.g2b.go.kr:8101/ep/tbid/tbidFwd.do"

# 나라장터 접속
driver.get(url)
#%%

# 용역 << 요소 탐색
# 용역버튼 = driver.find_element(By.XPATH, '//*[@id="000019"]/a')  # <<<<<<<<<<< 코드는 설명을 위해 고의로 에러를 발생시켰으므로 최종 코드에서는 주석처리 함


#%% default 프레임에서 모든 프레임 요소 가져오기

driver.switch_to.default_content()  # 기본 문서로 돌아가기   <<<<<<< 한번도 이동하지 않았기에 필요 없지만, 넣어둠

frames = driver.find_elements(By.TAG_NAME,'frame')

# 각 프레임의 name 출력
for frame in frames:
    frame_name = frame.get_attribute('name')
    print(f'프레임 이름: {frame_name}')
print('프레임 개수 : ',len(frames))


driver.switch_to.frame('sub') #frame id or name을 이용하여 이동하는 코드 저도 확실하지 않아서 검토 해 보아야함
# driver.switch_to.frame(1) #frame 번호로 이동하는 코드  (0,1,2) 순서 이므로 2번 째 프레임으로 이동함
driver.execute_script("return window.frameElement.id;")   #현재 프레임 id 갑을 출력하는 코드

driver.switch_to.frame('left') #frame id or name을 이용하여 이동하는 코드 저도 확실하지 않아서 검토 해 보아야함
driver.execute_script("return window.frameElement.name;")   #현재 프레임 name 갑을 출력하는 코드


용역버튼 = driver.find_element(By.XPATH, '//*[@id="000019"]/a')  
용역버튼.click()

driver.find_element(By.XPATH,'//*[@id="000022"]/a').click() # 공고현황 클릭하기

#%%
driver.switch_to.default_content()  # 다시 기본 문서로 돌아가기

driver.switch_to.frame('sub') # 다음 frame로 들어가기

driver.switch_to.frame('main') # 입찰정보 검색 frame로 들어가기

driver.find_element(By.XPATH,'//*[@id="setMonth1_3"]').click()  #최근 6개월 항목 클릭

# 목록수 100으로 변경하는 코드
from selenium.webdriver.support.select import Select
select_element = driver.find_element(By.CSS_SELECTOR,"#recordCountPerPage")
select = Select(select_element)
select.select_by_value("100")

driver.find_element(By.XPATH,'//*[@id="buttonwrap"]/div/a[1]').click() #검색하기 클릭

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

# 첫 번째 검색
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
입찰공고목록_요소 = soup.find('table')
입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]
입찰공고목록_합 = 입찰공고목록_table

# 더 보기 버튼 클릭
driver.find_element(By.CLASS_NAME,'default').click()

# 첫 번째 검색 결과에 2 번째 검색 결과 합치기
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
입찰공고목록_요소 = soup.find('table')
입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]

입찰공고목록_합 = pd.concat([입찰공고목록_합,입찰공고목록_table])

# 더보기 10회 진행하기
i = 0
반복횟수 = 100
while i < 반복횟수:
    try:
        driver.find_element(By.CLASS_NAME,'default').click()
    except:
        print('에러 있는듯... 검토 필요')
        break
    
    # 첫 번째 검색 결과에 2 번째 검색 결과 합치기
    html = driver.page_source
    soup = BeautifulSoup(html, 'html.parser')
    입찰공고목록_요소 = soup.find('table')
    입찰공고목록_table = pd.read_html(str(입찰공고목록_요소))[0]
    
    입찰공고목록_합 = pd.concat([입찰공고목록_합,입찰공고목록_table])
    
    현재페이지 = driver.find_element(By.XPATH,"//span[@title='현재페이지']").text

    print('현재 페이지 번호 : ',현재페이지 )

    i = i+1



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

 

잘 보셨으면 댓글 하나씩만 달아주세요!!!!!!!!!!!!

반응형

+ Recent posts