- 수업 내용 리마인드 및 아카이빙 목적의 업로드
Q. 네이버 블로그에서 '특정 키워드(청년취업사관학교)'와 '날짜 범위(20240101~20240731)'에 해당하는 게시물들을 자동으로 수집하고, 각 게시물의 "제목", "작성자 닉네임", "작성일", "본문 내용", "URL"을 추출하여 CSV 파일로 저장하는 코드를 작성하세요.
A. 네이버 블로그 데이터 수집 스크립트
전체 코드
import requests
from bs4 import BeautifulSoup
import pandas as pd
import json
def clean_text(text):
return text.replace("\n", "").replace("\u200b", "").replace("\xa0", "").replace("\t", "").replace("\r", "")
def get_blog_item(url):
tmp = url.split("/")
url = f'https://blog.naver.com/PostView.naver?blogId={tmp[-2]}&logNo={tmp[-1]}'
try:
res = requests.get(url)
res.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Failed to retrieve blog post: {url}, error: {e}")
return None
nick = tmp[-2]
soup = BeautifulSoup(res.text, "html.parser")
try:
if soup.select_one(".se-title-text"):
title = soup.select_one(".se-title-text").text
date = soup.select_one(".se_publishDate").text
content = soup.select_one(".se-main-container").text
else:
title = soup.select_one(".se_title h3").text
date = soup.select_one(".se_publishDate").text
content = soup.select(".se_component_wrap")[1].text
title = clean_text(title)
content = clean_text(content)
return title, nick, date, content, url
except AttributeError as e:
print(f"Failed to parse blog post: {url}, error: {e}")
return None
def get_naver_blog(keyword, startdate, enddate, to_csv=False):
url = f'https://s.search.naver.com/p/review/48/search.naver?ssc=tab.blog.all&api_type=8&query={keyword}&start=1&nx_search_query=&nx_and_query=&nx_sub_query=&ac=1&aq=0&spq=0&sm=tab_opt&nso=so%3Add%2Cp%3Afrom{startdate}to{enddate}&prank=30&ngn_country=KR&lgl_rcode=09170128&fgn_region=&fgn_city=&lgl_lat=37.5278&lgl_long=126.9602&enlu_query=IggCADqCULhpAAAAj0RP67RmqTWRq3DkdYxhcV7F5RKpJAPG1d9ZSyMVgoc%3D&abt=&retry_count=0'
ret = []
while url:
try:
res = requests.get(url)
res.raise_for_status()
res_dic = json.loads(res.text)
except requests.exceptions.RequestException as e:
print(f"Failed to retrieve search results: {url}, error: {e}")
break
except json.JSONDecodeError as e:
print(f"Failed to parse JSON: {url}, error: {e}")
break
soup = BeautifulSoup(res_dic.get('contents', ''), 'html.parser')
url = res_dic.get('nextUrl')
for item in soup.select('.title_area > a'):
try:
blog_data = get_blog_item(item['href'])
if blog_data:
ret.append(blog_data)
except Exception as e:
print(f"Failed to process blog item: {item['href']}, error: {e}")
if not url:
break
df = pd.DataFrame(ret, columns=['title', 'nick', 'date', 'content', 'url'])
if to_csv:
df.to_csv(f'blog_{keyword}_{startdate}_{enddate}.csv', index=False)
get_naver_blog('청년취업사관학교', '20240101', '20240731', to_csv=True)
코드 설명
1. 필요한 모듈 임포트
import requests
from bs4 import BeautifulSoup
import pandas as pd
import json
- requests: 웹 페이지의 내용을 가져오기 위해 사용됩니다.
- BeautifulSoup: HTML 파싱을 위해 사용되는 라이브러리입니다.
- pandas: 데이터를 구조화된 형태(예: DataFrame)로 관리하고, CSV 파일로 저장하기 위해 사용됩니다.
- json: JSON 형식의 데이터를 다루기 위해 사용됩니다.
2. 텍스트 정리 함수 (clean_text)
def clean_text(text):
return text.replace("\n", "").replace("\u200b", "").replace("\xa0", "").replace("\t", "").replace("\r", "")
- 이 함수는 텍스트에서 불필요한 공백 문자나 특수 문자를 제거하여 텍스트를 깔끔하게 정리합니다.
3. 블로그 게시물 정보 추출 함수 (get_blog_item)
def get_blog_item(url):
tmp = url.split("/")
url = f'https://blog.naver.com/PostView.naver?blogId={tmp[-2]}&logNo={tmp[-1]}'
try:
res = requests.get(url)
res.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Failed to retrieve blog post: {url}, error: {e}")
return None
- url.split("/"): 블로그 URL을 슬래시(/)를 기준으로 나눕니다.
- f'https://blog.naver.com/PostView.naver?blogId={tmp[-2]}&logNo={tmp[-1]}': 네이버 블로그의 포스트 뷰 URL 형식에 맞게 새로운 URL을 생성합니다.
- requests.get(url): 블로그 게시물의 HTML 페이지를 요청합니다.
- res.raise_for_status(): 요청이 성공적이지 않으면 예외를 발생시킵니다.
nick = tmp[-2]
soup = BeautifulSoup(res.text, "html.parser")
- nick = tmp[-2]: 블로그 작성자의 닉네임을 추출합니다.
- BeautifulSoup(res.text, "html.parser"): HTML 문서를 파싱하여 soup 객체로 만듭니다.
try:
if soup.select_one(".se-title-text"):
title = soup.select_one(".se-title-text").text
date = soup.select_one(".se_publishDate").text
content = soup.select_one(".se-main-container").text
else:
title = soup.select_one(".se_title h3").text
date = soup.select_one(".se_publishDate").text
content = soup.select(".se_component_wrap")[1].text
- 블로그 게시물의 제목, 작성일자, 내용이 위치하는 HTML 태그를 선택합니다. 두 가지 형식이 존재할 수 있어 조건문으로 분기 처리합니다.
title = clean_text(title)
content = clean_text(content)
return title, nick, date, content, url
except AttributeError as e:
print(f"Failed to parse blog post: {url}, error: {e}")
return None
- clean_text 함수를 사용해 텍스트를 정리한 후, 제목, 작성자, 작성일, 내용, URL을 반환합니다.
- 만약 필요한 정보를 찾지 못하면 AttributeError 예외를 처리하고 None을 반환합니다.
4. 네이버 블로그 검색 결과 가져오기 (get_naver_blog)
def get_naver_blog(keyword, startdate, enddate, to_csv=False):
url = f'https://s.search.naver.com/p/review/48/search.naver?ssc=tab.blog.all&api_type=8&query={keyword}&start=1&nx_search_query=&nx_and_query=&nx_sub_query=&ac=1&aq=0&spq=0&sm=tab_opt&nso=so%3Add%2Cp%3Afrom{startdate}to{enddate}&prank=30&ngn_country=KR&lgl_rcode=09170128&fgn_region=&fgn_city=&lgl_lat=37.5278&lgl_long=126.9602&enlu_query=IggCADqCULhpAAAAj0RP67RmqTWRq3DkdYxhcV7F5RKpJAPG1d9ZSyMVgoc%3D&abt=&retry_count=0'
- 네이버 블로그 검색 URL을 생성합니다. 검색어와 시작일, 종료일을 포함한 URL을 만듭니다.
ret = []
while url:
try:
res = requests.get(url)
res.raise_for_status()
res_dic = json.loads(res.text)
except requests.exceptions.RequestException as e:
print(f"Failed to retrieve search results: {url}, error: {e}")
break
except json.JSONDecodeError as e:
print(f"Failed to parse JSON: {url}, error: {e}")
break
- 블로그 검색 결과를 가져와 JSON으로 파싱합니다. 요청에 실패하거나 JSON 파싱에 실패하면 반복을 중단합니다.
soup = BeautifulSoup(res_dic.get('contents', ''), 'html.parser')
url = res_dic.get('nextUrl')
- 검색 결과에서 블로그 게시물 링크를 추출할 수 있도록 HTML을 파싱합니다. 다음 페이지가 있으면 nextUrl을 업데이트합니다.
for item in soup.select('.title_area > a'):
try:
blog_data = get_blog_item(item['href'])
if blog_data:
ret.append(blog_data)
except Exception as e:
print(f"Failed to process blog item: {item['href']}, error: {e}")
- 각 블로그 게시물의 링크를 순회하며 get_blog_item 함수를 사용해 게시물 정보를 가져옵니다. 가져온 정보는 ret 리스트에 추가됩니다.
if not url:
break
- 더 이상 검색 결과가 없으면 반복을 종료합니다.
5. 데이터프레임 생성 및 CSV 저장
df = pd.DataFrame(ret, columns=['title', 'nick', 'date', 'content', 'url'])
if to_csv:
df.to_csv(f'blog_{keyword}_{startdate}_{enddate}.csv', index=False)
- 수집한 블로그 데이터를 pandas.DataFrame으로 구조화합니다.
- to_csv가 True로 설정되면, 데이터프레임을 CSV 파일로 저장합니다.
6. 함수 호출
get_naver_blog('청년취업사관학교', '20240101', '20240731', to_csv=True)
- 키워드 "청년취업사관학교"에 대해 2024년 1월 1일부터 2024년 7월 31일까지의 블로그 게시물을 수집하고, 결과를 CSV 파일로 저장합니다.
'+ 개발' 카테고리의 다른 글
뉴스 크롤링(#네이버 뉴스)_코드 설명 (0) | 2024.08.31 |
---|---|
논문 리뷰(#텍스트 마이닝 #금통위 의사록 분석)_Gen.AI (3) | 2024.08.30 |
Pandas로 데이터 분석하기 (0) | 2024.08.29 |
Numpy로 데이터 처리하기 (1) | 2024.08.28 |
데이터 시각화 기초 (1) | 2024.08.26 |