부트캠프

멋쟁이사자처럼 부트캠프 그로스마케팅 4기 27일차_260416

Yuuma 2026. 4. 16. 17:23
Day11 | 데이터 수집 및 전처리 | 크롤링 실습 2

데이터 수집 및 전처리
크롤링 실습 2

1

복습 + pandas 추가 — 구글 뉴스 DataFrame으로 만들기

어제(Day10) 배운 구글 뉴스 크롤링 코드에 pandas가 추가됩니다. CSV로 저장하는 건 똑같지만, 수집한 데이터를 DataFrame이라는 표 형태로도 동시에 만들어두면 이후 분석과 전처리가 훨씬 편해집니다.

📌 pandas란? 파이썬에서 데이터를 엑셀 표처럼 다룰 수 있게 해주는 라이브러리입니다. pd.DataFrame()으로 리스트를 표로 만들고, 정렬·필터·저장을 쉽게 할 수 있습니다.

어제 코드에서 달라진 점

3곳에 pandas 관련 코드가 추가됩니다. 나머지는 완전히 동일합니다.

Python — Google Colab (pandas 추가 버전)
!pip install requests beautifulsoup4 lxml -q

import requests, csv
import pandas as pd       # ★ 추가: DataFrame 만들기 위해
from bs4 import BeautifulSoup
from urllib.parse import quote_plus
from google.colab import files
from datetime import datetime  # ★ 추가: 날짜 변환 위해

search_query = "마케팅"

rss_url  = f"https://news.google.com/rss/search?q={quote_plus(search_query)}&hl=ko&gl=KR&ceid=KR:ko"
response = requests.get(rss_url, headers={"User-Agent": "Mozilla/5.0"})
soup     = BeautifulSoup(response.text, "xml")
items    = soup.find_all("item")

news_list = []  # ★ 추가: DataFrame용 빈 리스트

filename = f"news_{search_query}.csv"
with open(filename, "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["제목", "출처", "날짜", "링크"])
    for idx, item in enumerate(items[:10], start=1):
        title    = item.find("title").text    if item.find("title")   else ""
        source   = item.find("source").text  if item.find("source")  else ""
        pub_date = item.find("pubDate").text if item.find("pubDate") else ""
        link     = item.find("link").text    if item.find("link")    else ""
        if pub_date:
            pub_date = datetime.strptime(pub_date, "%a, %d %b %Y %H:%M:%S GMT").strftime("%Y-%m-%d")
        news_list.append([title, source, pub_date, link])  # ★ 추가
        writer.writerow([title, source, pub_date, link])
        print(f"{idx}. [{source}] {title}")

# ★ 추가: 리스트를 DataFrame(표)으로 변환
df_news = pd.DataFrame(news_list, columns=["title", "source", "pubDate", "link"])
print(df_news)  # 표 형태로 확인

files.download(filename)
pd.DataFrame(리스트, columns=[열 이름])

리스트에 쌓인 데이터를 엑셀 표처럼 구조화합니다.
columns에 각 열의 이름을 지정하면, 이후 df["title"]처럼 열 이름으로 데이터에 접근할 수 있습니다.
CSV에 저장하는 것과 별도로 파이썬 메모리 안에 표로 남아있기 때문에 바로 전처리·분석에 활용할 수 있습니다.


2

네이버 뉴스 공식 API 사용하기 NEW

구글 뉴스 RSS가 "비공식 통로"라면, 네이버 검색 API는 네이버가 공식으로 열어준 창구입니다. 키를 발급받아야 하지만, 더 안정적이고 법적으로도 안전합니다.

RSS 크롤링 vs 네이버 공식 API 비교
두 방식의 핵심 차이 — 오늘은 공식 API를 사용합니다
네이버 API 동작 방식
API는 4단계로 동작합니다 — 키 발급 → 요청 → JSON 응답 → DataFrame 변환

API 키 발급 방법

🔑 네이버 개발자 센터에서 API 키 발급하기

  1. developers.naver.com 접속 후 로그인
  2. 상단 메뉴 → Application → 애플리케이션 등록
  3. 애플리케이션 이름 입력 (예: "뉴스수집테스트")
  4. 사용 API → 검색 체크 → 등록
  5. 발급된 Client IDClient Secret을 코드에 붙여넣기

RSS 태그 vs API JSON 필드 비교

RSS 태그API JSON 키내용
<item>data["items"]기사 하나
<title>item["title"]기사 제목
<link>item["link"]기사 링크
<pubDate>item["pubDate"]발행 날짜
<description>item["description"]기사 요약
(없음)item["originallink"]원본 언론사 링크

전체 코드

실습 2 — 네이버 뉴스 API
Python — Google Colab
# ① API 키를 여기에 붙여넣으세요 (developers.naver.com 에서 발급)
client_id     = "나의 Client ID"
client_secret = "나의 Client Secret"

import requests
import pandas as pd

# ② 네이버 뉴스 검색 API 주소
url = "https://openapi.naver.com/v1/search/news.json"

# ③ 신분증 역할: 내가 발급받은 키를 헤더에 담아서 보냄
headers = {
    "X-Naver-Client-Id":     client_id,
    "X-Naver-Client-Secret": client_secret
}

# ④ 검색 조건 설정
params = {
    "query":   "CRM 후기",   # 검색어 (여기만 바꾸면 됨)
    "display": 30,           # 가져올 기사 수 (최대 100)
    "sort":    "date"         # 정렬 기준: date(최신순) or sim(관련도순)
}

# ⑤ 요청 보내기
response = requests.get(url, headers=headers, params=params)
data     = response.json()   # JSON → 파이썬 딕셔너리로 변환

# ⑥ 기사 목록 추출
rows = []
for item in data["items"]:
    rows.append({
        "title":        item["title"],
        "link":         item["link"],
        "originallink": item.get("originallink"),  # .get(): 없으면 None 반환
        "pubDate":      item.get("pubDate"),
        "description":  item.get("description")
    })

# ⑦ DataFrame으로 변환해서 표 형태로 확인
df_news = pd.DataFrame(rows)
print(df_news)

헷갈리는 부분 짚어보기

item["key"] vs item.get("key")

item["key"]는 해당 키가 없으면 에러가 발생합니다.
item.get("key")는 해당 키가 없으면 None을 반환하고 에러 없이 계속 실행됩니다.
실무에서는 데이터가 빠져있는 경우가 많기 때문에 확신이 없는 필드는 .get()을 쓰는 게 안전합니다.

response.json()

API가 돌려주는 응답은 JSON 형식의 문자열입니다.
.json()을 호출하면 이 문자열을 파이썬 딕셔너리(dictionary)로 자동 변환해줍니다.
RSS에서는 XML을 BeautifulSoup으로 파싱했지만, JSON API는 이 한 줄로 끝납니다.

params 딕셔너리

URL에 검색 조건을 넘기는 방법입니다. requests.get()params=로 넘기면 자동으로 URL에 붙여줍니다.
"display": 30은 30개 가져오기, "sort": "date"는 최신순 정렬, "sort": "sim"은 관련도 높은 순으로 바꿀 수 있습니다.


3

수집된 데이터 전처리하기 (5단계) NEW

API로 데이터를 가져오면 날짜 형식이 이상하거나, HTML 태그가 섞여 있거나, 중복·결측치가 있습니다. 분석에 쓰기 전에 반드시 전처리(Preprocessing)를 거쳐야 합니다.

데이터 전처리 5단계
5단계를 순서대로 실행하면 깔끔한 데이터가 됩니다
Python — 전처리 전체 코드
import pandas as pd
import re

# ① 날짜 형식 변환
# "Wed, 16 Apr 2026 09:00:00 +0900" → "2026-04-16"
df_news["pubDate"] = pd.to_datetime(df_news["pubDate"])
df_news["pubDate"] = df_news["pubDate"].dt.strftime("%Y-%m-%d")

# ② 날짜순 정렬 (최신 기사가 맨 위로)
df_news = df_news.sort_values("pubDate", ascending=False)

# ③ HTML 태그 제거 (<b>CRM</b> → CRM)
df_news["title"]       = df_news["title"].str.replace(r"<.*?>", "", regex=True)
df_news["description"] = df_news["description"].str.replace(r"<.*?>", "", regex=True)

# ④ 중복 기사 제거 (제목 기준, 링크 기준 각각 실행)
df_news = df_news.drop_duplicates(subset=["title"])
df_news = df_news.drop_duplicates(subset=["link"])

# ⑤ 결측치 처리 (비어있는 셀 기본값으로 채우기)
df_news["title"]       = df_news["title"].fillna("제목 없음")
df_news["description"] = df_news["description"].fillna("내용 없음")
df_news["link"]        = df_news["link"].fillna("링크 없음")

# 결과 확인
df_news.head()

각 함수 완전 이해하기

pd.to_datetime() + .dt.strftime()

pd.to_datetime()은 문자열로 된 날짜를 파이썬이 "진짜 날짜"로 인식하게 만듭니다.
그 다음 .dt.strftime("%Y-%m-%d")로 우리가 원하는 형태(2026-04-16)로 다시 문자열로 바꿉니다.
왜 두 단계를 거치냐? to_datetime으로 바꿔야 비로소 날짜 계산·정렬이 가능해지기 때문입니다.

df.sort_values("열이름", ascending=False)

DataFrame의 특정 열을 기준으로 정렬합니다.
ascending=False내림차순(큰 값이 위) → 날짜는 최신이 위로 올라옵니다.
ascending=True로 바꾸면 오름차순(오래된 기사가 위)이 됩니다.

.str.replace(r"<.*?>", "", regex=True)

네이버 API가 반환하는 제목에는 <b>CRM</b>처럼 HTML 태그가 섞여 있습니다.
r"<.*?>"정규표현식(regex)으로, <로 시작해서 >로 끝나는 모든 태그를 의미합니다.
이것을 ""(빈 문자열)로 바꾸면 태그가 깔끔하게 사라집니다.

df.drop_duplicates(subset=["title"])

같은 기사가 여러 번 수집되는 경우 중복을 제거합니다.
subset에 기준이 되는 열을 지정합니다. 제목이 같으면 제거, 링크가 같으면 제거 — 두 번 실행해서 모두 잡습니다.
기본적으로 첫 번째 항목만 남기고 나머지를 삭제합니다.

.fillna("기본값")

데이터에 빈 값(NaN)이 있으면 분석 시 오류가 생깁니다.
.fillna()로 빈 셀에 기본값을 채워서 오류를 예방합니다.
"제목 없음", "내용 없음"처럼 의미 있는 텍스트를 채우는 것이 나중에 데이터를 볼 때 편합니다.

전처리 단계 요약표

단계코드목적
① 날짜 변환pd.to_datetime() + .strftime()날짜를 다루기 쉬운 형태로 통일
② 날짜 정렬sort_values(ascending=False)최신 기사가 위로
③ 태그 제거.str.replace(r"<.*?>", "", regex=True)HTML 태그 제거
④ 중복 제거drop_duplicates(subset=[...])동일 기사 중복 제거
⑤ 결측치 처리.fillna("기본값")빈 셀 채우기

4

네이버 API로 블로그 링크 수집하기 회고조 실습

뉴스 API와 동일한 방식으로, URL 주소만 블로그 검색 엔드포인트로 바꾸면 됩니다. 경쟁사나 키워드에 대한 블로그 포스팅 링크를 한 번에 수집할 때 유용합니다.

📎 엔드포인트(Endpoint)란? API에서 "어떤 데이터를 줄지" 결정하는 주소입니다.
뉴스: /v1/search/news.json  |  블로그: /v1/search/blog.json
주소의 news 부분만 blog로 바꾸면 블로그 검색 결과를 가져올 수 있습니다.
Python — 네이버 블로그 링크 수집
# ① API 키 설정
client_id     = "나의 Client ID"
client_secret = "나의 Client Secret"

import requests
import pandas as pd

# ② 블로그 검색 엔드포인트 (news → blog 로만 바뀜!)
url = "https://openapi.naver.com/v1/search/blog.json"

# ③ 인증 헤더 (뉴스 코드와 완전히 동일)
headers = {
    "X-Naver-Client-Id":     client_id,
    "X-Naver-Client-Secret": client_secret
}

# ④ 검색 조건
params = {
    "query":   "CRM 후기",  # 검색어를 여기서 바꾸세요
    "display": 30,
    "sort":    "date"
}

# ⑤ 요청 및 응답
response = requests.get(url, headers=headers, params=params)
data     = response.json()

# ⑥ 블로그 링크만 수집
links = []
for item in data["items"]:
    links.append(item["link"])

# ⑦ DataFrame으로 만들어 확인
df_links = pd.DataFrame(links, columns=["url"])
print(df_links)

더 많은 정보를 함께 수집하고 싶다면

링크만 수집하는 대신, 블로그 제목·날짜·요약까지 한 번에 수집하는 확장 버전입니다.

Python — 블로그 전체 정보 수집 (확장 버전)
rows = []
for item in data["items"]:
    rows.append({
        "제목":      item.get("title", ""),
        "링크":      item.get("link", ""),
        "블로그명":   item.get("bloggername", ""),
        "발행일":    item.get("postdate", ""),
        "요약":      item.get("description", "")
    })

df_blog = pd.DataFrame(rows)

# HTML 태그 제거 (제목, 요약에 섞여있음)
df_blog["제목"] = df_blog["제목"].str.replace(r"<.*?>", "", regex=True)
df_blog["요약"]  = df_blog["요약"].str.replace(r"<.*?>", "", regex=True)

df_blog.head(10)
💡 블로그 API 활용 아이디어
경쟁사 이름으로 검색 → 소비자가 직접 쓴 후기 링크 한 번에 수집
우리 제품명으로 검색 → 자사 브랜드 언급 블로그 모니터링
키워드로 검색 → 콘텐츠 기획 시 경쟁 포스팅 파악

뉴스 vs 블로그 API 비교

항목뉴스 API블로그 API
엔드포인트/search/news.json/search/blog.json
출처언론사 기사네이버/외부 블로그
고유 필드originallink, sourcebloggername, postdate
주요 용도뉴스 모니터링, 트렌드 파악소비자 후기, 브랜드 언급 수집