AI SCHOOL/Python

[Python] 다산콜센터 주요 민원 내용 수집(2)

moru_xz 2023. 1. 24. 16:56

다산콜센터 (1)이랑 다른점은  (2)는 작성자- 이런 것에 내용을 붙임

# 필요한 라이브러리들을 불러옵니다.
# pandas : 파이썬에서 사용할 수 있는 엑셀과 유사한 데이터분석 도구입니다.
# requests : 매우 작은 브라우저로 웹사이트의 내용과 정보를 불러옵니다.
# BeautifulSoup : request로 가져온 웹사이트의 html 태그를 찾기 위해 사용합니다.
# time : 한 번에 많은 양의 데이터를 가져오게 되면 서버에서 부담을주기 때문에 시간 간격을 두고 가져오기 위해 사용합니다.
import time
import pandas as pd
import numpy as np
import requests
from bs4 import BeautifulSoup as bs

# 수집해온 파일("seoul-120-list.csv")을 읽어옵니다.
df = pd.read_csv('seoul-120-list.csv_복습')
df.shape

 

특정 내용 읽어오기

# 내용 페이지의 주소를 url 변수에 담아줍니다.
# 웹페이지의 결과를 받아옵니다.
# BeautifulSoup을 통해 lxml로 파싱해 올 수 있도록 합니다.
# html 태그에서 "div.line-all"의 0번째 값을 선택(select)하여 text를 확인합니다. 

no = df['내용번호'][0]
url = f'https://opengov.seoul.go.kr/civilappeal/{no}'
print(url)
response = requests.get(url)
html = bs(response.text)
# tb01
# tb02
df_desc = pd.read_html(response.text)[-1]
df_desc

# 전치행렬 transpose() == T 를 하기 위해 인덱스를 설정해 주었습니다.
# 전치행렬을 했을 때 index <=> columns 위치가 변경되기 때문에 인덱스로 설정해 주었습니다.
tb01 = df_desc[[0,1]].set_index(0).T
display(tb01)
tb02 = df_desc[[2,3]].set_index(2).T
display(tb02)
# concat을 할 때 axis=1이라면 index 값 기준으로 컬럼(열)로 붙여주기 때문에 index 값이 같아야 합니다.
tb02.index = tb01.index
pd.concat([tb01, tb02], axis = 1)

# 해당 문의가 어떤 분류에 해당되는지 알기 위해 분류를 수집합니다.
def get_desc(response):
    """ 분류 수집하기 
    1) 테이블의 0, 1 번째 데이터 가져와서 0번째 컬럼을 인덱스로 만들고 전치행렬 만들기
    2) 테이블의 2, 3 번째 데이터 가져와서 2번째 컬럼을 인덱스로 만들고 전치행렬 만들기
    3) 1), 2) 번에서 만든 값을 concat으로 병합하기
    4) 병합한 값 반환하기
    """
    # response = request.get(url)을 하면
    # response를 받기로 햇는데 이미 함수 안에서 지정해줘서 
    # 정해져있는 url만 받음
    df_desc = pd.read_html(response.text)[-1]
    tb01 = df_desc[[0, 1]].set_index(0).T.reset_index(drop=True)
    tb02 = df_desc[[2, 3]].set_index(2).T.reset_index(drop=True)

    df_desc_tb = pd.concat([tb01, tb02], axis=1)
    return df_desc_tb    

# 함수가 잘 만들어졌는지 확인하기
get_desc(response)

-> 분류 수집 함수 완성!

 

내용 수집 함수

# 위의 전체 과정을 함수로 만들어 봅니다.

def get_view_page(view_no):
    """ 
    내용과 분류를 수집하는 함수 만들기
    1) url을 만들어 줍니다.
    2) requests 로 요청을 보냅니다.
    3) 분류를 수집하는 함수에 response 값을 넘겨 분류와 제공부서 등이 들어있는 데이터프레임을 반환 받습니다.
    4) 내용을 bs 으로 텍스트만 추출합니다.
    5) 3)번 내용에 내용, 내용번호를 함께 데이터프레임에 추가합니다.
    6) 반복문 대신 map이나 apply를 사용할 것이기 때문에 time.sleep으로 쉬도록 합니다.
    7) 5번까지 수집한 내용을 반환하도록 합니다.
    """
    try :
        url = f"https://opengov.seoul.go.kr/civilappeal/{view_no}"
        response = requests.get(url)
        desc = get_desc(response)
        html = bs(response.text)
        cont = html.select("#content > div > div > div:nth-child(2) > div")[0].text.strip()
        desc['내용'] = cont
        desc['내용번호'] = view_no
        return desc
    
    except Exception as e :
        print(f"오류 게시물 번호 : {view_no}, 오류 메시지 : {e}")
# 없는 데이터를 불러왔을 때 오류가 나는지 확인
# view_no가 22904492 인 것을 get_view_page()로 확인해 봅니다.
get_view_page(view_no=27097033)

전체 내용 가져오기

# tqdm.notebook 의 tqdm 을 통해 수집 진행상태를 확인합니다.
# progress_apply 를 사용하면 진행상태를 확인하며 데이터를 가져올 수 있습니다.
from tqdm.notebook import tqdm
tqdm.pandas()

view_detail = df['내용번호'].progress_map(get_view_page)

view_detail

하나로 병합하기

# 수집한 내용을 tolist() 를 통해 리스트로 변환 후 concat 으로 병합합니다.
# df_view
type(view_detail)
df_view = pd.concat(view_detail.to_list(), ignore_index = True)
df_view

-> 리스트만 concat 할 수 있기 때문에 

# 기존 데이터와 병합하여 내용이 함께 수집된 것을 확인합니다.
# df_detail
df_detail = df.merge(df_view, on = ['내용번호', '생산일'], how = 'left')

merge 사용