ABC부트캠프

[11일차] 네이버 기사 수집 및 시각화

수야! 2025. 7. 7. 23:11

 

 

 

데이터 분석 및 시각화 4DAY

 

으아ㅏㅏ... 벌써 월요일 이라니..시간이 정말정말 빠르군요 😭

주말에 신나게 놀았으니 다시 열심히 살아봐야죠!

초롱초롱 눈뜨기!!!

 

오늘은 데이터 분석 및 시각화 4일차 입니다.

이번주 부터는 데이터 수집도 한다고 하는데요. 처음해보는 건 언제나 설레군요ㅎㅎ

힘차게 시작해봅시다! GOGO!

 

01. HTML 기본기 다지기

1. 인터넷 vs 웹

  • 인터넷: 물리적 연결망(Network)
  • 웹: 콘텐츠(웹페이지) 연결망(Application)


2. 클라이언트/서버 역할

  • 클라이언트: 요청(Request)
  • 서버: 응답(Response)

3. 웹 서비스 흐름

1. 요청(Request) → 2. 처리(Static vs Dynamic) → 3. 응답(Response) → 4. 렌더링(Rendering)


4. 정적 vs 동적 페이지

  • 정적: 미리 만들어둔 HTML/CSS/JS
  • 동적: 요청 시 서버 프로그래밍(JSP/PHP/ASP)으로 생성

5. 프론트엔드/백엔드/풀스택

  • 프론트엔드: HTML, CSS, JavaScript
  • 백엔드: 서버 언어, DB 관리
  • 풀스택: 양쪽 모두(Node.js, React 등)

6. HTML·CSS·JavaScript 역할 구분

  • HTML (Structure): 문서의 뼈대
  • CSS (Presentation): 디자인·레이아웃
  • JavaScript (Behavior): 동적 동작

7. HTML 문서 기본 구조

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>문서 제목</title>
  <meta name="keywords" content="html5, 웹표준">
  <meta name="description" content="HTML5 웹 표준 공부">
  <meta name="author" content="작성자">
</head>
<body>
  <!-- 실제 화면에 표시될 콘텐츠 -->
</body>
</html>

 


오늘은 정적 웹페이지를 이용해서 크롤링을 해 볼 예정입니다.

정적 웹페이지에서 코드를 확인을 하는 방법은  F12를 누르시거나 마우스 오른쪽을 클릭 후 페이지 소스보기를 통해서도 가능합니다!

 

 

02. 텍스트와 관련 태그들

1. 텍스트 블록 태그

<h1>제목</h1>
<p>단락 내용</p>
<hr>
<blockquote>인용문</blockquote>
<pre>  공백과
줄바꿈을
그대로 표시</pre>
  • <h1>~<h6>: 제목 계층적 표현(h1 가장 큼)
  • <p>: 문단 구분, 전후로 빈 줄 생성
  • <hr>: 수평 구분선(주제 전환)
  • <blockquote>: 들여쓰기된 인용문 삽입
  • <pre>: 공백·줄바꿈 그대로 유지, 주로 코드 표시에 사용

2. 인라인 강조 및 그룹화

<strong>강조된 굵은 텍스트</strong>
<em>강조된 이탤릭</em>
<mark>하이라이트</mark>
<span class="blue">인라인 컨테이너</span>
  • <strong>/<b>: 굵게 표시(strong은 의미적 강조)
  • <em>/<i>: 이탤릭체(em은 의미적 강조)
  • <mark>: 배경 색 강조(형광펜 효과)
  • <span>: 인라인 컨테이너, 스타일·스크립트 적용용 [3주차] 텍스트 관련 태그 및 이미지와 …

3. 목록 태그

<ul>
  <li>순서 없는 목록</li>
</ul>
<ol type="a" start="3">
  <li>순서 있는 목록</li>
</ol>
<dl>
  <dt>용어</dt><dd>설명</dd>
</dl>
  • <ul>/<ol>: 불릿/숫자 목록, type·start 속성으로 커스터마이즈
  • <li>: 목록 아이템, 닫는 태그 생략 가능
  • <dl>/<dt>/<dd>: ‘용어-설명’ 쌍의 설명 목록 [3주차] 텍스트 관련 태그 및 이미지와 …

4. 표 태그

<table>
  <caption>표 제목</caption>
  <thead>…</thead><tbody>…</tbody><tfoot>…</tfoot>
</table>
  • <table>, <tr>, <th>, <td>: 기본 구조
  • <caption>/<colgroup>/<col>: 제목·열 그룹화
  • <thead>/<tbody>/<tfoot>: 구조 분리로 접근성·스크롤 제어 용이
  • colspan/rowspan: 셀 병합

 

03. 이미지와 하이퍼링크

1. 이미지 삽입 태그

<figure>
  <img src="img.jpg" alt="설명 텍스트" width="250">
  <figcaption>이미지 설명</figcaption>
</figure>
  • <img>: src, alt 필수, width/height로 표시 크기만 조정
  • <figure>/<figcaption>: 이미지+캡션 묶음, 문맥 제공·접근성 향상 [3주차] 텍스트 관련 태그 및 이미지와 …

2.. 하이퍼링크 태그

<a href="https://example.com" target="_blank">외부 링크</a>
<a href="#section1">페이지 내 이동</a>
<img src="map.jpg" usemap="#mymap">
<map name="mymap"><area shape="rect" coords="…" href="…"></map>
  • <a>: href 필수, target="_blank"로 새 탭/창
  • 페이지 내 앵커: id + #id
  • 이미지맵: <map>/<area>로 이미지 영역별 링크 지정 [3주차] 텍스트 관련 태그 및 이미지와 …

3. SVG 삽입

<img src="icon.svg" alt="아이콘">
<!-- 또는 -->
<svg width="100" height="100">…</svg>
  • 벡터 기반 이미지(무한 확대·축소에도 선명)
  • 로고·아이콘·차트 등에 활용

 

04. 폼 관련 태그들

1. <form>: 폼의 기본 틀

<form action="process.php" method="post">
  <!-- 폼 요소들 -->
</form>
  • action: 제출된 데이터를 처리할 서버 스크립트 지정
  • method: get 또는 post 선택
 

2. 레이블 연결: <label>

<label for="user-id">아이디</label>
<input type="text" id="user-id">

또는

<label>비밀번호<input type="password"></label>
  • 입력 필드에 텍스트 레이블 부여
  • 클릭 시 해당 입력으로 포커스 이동
 

3. 그룹화: <fieldset> & <legend>

<fieldset>
  <legend>개인 정보</legend>
  <!-- 요소들 -->
</fieldset>
  • 관련 폼 요소를 박스로 묶고 제목 지정
 

4. <input>: 주요 타입

<input type="email" required placeholder="you@site.com">
<input type="number" min="1" max="10" step="1">
<input type="radio" name="opt" value="A">
  • 텍스트 계열: text, password, search, url, email, tel, hidden
  • 숫자/범위: number (스핀박스), range (슬라이더)
  • 선택형: radio (단일), checkbox (다중), color (색상 선택)
  • 날짜/시간: date, month, week, time, datetime-local
  • 버튼류: submit, reset, image

 


5. <input> 부가 속성

<input type="text" maxlength="8" required>
  • autofocus: 페이지 로드시 자동 포커스
  • placeholder: 힌트 텍스트
  • readonly: 읽기 전용
  • required: 필수 입력
  • min/max/step: 수치·날짜·시간 입력 제한
  • size/minlength/maxlength: 텍스트 입력 길이 제어
 

6. 선택 목록

<select>
  <optgroup label="공과대학">
    <option value="computer">컴퓨터공학과</option>
  </optgroup>
</select>
<input list="majors">
<datalist id="majors">
  <option value="문법"></option>
</datalist>
  • 드롭다운: <select> + <option>
  • 옵션 그룹: <optgroup>
  • 자동완성 목록: <datalist> + <option>
 

7. 여러 줄 입력: <textarea>

<textarea rows="5" cols="40" placeholder="내용 입력"></textarea>
  • 게시판 글, 메모 등 다중 행 텍스트 박스

8. 버튼 커스터마이징: <button>

<button type="submit" class="subm">
  <img src="tick.png" alt=""> 전송하기
</button>
  • <button> 태그로 이미지·텍스트·HTML 자유 구성
 

9. 출력 및 진행 표시

<output name="sum">0</output>
<progress value="30" max="100"></progress>
<meter value="0.5" optimum="0.8"></meter>
  • 계산 결과: <output>
  • 진행 상태: <progress>
  • 비율 표시: <meter>

 

 

05. CSS기초

1. 스타일과 스타일 시트

<!-- 내부 스타일 시트 -->
<head>
  <style>
    p { color: blue; font-size: 0.9em; }
  </style>
</head>

<!-- 외부 스타일 시트 -->
<link rel="stylesheet" href="css/style.css">

<!-- 인라인 스타일 -->
<p style="color: red;">인라인 예시</p>
  • HTML과 디자인을 완전히 분리해 유지보수성 향상
  • 스타일 시트 형식: 선택자 { 속성: 값; }
  • 내부(<style>), 외부(<link>), 인라인(style=) 적용 가능

 


2. 주요 선택자

/* 전체 선택자 */
* { margin: 0; padding: 0; }

/* 태그 선택자 */
h2 { color: brown; }

/* 클래스 선택자 */
.bluetext { color: blue; }

/* ID 선택자 */
#container { width: 600px; }

/* 그룹 선택자 */
h1, h2, p { line-height: 1.5; }
  • *: 모든 요소 대상, 주로 브라우저 기본 여백 리셋
  • 태그, 클래스(.), ID(#), 그룹(,)별로 범위와 재사용성 조절


3. 캐스캐이딩(Cascading)

<style>
  p { color: blue; }             /* 태그 스타일 */
  .note { color: green; }         /* 클래스 스타일 */
  #main p { color: purple; }      /* 구체적 선택자 */
</style>

<!-- 인라인이 최우선 -->
<p id="main" class="note" style="color: red;">
  최종 색상: 빨강
</p>
  • 우선순위: 인라인 > ID > 클래스 > 태그
  • !important로 강제 우선 적용 가능
  • 동일 명시도 시 나중에 선언된 규칙이 적용 (소스 순서)
  • 부모→자식 상속: 글자 색처럼 일부 속성만 전달[5주차] CSS 기초

4. CSS3 & 모듈, 벤더 접두사

.box:hover {
  /* 표준 속성 */
  transform: rotate(15deg);
  /* 벤더 접두사 */
  -webkit-transform: rotate(15deg);
  -moz-transform: rotate(15deg);
}
  • CSS3는 모듈별로 분리된 기능 집합
  • 표준화 전 실험적 속성은 -webkit-, -moz-, -ms-, -o- 접두사 필요
  • prefixfree.js 로 자동화 가능[5주차] CSS 기초

 

06. 네이버 언론사별 랭킹뉴스 크롤링 및 데이터 시각화

1. 패키치 설치 및 임포트

!pip install koreanize-matplotlib
!pip install konlpy

from urllib.request import urlopen
from bs4 import BeautifulSoup

import pandas as pd
import datetime
from pytz import timezone

import warnings
warnings.filterwarnings('ignore')

 

2. 네이버 언론사별 랭킹 뉴스 -많이 본 뉴스 크롤링

# 1) 데이터 프레임 준비하기
data = pd.DataFrame(columns=['언론사명', '순위', '기사제목', '기사링크', '수집일자'])

# 2) 언론사별 랭킹뉴스 URL(접속 주소)
url = 'https://news.naver.com/main/ranking/popularDay.naver'

# 3) URL 접속하여 html 태그 가져오기
html = urlopen(url)

# 4) html 태그 파싱하여 변환
soup = BeautifulSoup(html, 'html.parser')

# 5) 랭킹 뉴스 정보가 들어있는 div만 추출 -> rankingnews_box
div = soup.find_all('div', {'class':'rankingnews_box'})

# 6) 랭킹 뉴스 언론사명, 기사 제목, 상세링크 추출
for index_div in range(len(div)):

  # 언론사 추출 .find('태그명':'클래스명')
  strong = div[index_div].find('strong', {'class':'rankingnews_name'})
  press = strong.text

  # 5개의 순위 기사 정보 추출 ul 태그 -> rankingnews_list
  ul = div[index_div].find_all('ul', {'class':'rankingnews_list'})
  for index_r in range(len(ul)):
    li = ul[index_r].find_all('li')

    for index_l in range(len(li)):

      try:

        # 순위 추출 em -> list_ranking_num
        rank = li[index_l].find('em', {'class':'list_ranking_num'}).text

        # 타이틀 추출 a -> list_title
        title = li[index_l].find('a', {'class':'list_title'}).text

        # 상세링크 추출 a -> list_title, href 속성 정보로 추출
        link = li[index_l].find('a', {'class':'list_title'}).attrs['href']

        # 데이터프레임에 담기
        temp_df = pd.DataFrame({'언론사명': press,
                                '순위': rank,
                                '기사제목': title,
                                '기사링크': link,
                                '수집일자': datetime.datetime.now(timezone('Asia/Seoul'))},
                               index=['순위'])

        data = pd.concat([data, temp_df], ignore_index=True)

      except:
        pass

      print('complets of',rank,':',title)
print('-'*50)
print(data.info())

 

3. 크롤링한 데이터 저장하기

data.to_csv('네이버에랭킹뉴스_많이본뉴스_20250707.csv', encoding='utf-8-sig', index=False)

 

4. 크롤링한 데이터 시각화

import matplotlib.pyplot as plt
import koreanize_matplotlib

import konlpy
from wordcloud import WordCloud

#1. 워드클라우드를 위한 전처리
# 기사제목을 텍스트뭉치로 변환해서 워드 클라우드 시각화
text = ' '.join(title for title in data['기사제목'].astype(str))
text

#2.워드클라우드 시각화
font_path = '/content/BMDOHYEON_ttf.ttf'

wc = WordCloud(width=1000, height=700, font_path=font_path).generate(text)

plt.axis('off')
plt.imshow(wc, interpolation='bilinear')
plt.show()

 

불용어 리스트를 만들어서 삭제도 가능하니 불필요한 단어는 삭제해서 시각화 시키면됩니다!

코드 첨부해 놓겠습니다.

komoran = konlpy.tag.Komoran()
words = komoran.nouns(text)
words

# 불용어 리스트 만들어서 삭제하기
stopwords = ['속보','단독','위','이','것']

def remove_stopwords(words):
  return [word for word in words if word not in stopwords]
  
words = remove_stopwords(words)
words

text = ' '.join(title for title in words)
text

font_path = '/content/BMDOHYEON_ttf.ttf'

wc = WordCloud(width=1000, height=700, font_path=font_path).generate(text)

plt.axis('off')
plt.imshow(wc, interpolation='bilinear')
plt.show()

 

마무리

으아아아ㅏㅇ아아아아ㅏ앙앍 오늘은 진짜진짜 피곤했던 하루였습니다...

오늘은 웹의 기초부터 데이터 크롤링, 시각화까지 한 번에 배워서 머릿속이 꽉 찬 느낌입니다!!!!!!!!!!!!!!!

 

HTML 태그 하나하나가 페이지를 어떻게 구성하는지 직접 확인해보니, 내가 곧바로 웹 콘텐츠를 긁어올 수 있다는 사실이 새삼 신기했습니다. F12로 정적 페이지 구조를 뜯어보는 방법을 익히니, 앞으로 크롤링할 때 훨씬 수월할 것 같습니다.

BeautifulSoup으로 네이버 랭킹 뉴스를 크롤링하며, 실시간 데이터가 쌓여가는 과정이 재미있어 집중력이 확 올라갔습니다.

pandas로 수집한 데이터를 다루는 순간 ‘아, 이게 진짜 데이터 분석이구나’ 싶었고, DataFrame 조작이 손에 익어가는 게 느껴졌습니다.

 

워드클라우드를 통해 뉴스 제목의 핵심 키워드를 시각적으로 확인하니, 텍스트 분석의 매력이 한층 와닿았습니다.

불용어를 제거하고 시각화를 개선해보니, 데이터 전처리의 중요성과 보람을 동시에 맛볼 수 있었습니다.

오늘 배운 기술들이 실제 프로젝트에 적용될 날이 벌써부터 기대돼요. 다음에는 내가 원하는 데이터를 직접 가져와 시각화해보고 싶습니다!

 

그럼 내일도 뽜샤!!!