크롤링하기 위해 필요한 라이브러리

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

안양 청년 정책 웹 사이트 url을 얻어온다.

driver.get("https://www.anyang.go.kr/youth/contents.do?key=3567")

웹페이지에서 요소를 찾기 위해 암묵적으로 10초 대기

driver.implicitly_wait(10)

제목, URL 크롤링

해당 페이지에서 각 정책의 제목과 url 크롤링

해당 정책이 몇 개인지 고정되어있지 않기 때문에 값을 설정할 수 없어서 while문을 사용하여 정책 요소들을 순회한다.

순회하면서 해당 정책의 각 url의 key값, 정책 제목을 구한다.

구해온 리스트 안의 딕셔너리 형태로 저장한다. key: key, title: 정책 제목 형태

while True:
        try:
            # key
            url_element = driver.find_element(By.XPATH, '//*[@id="contents"]/div/div/div/ul/li[{}]/a'.format(i))
            title = driver.find_element(By.XPATH, '//*[@id="contents"]/div/div/div/ul/li[{}]/a/span[1]'.format(i))
            
            url = url_element.get_attribute('href')
            key = url.split('=')[-1]
            policyData.append({"key": key, "title": title.text})
            
            i += 1
        except NoSuchElementException:
            break  # 에러가 발생하면 반복문 종료

각 정책들이 리스트 안의 딕셔너리 형태로 저장됨.


데이터프레임으로 저장

이후 고유한 값은 해당 url의 key 값으로 지정하고, 정책 제목은 title로 지정하여 데이터 프레임으로 만든다.

데이터 프레임은 엑셀의 파이썬 버전이라고 생각하면 쉽다.

dfPolicy = pd.DataFrame(policyData) # 데이터 프레임으로 만들기

위 리스트와 같은 값이지만 데이터프레임으로 저장하면 데이터를 관리하기 쉬워진다.


데이터프레임 column 추가하기

현재 key, title만 설정되어있다. sub_title, img의 값들도 추가할 것이기 때문이기 때문에 컬럼명부터 설정한다.

dfPolicy['sub_title'] = None
dfPolicy['img'] = None


위에서 구한 Key 값으로 나머지 sub_title / img 구하기

url의 key 값으로 정책의 이미지와 사업 목적을 구해올 것이다.

정책 페이지 순회

먼저 데이터 프레임 안에 있는 키값을 이용하여 정책 페이지를 순회한다

for index, row in dfPolicy.iterrows():
        policy_key = row['key']
        driver.get('https://www.anyang.go.kr/youth/contents.do?key={}'.format(policy_key))

이미지 구하기

이미지는 로딩이 느릴 수도 있으므로 로드될 때까지 기다린 후 로딩이 끝나면 요소를 구해온 후 리스트로 저장

# 이미지 로드될 때까지 기다림
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="contents"]/div/div/div[1]/div/div[1]/div/div/div/div/div/img')))
img = element.get_attribute('src')
policy_img_lst.append(img)

사업목적 구하기

이후 사업목적도 동일한 방식으로 구해온 후 리스트로 저장

sub_title = driver.find_element(By.XPATH, '//*[@id="contents"]/div/div/div[2]/div/ul/li[1]/p')
sub_title_lst.append(sub_title.text)

데이터 프레임에 저장

dfPolicy['img'] = policy_img_lst
dfPolicy['sub_title'] = sub_title_lst

리스트 안의 값들을 데이터프레임 img, sub_title 열 안에 저장한다.

여러 줄로 잘렸지마나 데이터프레임에 key, title, sub_title, img가 잘 들어가있는 것을 볼 수 있다!

크롤링한 데이터(정책) > 엑셀 > 데이터베이스 > 스프링 > 프론트에 띄우기 ==> 일단 이렇게 생각하고 작업 중이다.

데이터 양이 많아서 스프링 애플리케이션 내에서 메모리에 모두 유지하는 것보다는

데이터베이스에 저장하여 관리하는 것이 좋을 것 같아서 저러한 과정을 거치기로 한 것.

 

크롤링한 데이터를 엑셀 파일로 저장하는 과정은 생각보다 어렵지 않았다

1. 먼저 필요한 라이브러리 설치

  • pip install openpyxl 

2. 엑셀파일 만들고 저장

# 엑셀 만들기
import openpyxl

wb = openpyxl.Workbook()

ws = wb.create_sheet('주거정책')

ws['A1'] = 'number'
ws['B1'] = 'name'

ws['A2'] = 1
ws['B2'] = '홍길동'

wb.save(r'C:\Users\tmdgm\Desktop\pyex\주거정책_data.xlsx')

엑셀파일 만들기 > openpyxl.Workbook()

엑셀 워크시트 만들기 > wb.create_sheet('엑셀시트이름')

행, 열에 들어갈 데이터 추가한 후 wb.save('저장할 경로') 로 저장하면 해당 폴더에 엑셀 시트가 만들어지는 것을 볼 수 있다.

 

이 코드를 데이터 크롤링하는 코드와 합쳐보면

# 가져온 데이터 엑셀파일로 저장
import requests
from bs4 import BeautifulSoup
import openpyxl

fpath = r'C:\Users\tmdgm\Desktop\pyex\주거정책_data.xlsx'

wb = openpyxl.load_workbook(fpath)
ws = wb.active # 현재 활성화된 시트 선택 - 기본시트 선택

row = 2
for i in range(1, 5):
  response = requests.get(f'https://youth.incheon.go.kr/youthpolicy/youthPolicyInfoList.do?menudiv=dwelling&pgno={i}')
  html = response.text
  soup = BeautifulSoup(html, 'html.parser')
  titles = soup.select(".boardList .con-box .tit") # 정책 title
  links = soup.select(".boardList .btn-box .btn:first-child") # 정책 url
  
  # for link in links:
  #   url = link.attrs['href']
  #   print(f'https://youth.incheon.go.kr{url}')
    
  for title in titles:
    print(title.text.strip())
    ws[f'B{row}'] = title.text
    row += 1
    
wb.save(fpath)

 

1. 엑셀 파일을 불러와서

openpyxl.load_workbook(엑셀파일저장되어있는경로) 

2. 현재 활성화된 시트를 선택하고

wb.active

3. 크롤링한 데이터들을 행에 알맞게 저장한다.

ws.[f'B{rows}'] = title.text

B행에 쭉 저장되겠죠 ?

4. 저장하면 끝.

wb.save(fpath)

 

전 포스팅에서 공공데이터 API를 활용하여 정책들을 받아왔었다.

그거 하는 것도 꽤나 애먹었는데 내가 필요한 정보들이 아니었다.

그래서 여러 사이트를 검색해보던 중 청년 정책들을 잘 소개해주는 사이트를 발견했다.

카테고리 주거분야로 들어가면 주거 관련 정책들만 쫙 모아주니 여기서 데이터를 받아오면 좋겠다 생각했다.

그래서 이번에는 웹 크롤링을 시도해봤다. 이것저것 정말 많이 해보는 ...  (vsCode 사용했습니다.)

 

내가 할 것은
1. 위의 사이트에서 정책 제목들을 가져오는 것
2. 해당 정책의 상세보기에 접근할 수 있는 '사업 안내' 버튼 URL을 가져오는 것

1. 필요한 라이브러리 설치

크롤링에 기본이 되는 라이브러리들이다.

  • pip install requests
  • pip install beautifulsoup

파이썬 버전 문제때문에 시간을 또 잡아먹었는데

https://youtu.be/eJ7kqK18afY?si=cD5xM1nliGlPtFhW

이거보고 해결함 ㅠㅠ 

2. 크롤링하고 싶은 URL 가져오기

# 크롤링 기본
import requests
from bs4 import BeautifulSoup

# 크롤링하고 싶은 url get해오기
response = requests.get("https://youth.incheon.go.kr/youthpolicy/youthPolicyInfoList.do?")
html = response.text # html 전체 코드 들어있음.
soup = BeautifulSoup(html, 'html.parser') # html 번역기
# soup.select > 여러개 / soup.select_one > 한 개 선택
titles = soup.select(".tit")

for title in titles:
  print(title.text.strip())

 

설치한 라이브러리들을 import 해준다.

requests.get("URL")로 내가 크롤링하고 싶은 주소를 넣는다.

성공적으로 가져와졌다면 response 출력시 <Response [200]> 이 뜰 것이다.

이후 html번역기인 html.parser를 활용

soup.select() < css 선택자를 활용하여 가져오고 싶은 태그 선택

  • select > 한 개 선택
  • select_one > 여러 개 선택

.tit가 여러 개라면 리스트 형태로 titles에 들어온다.

반복문으로 title를 출력

성공 나이쓰 !

3. 링크 가져오기 

import requests
from bs4 import BeautifulSoup

response = requests.get("https://youth.incheon.go.kr/youthpolicy/youthPolicyInfoList.do?menudiv=dwelling")
html = response.text
soup = BeautifulSoup(html, 'html.parser')
titles = soup.select(".boardList .con-box .tit") # 정책 title
links = soup.select(".boardList .btn-box .btn:first-child") # 해당 정책 URL 접근

for link in links:
  url = link.attrs['href']
  print(f'https://youth.incheon.go.kr{url}')

위와 비슷한 코드이다.

다른 은 a태그 href 속성을 활용하여 url을 가져온 것

link에는 a 태그가 들어가 있다. 

link.attrs['href'] : 해당 링크의 url을 가져올 수 있다.

위의 '~ 인천시 청년월세 지원사업' 들의 해당 정책 상세보기 링크에 접근할 수 있는 것!

4. 여러 페이지 가져오기

정책들이 여러 페이지로 이루어져 있을 것이다.

페이지를 이동할 때마다 변경되는 url을 보고 활용하면 된다.

1페이지
2페이지

페이지가 이동될 때 pgno= 1, 2로 변경되는 것을 볼 수 있다.

# 여러 페이지 가져오기
import requests
from bs4 import BeautifulSoup

pageNum = 1 
for i in range(1, 10):
  print(f'{pageNum}페이지입니다.')
  response = requests.get(f'https://youth.incheon.go.kr/youthpolicy/youthPolicyInfoList.do?menudiv=dwelling&pgno={i}')
  html = response.text
  soup = BeautifulSoup(html, 'html.parser')
  titles = soup.select(".boardList .con-box .tit") # 정책 title
    
  for title in titles:
    print(title.text.strip())
    
  pageNum += 1

 

 

 

반복문으로 pgno={i} < 1~10페이지까지의 모든 정책 제목을 가져올 수 있었다.

간단하게 사이트 크롤링해보기 성공

앞으로의 여정은 멀고도 험하지만요 시작이 반이라고~

 

 

+ Recent posts