- 수업 내용 리마인드 및 아카이빙 목적의 업로드
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("\t", "").replace("\r", "")
def get_news_item(url):
try:
res = requests.get(url)
res.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Failed to retrieve news item: {url}, error: {e}")
return None
soup = BeautifulSoup(res.text, "html.parser")
try:
title = soup.select_one("h2#title_area").text
media = soup.select_one(".media_end_head_top_logo img")["title"]
date = soup.select_one(".media_end_head_info_datestamp_time")["data-date-time"]
content = clean_text(soup.select_one("#newsct_article").text)
return title, media, date, content, url
except AttributeError as e:
print(f"Failed to parse news item: {url}, error: {e}")
return None
def get_naver_news(keyword, startdate, enddate, to_csv=False):
ret = []
for d in pd.date_range(startdate, enddate, freq='D'):
page = 1
print(f"Processing date: {d}")
while True:
start = (page - 1) * 10 + 1
url = f"https://s.search.naver.com/p/newssearch/search.naver?de={d.strftime('%Y.%m.%d')}&ds={d.strftime('%Y.%m.%d')}&eid=&field=0&force_original=&is_dts=0&is_sug_officeid=0&mynews=0&news_office_checked=&nlu_query=&nqx_theme=&nso=%26nso%3Dso%3Add%2Cp%3Afrom{d.strftime('%Y%m%d')}to{d.strftime('%Y%m%d')}%2Ca%3Aall&nx_and_query=&nx_search_hlquery=&nx_search_query=&nx_sub_query=&office_category=0&office_section_code=0&office_type=0&pd=3&photo=0&query={keyword}&query_original=&service_area=0&sort=1&spq=0&start={start}&where=news_tab_api&nso=so:dd,p:from{d.strftime('%Y%m%d')}to{d.strftime('%Y%m%d')},a:all"
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
li = res_dic.get('contents', [])
if len(li) == 0:
break
for item in li:
soup = BeautifulSoup(item, 'html.parser')
a_tags = soup.select("div.info_group a")
if len(a_tags) == 2:
news_data = get_news_item(a_tags[1]['href'])
if news_data:
ret.append(news_data)
page += 1
df = pd.DataFrame(ret, columns=["title", "media", "date", "content", "url"])
if to_csv:
df.to_csv(f"{keyword}_{startdate.replace('.','')}_{enddate.replace('.','')}.csv", index=False)
return df
get_naver_news("청년취업사관학교", "2024.01.01", "2024.07.31", to_csv=True)
코드 설명
1. 필요한 라이브러리 임포트
import requests
from bs4 import BeautifulSoup
import pandas as pd
import json
- requests: HTTP 요청을 보내 웹 페이지의 내용을 가져오는 데 사용됩니다.
- BeautifulSoup: HTML 및 XML 파일을 파싱하고 탐색하는 데 사용됩니다. 주로 웹 스크래핑에 사용되며, 이 코드에서는 네이버 뉴스 페이지의 HTML을 파싱하는 데 사용됩니다.
- pandas: 데이터 분석을 위한 라이브러리로, 데이터프레임 형태로 데이터를 저장하고 조작하는 데 사용됩니다.
- json: JSON 데이터를 파싱하는 데 사용됩니다. 이 코드는 json.loads를 사용해 서버로부터 받은 JSON 데이터를 딕셔너리로 변환합니다.
2. 텍스트 정리 함수 (clean_text)
def clean_text(text):
return text.replace("\n", "").replace("\t", "").replace("\r", "")
- 문자열에서 불필요한 공백 문자(\n, \t, \r)를 제거하는 함수입니다. 뉴스 본문 내용을 깔끔하게 정리하는 데 사용됩니다.
3. 뉴스 정보 추출 함수 (get_news_item)
def get_news_item(url):
try:
res = requests.get(url)
res.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"Failed to retrieve news item: {url}, error: {e}")
return None
soup = BeautifulSoup(res.text, "html.parser")
try:
title = soup.select_one("h2#title_area").text
media = soup.select_one(".media_end_head_top_logo img")["title"]
date = soup.select_one(".media_end_head_info_datestamp_time")["data-date-time"]
content = clean_text(soup.select_one("#newsct_article").text)
return title, media, date, content, url
except AttributeError as e:
print(f"Failed to parse news item: {url}, error: {e}")
return None
- 주어진 뉴스 URL에서 뉴스의 제목, 매체 이름, 작성일, 본문 내용을 추출하여 튜플로 반환합니다.
- 작동 방식:
- HTTP 요청: requests.get으로 URL에 대해 GET 요청을 보내고, raise_for_status()로 요청이 성공했는지 확인합니다.
- HTML 파싱: BeautifulSoup을 사용해 페이지의 HTML을 파싱합니다.
- 데이터 추출:
- 제목: h2#title_area 요소에서 뉴스 제목을 추출합니다.
- 매체 이름: .media_end_head_top_logo img 요소의 title 속성에서 매체 이름을 추출합니다.
- 작성일: .media_end_head_info_datestamp_time 요소의 data-date-time 속성에서 작성일을 추출합니다.
- 본문 내용: #newsct_article 요소에서 본문 내용을 추출하고, 불필요한 공백을 제거합니다.
- 예외 처리: 뉴스 아이템을 가져오거나 파싱하는 과정에서 오류가 발생하면, 오류 메시지를 출력하고 None을 반환합니다.
4. 네이버 뉴스 검색 결과 가져오기 (get_naver_news)
def get_naver_news(keyword, startdate, enddate, to_csv=False):
ret = []
for d in pd.date_range(startdate, enddate, freq='D'):
page = 1
print(f"Processing date: {d}")
while True:
start = (page - 1) * 10 + 1
url = f"https://s.search.naver.com/p/newssearch/search.naver?de={d.strftime('%Y.%m.%d')}&ds={d.strftime('%Y.%m.%d')}&eid=&field=0&force_original=&is_dts=0&is_sug_officeid=0&mynews=0&news_office_checked=&nlu_query=&nqx_theme=&nso=%26nso%3Dso%3Dd d%2Cp%3Afrom{d.strftime('%Y%m%d')}to{d.strftime('%Y%m%d')}%2Ca%3Aall&nx_and_query=&nx_search_hlquery=&nx_search_query=&nx_sub_query=&office_category=0&office_section_code=0&office_type=0&pd=3&photo=0&query={keyword}&query_original=&service_area=0&sort=1&spq=0&start={start}&where=news_tab_api&nso=so:dd,p:from{d.strftime('%Y%m%d')}to{d.strftime('%Y%m%d')},a:all"
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
li = res_dic.get('contents', [])
if len(li) == 0:
break
for item in li:
soup = BeautifulSoup(item, 'html.parser')
a_tags = soup.select("div.info_group a")
if len(a_tags) == 2:
news_data = get_news_item(a_tags[1]['href'])
if news_data:
ret.append(news_data)
page += 1
df = pd.DataFrame(ret, columns=["title", "media", "date", "content", "url"])
if to_csv:
df.to_csv(f"{keyword}_{startdate.replace('.','')}_{enddate.replace('.','')}.csv", index=False)
return df
- 주어진 키워드와 날짜 범위에 해당하는 네이버 뉴스 기사를 수집하여 데이터프레임에 저장하고, 필요시 CSV 파일로 저장합니다.
- 작동 방식:
- 날짜 범위 설정: pd.date_range를 사용해 startdate부터 enddate까지의 날짜 범위를 생성합니다.
- 페이지 순회:
- 각 날짜에 대해 뉴스 목록 페이지를 순회합니다. 페이지마다 시작 인덱스를 계산하고, 이를 포함한 URL을 생성합니다.
- HTTP 요청: requests.get으로 URL에 대해 GET 요청을 보내고, raise_for_status()로 요청이 성공했는지 확인합니다.
- JSON 파싱: json.loads를 사용해 서버 응답을 JSON 형식으로 파싱합니다.
- 뉴스 목록 추출: JSON 데이터에서 contents 키를 통해 뉴스 목록을 가져옵니다.
- 뉴스 목록이 비어 있으면 해당 날짜의 처리 루프를 종료합니다.
- 각 뉴스 항목에 대해 HTML을 파싱하고, div.info_group a에서 두 번째 링크(기사 링크)를 선택해 뉴스 URL을 추출합니다.
- 추출한 URL을 get_news_item 함수로 처리하여 데이터를 수집합니다.
- 다음 페이지로 이동하기 위해 page를 증가시킵니다.
- 데이터 저장: 수집된 데이터를 pandas 데이터프레임에 저장합니다. to_csv=True인 경우, 결과를 CSV 파일로 저장합니다.
5. 함수 호출
get_naver_news("청년취업사관학교", "2024.01.01", "2024.07.31", to_csv=True)
- get_naver_news 함수를 실행하여 "청년취업사관학교"라는 키워드를 포함한 뉴스 기사를 2024년 1월 1일부터 2024년 7월 31일까지 수집하고, 결과를 CSV 파일로 저장합니다.
'+ 개발' 카테고리의 다른 글
Streamlit으로 데이터 분석 및 시각화 (0) | 2024.09.02 |
---|---|
논문 리뷰(#텍스트 마이닝 #뉴스 분석 #금융 시장 변동성)_Gen.AI (6) | 2024.09.01 |
논문 리뷰(#텍스트 마이닝 #금통위 의사록 분석)_Gen.AI (3) | 2024.08.30 |
블로그 크롤링(#네이버 블로그)_코드 설명 (2) | 2024.08.30 |
Pandas로 데이터 분석하기 (0) | 2024.08.29 |