본문 바로가기
python

[크롤링] 웹 크롤링 kbs 뉴스 데이터로 직접 해보자! (Beautifulsoup 활용)

by 포 키 2024. 3. 11.
728x90

먼저 해당 포스팅은 앞전의 크롤링 개념 포스팅을 먼저 보고 오는 것을 추천한다.

2024.03.11 - [python] - [크롤링] 웹 크롤링에 대한 기초 지식을 알아보자!

 

[크롤링] 웹 크롤링에 대한 기초 지식을 알아보자!

오늘은 크롤링 강의를 통해 개념을 다시 잡고 실습해보는 시간을 가졌다. 이 포스팅은 메타코드의 웹 크롤링 기초 강의의 1강 내용을 요약한 포스팅이며, 다음 포스팅에 실습에 대해서도 남기려

forky-develop.tistory.com

 

크롤링에 대한 개념이 제대로 확립되지 않은 채로 진행하면 파이널 프로젝트를 진행할 때의 나처럼 방향성을 잡기가 매우 어려울 것이다.

2023.11.06 - [프로젝트] - [selenium] 웹 크롤링으로 장소와 주소 긁어서 엑셀로 저장하기 (url 안변할때 쓰는 방법)

 

[selenium] 웹 크롤링으로 장소와 주소 긁어서 엑셀로 저장하기 (url 안변할때 쓰는 방법)

이전에 작성했던 포스팅은 url이 변경되는 사이트여서 사용할 수 있었지만, url이 변하지 않아서 다음 버튼을 눌러주면서 스크롤 위치도 조정하면서 해야하는 크롤링에 맞닿았다. 크롤링을 제대

forky-develop.tistory.com

 

이번 포스팅도 마찬가지로 해당 앞전 포스팅에서 참고한 강의를 따라 실습을 진행했음을 알린다.

메타코드의 웹 크롤링 기초 강의로 오늘까지 무료로 수강가능하니 늦기전에 들어보길 바란다!

 

 

 

뉴스 기사 크롤링하기

HTML 소스 따는 방법

 

먼저 전체 카테고리의 오늘 날짜의 제일 상단 뉴스를 눌러서 같이 진행해보고자 한다.

캡쳐본을 보면 크롤링을 경험해보거나, HTML 코드를 통해 이미지를 수집했던 사람들이라면 모두 아는 내용일거라 생각한다.

페이지 검사를 눌러 HTML 소스들을 확인할 수 있고, 위와 같은 것을 처음 따라해보는 사람들을 위해 제목 부분에 코드가 함께 뜨면서 블록 처리된 것을 설명해보자면 페이지 검사에서 뜨는 Elements 옆의 화살표 부분을 누르고 원하는 글자나 이미지를 클릭하면 다음과 같이 되니 한번 해보길 바란다.

 

 

시작 코드

 

먼저 뉴스를 크롤링하기 위해 새로운 ipynb을 생성해준다.

그리고 requests와 BeautifulSoup 라이브러리를 import 해준다.

라이브러리까지 세팅이 완료되었다면, 원하는 뉴스 기사를 클릭해 해당 주소를 복사해오고, 이를 url에 담아준다.

그리고 이 url의 text를 html_doc에 담아주겠다고 설정하면 기본 세팅은 끝났다!

 

 

 

다음으로 해야할 부분은 우리가 수집하고자 하는 부분이 어떤 태그에 담겨있는지를 파악해야한다.

그전에 미리 해두어야 할 부분이 하나 있는데, 현재는 html_doc에 html 코드가 모두 담겨있지만, 위의 사진처럼 정렬이 된 상태가 아니다.

그렇기 때문에 이 부분을 우리가 쉽게 알아보고자 BeautifulSoup을 사용해서 정렬된 상태로 볼 수 있도록 코드를 작성해주자.

soup = BeautifulSoup(html_doc, 'html.parser')
soup

 

 

추출해서 저장하기

 

title1 = soup.find('h4', class_ = 'headline-title')
body1 = soup.find('div', class_ = 'detail-body font-size')

# 딕셔너리 데이터 구조에 저희가 원하는 데이터를 담습니다.
data = {'뉴스 url' : [url], '제목' : [title1.text], '내용' : [body1.text]}

# 저희가 만든 데이터를 데이터프레임 구조로 만듭니다.
df = pd.DataFrame(data)

# CSV 파일로 저장합니다.
df.to_csv('news1_kbs_index_False.csv', index = False)
df.to_csv('news1_kbs_index_True.csv', index = True)

 

위의 코드와 같이 뉴스 제목을 추출하고, 기사 내용을 따로 추출해서 객체에 담아준다.

그리고 해당 뉴스의 url과 제목 부분의 text와 기사 내용 부분의 text를 딕셔너리 구조로 묶어주고, 이를 pandas 데이터 프레임으로 생성해서 표 형식으로 보기 쉽게 만들어 준다.

여기서 index를 T/F로 따로 한 이유는 저장이 어떻게 되는지를 보기 위한 예시이다.

 

 

2개 이상의 기사 크롤링

 

이제 앞전엔 하나의 기사를 csv 파일로 담아오는 것을 해봤으니, 이제는 다수의 기사를 크롤링해올 차례이다.

먼저 url, 타이틀, 내용별로 각각 리스트를 생성해주고, 앞전에 작업한 코드에는 1번째 기사라는 의미고 1을 붙여주자.

그리고 다음 기사를 눌러서 같은 과정을 반복해주는데, 이 때 title이나 body의 class가 동일한 것을 알 수 있다.

여러개를 담기 위해서는 아까 만들었던 리스트에 append를 붙여서 하나씩 넣어 확장시켜줘야 한다.

 

 

 

저장한 csv 파일을 확인해보면 위의 사진과 같이 나온다.

이 때, 내용에 원하는 기사 내용만 나오지 않고 코드가 나왔는데 우리가 위에서 원하는 코드에 text를 붙이지 않았기 때문이다.

따라서 위의 코드를 아래와 같이 수정해서 한다면 타이틀과 내용이 텍스트로 추출되어 우리가 원하는 결과 형식으로 반환될 것이다.

url_list = []
title_list = []
body_list = []

url1 = 'https://news.kbs.co.kr/news/pc/view/view.do?ncd=7910449'
html_doc1 = requests.get(url1).text
soup1 = BeautifulSoup(html_doc1, 'html.parser')
title1 = soup1.find('h4', class_ = 'headline-title').text
body1 = soup1.find('div', class_ = 'detail-body font-size').text

url_list.append(url1)
title_list.append(title1)
body_list.append(body1)

url2 = 'https://news.kbs.co.kr/news/pc/view/view.do?ncd=7910446'
html_doc2 = requests.get(url2).text
soup2 = BeautifulSoup(html_doc2, 'html.parser')
title2 = soup2.find('h4', class_ = 'headline-title').text
body2 = soup2.find('div', class_ = 'detail-body font-size').text

url_list.append(url2)
title_list.append(title2)
body_list.append(body2)

data12 = {'뉴스 url' : url_list, '제목' : title_list, '내용' : body_list}

df12 = pd.DataFrame(data12)
df12.to_csv('news12_kbs.csv', index = False)

 

 

코드 자동화

 

위처럼 2개면 크게 상관없겠지만, 다수의 url을 가지고 하게되면 일일이 코드를 치는 것은 시간낭비일 것이다.

이를 위해 링크만 주어지면 같은 형식을 띄고 있기에 자동으로 돌릴 수 있는 코드를 작성해서 하면 훨씬 효율적이게 된다.

위의 사진과 같이 for 반복문을 통해서 한번의 코드로 짠다면, 훨씬 간편하고 헷갈리지 않게 처리할 수 있다.

url_list = []
title_list = []
body_list = []

urls = ['https://news.kbs.co.kr/news/pc/view/view.do?ncd=7910449'
        ,'https://news.kbs.co.kr/news/pc/view/view.do?ncd=7910446'
]

for url in urls:
    html_doc = requests.get(url).text
    soup = BeautifulSoup(html_doc, 'html.parser')
    title = soup.find('h4', class_ = 'headline-title').text
    body = soup.find('div', class_ = 'detail-body font-size').text

    url_list.append(url)
    title_list.append(title)
    body_list.append(body)

data = {'뉴스 url' : url_list, '제목' : title_list, '내용' : body_list}
df = pd.DataFrame(data)
df.to_csv('news12_kbs_same.csv', index=False)

 

 

날짜 인기 뉴스들 크롤링하기

 

데이터가 담기지 않을 때

 

데이터가 담기지 않은 상황 이전의 코드는 앞서 계속해온 기본코드뿐이라 설명없이 아래에 코드블록을 통해 남겨두겠다.

import requests
from bs4 import BeautifulSoup
import pandas as pd

url = 'https://news.kbs.co.kr/news/pc/category/category.do?ref=pSiteMap#20240311&1'
html_doc = requests.get(url).text
soup = BeautifulSoup(html_doc, 'html.parser')
box_contents = soup.find_all('a', class_ = 'box-content flex-style')
box_contents

 

코드는 다음과 같은 상황인데 box_contents 라는 리스트에 아무것도 담기지 않은 상황이 나왔다.

데이터가 담겨있지 않을 때는 먼저 태그명과 클래스 명이 같은지를 먼저 확인해봐야하는데 우리는 같은 상황이다.

이럴 때, 동적 뷰를 통한 페이지 로드가 이루어지는 자바스크립트를 통해 페이지가 생성된 것인지를 파악해야한다.

JS를 통해 만들어진 페이지일 경우 우리가 크롤링을 하는 것이 페이지가 로드되는 것보다 빠르게 접근되기 때문에 이런 상황이 초래되기도 한다.

 

 

알아보기 쉽게 따로 아래에 작성해두겠다.

더보기
## 데이터가 담겨있지 않은 원인
1. 크롤링하려는 태그들이 잘 설정되어있는지 확인
2. 페이지 소스에 JavaScript가 사용되었는지 확인
- 많은 웹페이지들이 javascript 동적 데이터를 로드

이 경우, 해결책 = Selenium
- Selenium 웹 페이지를 자동으로 제어, 테스트할 수 있는 도구. 직접적으로 웹 브라우저를 제어.
- requests, beautifulsoup으로 크롤링 불가능할 때, 원하는 결과를 가져오지 못할 때 : Selenium

## 정적 페이지 = requests + Beautifulsoup
- 서버로부터 한 번 요펑하면 변하지 않는 형태의 HTML로 작성된 페이지
- 웹 서버는 클라이언트 요청이 들어올 때마다 미리 만들어놓은 HTML 파일을 그대로 반환.
- 서버 측에서 미리 준비가 되어있기 때문에, 클라이언트 측에서 별다른 처리 없이 바로 브라우저에 표시

## 동적 페이지 = Selenium
- 웹 서버로 부터 HTML을 받아온 다음, 브라우저가 해석하고 실행하면서, JavaScript 같은 스크립트 언어를 사용, 동적으로 페이지를 만듦
- 이렇게 생성된 HTML > 데이터를 불러오거나, 저희가 입력하거나 클릭, 스크롤을 할 때 > 화면이 변경되는 등의 이런 상호작용이 필요한 웹페이지에서 사용.

 

 

Selenium 활용하기

 

셀레니움의 경우 앞전의 상황과 같이 동적인 페이지에서도 사용이 가능하다는 장점이 있기 때문에 자주 사용된다.

셀레니움은 주로 크롬의 웹드라이버와 함께 사용하며, 웹드라이버는 자동업데이트가 안되서 업데이트가 될 때마다 다운을 다시 받아야 하는 단점을 웹드라이버 매니저가 보완해준다.

위에서는 계속 Beautifulsoup을 사용했었던 예시를 다뤘기에 셀레니움은 크롬 드라이버와 함께 다운에 대해서만 살짝 언급하고 다음 포스팅에서 계속해서 작성해보겠다.

 

 

728x90