본문 바로가기
Python

[웹 스크래핑] 역대 대통령 연설기록 목록과 그 내용까지

2023. 1. 16.

행정안전부 대통령 기록관 사이트역대 대통령 연설기록을 스크래핑해본다.

president
대통령 기록관 연설기록 목록


페이지를 넘기면 나오는 목록 뿐 아니라 제목을 눌렀을 때 나오는 내용까지 수집한다.

필요한 라이브러리 import

import requests
import pandas as pd
from bs4 import BeautifulSoup as bs

URL로 HTTP 요청을 보내기 위해 requests,
데이터프레임을 만들기 위해 pandas,
내용으로 들어가기 위한 링크를 찾기 위해 BeautifulSoup

URL 작성

url = "https://www.pa.go.kr/research/contents/speech/index.jsp"
params = f"?spMode=&artid=&catid=&pageIndex={page_no}&searchHistoryCount=0&searchStartDate=&searchEndDate=&pageUnit=20"

URL 구조는 개발자 도구를 통해 파악할 수 있다.
검사 -> Network -> Doc -> jsp 파일 클릭 -> payload

params

page_no에 들어가는 숫자가 연설기록 몇 페이지인지를 의미한다.

HTTP 요청

response = requests.post(url, params=params, verify=False)
print(response.status_code)

# 실행 결과
200

verify=False는 SSL 인증서 확인 과정을 생략하겠다는 의미다.
요청을 보내고 응답을 잘 받았음을 status_code 200을 통해 알 수 있다.

데이터프레임 구하기

df = pd.read_html(response.text)[0]

특정 페이지의 연설기록 목록이 df에 저장되었다.

내용 수집을 위한 링크 찾기

html = bs(response.text)
# a tag 찾기
a_list = html.select("#M_More > tr > td.subject > a")
# href list 만들기
a_href = [a['href'] for a in a_list]

BeautifulSoup 객체를 만들고 select 함수 인자로 아래처럼  Copy selector로 구한 태그 정보를 넣어준다.
제목 부분에 마우스 우클릭 -> 검사(Inspect)를 누르면 <a> 태그 하나가 잡히는데, 그 태그에서 구한 값이다.

atag

a_list는 모든 a 태그 데이터가 들어간 리스트이며 list comprehension을 이용하여 a태그의 href 요소에 들어 있는 내용만 뽑아 a_href에 저장한다.

URL을 만들어 데이터프레임에 추가

df["내용링크"] = list(map(lambda x: url+x, a_href))

대통령기록관의 기본 url을 각 연설 별로 추출한 href 요소의 값의 앞 부분에 붙이며 df의 "내용링크" 컬럼에 추가한다.
여기까지 하면 연설기록 한 페이지의 목록(번호, 대통령, 형태, 유형, 제목, 연설일자)와 링크 스크래핑이 완료된 것이다.

하나의 함수로 정리

def page_scrapping(page_no):
    """
    1) page 번호로 URL 만들기
    2) requests.post()로 요청하기
    3) bs 적용
    4) 테이블 찾기
    5) a 태그 목록 찾기
    6) 내용링크에 a 태그 주소 추가하기
    7) 데이터프레임 반환
    """
    url = "https://www.pa.go.kr/research/contents/speech/index.jsp"
    params = f"spMode=&artid=&catid=&pageIndex={page_no}&searchHistoryCount=0&searchStartDate=&searchEndDate=&pageUnit=20"
    
    response = requests.post(url, params=params, verify=False)
    
    html = bs(response.text)

    df = pd.read_html(response.text)[0]

    a_list = html.select("#M_More > tr > td.subject > a")

    a_href = [a['href'] for a in a_list]

    df["내용링크"] = list(map(lambda x: url+x, a_href))
    
    return df

페이지 번호만 넘겨주면 그 페이지에 해당하는 연설기록 목록과 내용링크가 데이터프레임으로 반환되는 함수이다.

원하는 결과를 얻는지 확인

colab

코랩 환경에서 데이터프레임을 확인했고, 링크가 잘려 보이지만 제대로 입력된 것을 확인할 수 있었다.

내용 스크래핑하기

def get_content(url):
    response = requests.post(url, verify=False)
    html = bs(response.text)
    content = html.select("#content > div > table > tbody > tr > td.content")
    
    if len(content) == 0:
        return '음성 기록 또는 동영상 기록'
    else:
        return content[0].text
    
    time.sleep(0.1)
    return content

url을 입력하면 내용 텍스트만 반환하는 함수를 작성했다. 만약 연설문이 아닌 연설음성이나 연설동영상일 경우 '음성 기록 또는 동영상 기록'을 반환한다.

progress
tqdm의 progress_map 함수

내용링크 컬럼에 tqdm의 progress_map 함수를 적용해서 내용 컬럼을 추가한다.
tqdm import를 하지 않고 일반 map함수로 해도 같은 동작을 하지만, progress_map은 진행 상황을 체크할 수 있다는 장점이 있다.

그 후 내용링크 컬럼을 삭제하며 데이터프레임 구성을 마무리한다.

df = df.drop('내용링크', axis=1)

 

파일로 저장하여 확인

df.to_excel('연설문내용포함.xlsx', encoding='cp949', index=False)

content

to_excel을 통해 저장한 후 엑셀로 열어 내용까지 잘 저장된 것을 확인할 수 있다.

BeautifulSoup를 이용하여 마지막 페이지를 구하고, 반복문을 사용하여 모든 기록을 전부 스크래핑 할 수도 있다.

반응형

댓글