포스트

[Python 100일 챌린지] Day 60 - 미니 프로젝트: 뉴스 스크래퍼

[Python 100일 챌린지] Day 60 - 미니 프로젝트: 뉴스 스크래퍼

Phase 6 완성! 🎉 scraper.scrape_all()analyzer.analyze()storage.save() → 뉴스 자동 수집 시스템 완성!** 😊

9일간 배운 모든 웹 기술로 실전 뉴스 스크래퍼 제작! requests + BeautifulSoup + 크롤링 + 데이터 분석까지!

(50-60분 완독 ⭐⭐⭐⭐)

🎯 오늘의 학습 목표

📚 사전 지식


🎯 오늘의 학습 목표 1: Phase 6 내용 복습하기

Phase 6에서 배운 내용

Day 51-54: 웹 스크래핑 기초

  • requests 라이브러리
  • HTTP 메서드 (GET, POST, PUT, DELETE)
  • BeautifulSoup HTML 파싱
  • 동적 콘텐츠 스크래핑

Day 55-57: API 설계와 인증

  • API 설계 원칙
  • RESTful API 구현
  • API 인증 방식 (API Key, OAuth, JWT)
  • API 문서화

Day 58-59: 고급 크롤링

  • 웹 크롤러 구현
  • URL 관리와 방문 기록
  • Selenium 브라우저 자동화
  • 대기 전략과 예외 처리

오늘 만들 프로젝트

뉴스 스크래퍼 - Phase 6의 모든 웹 스크래핑 기술을 활용합니다!


🎯 오늘의 학습 목표 2: 뉴스 스크래퍼 시스템 설계하기

프로젝트 목표

뉴스 수집 및 분석 시스템:

  • 여러 뉴스 사이트 스크래핑
  • 데이터 정제 및 저장
  • 키워드 분석
  • JSON/CSV 출력
  • 일정 자동화

📁 프로젝트 구조

1
2
3
4
5
6
news_scraper/
├── scraper.py          # 스크래퍼
├── parser.py           # 파서
├── storage.py          # 저장
├── analyzer.py         # 분석
└── main.py             # 메인

🎯 오늘의 학습 목표 3: 웹 스크래핑과 API를 활용하여 구현하기

1. 뉴스 스크래퍼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# scraper.py
import requests
from bs4 import BeautifulSoup
from datetime import datetime

class NewsScraper:
    def __init__(self, sources):
        self.sources = sources

    def scrape_all(self):
        all_articles = []
        for source in self.sources:
            articles = self.scrape_source(source)
            all_articles.extend(articles)
        return all_articles

    def scrape_source(self, source):
        try:
            response = requests.get(source['url'], timeout=10)
            soup = BeautifulSoup(response.text, 'html.parser')

            articles = []
            elements = soup.select(source['article_selector'])

            for element in elements:
                article = self._parse_article(element, source)
                if article:
                    articles.append(article)

            return articles
        except Exception as e:
            print(f"{source['name']} 실패: {e}")
            return []

    def _parse_article(self, element, source):
        try:
            title = element.select_one(source['title_selector'])
            link = element.select_one(source['link_selector'])

            if title and link:
                return {
                    'source': source['name'],
                    'title': title.get_text(strip=True),
                    'url': link.get('href'),
                    'scraped_at': datetime.now().isoformat()
                }
        except:
            return None

📊 2. 데이터 분석

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# analyzer.py
from collections import Counter
import re

class NewsAnalyzer:
    def __init__(self, articles):
        self.articles = articles

    def get_statistics(self):
        return {
            'total': len(self.articles),
            'sources': Counter(a['source'] for a in self.articles)
        }

    def extract_keywords(self, top_n=10):
        all_text = ' '.join(a['title'] for a in self.articles)
        words = re.findall(r'\b\w+\b', all_text.lower())
        return Counter(words).most_common(top_n)

💾 3. 저장

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# storage.py
import json
import csv

class NewsStorage:
    def save_json(self, articles, filename='news.json'):
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(articles, f, ensure_ascii=False, indent=2)
        print(f"✅ JSON 저장: {filename}")

    def save_csv(self, articles, filename='news.csv'):
        if not articles:
            return

        with open(filename, 'w', newline='', encoding='utf-8') as f:
            writer = csv.DictWriter(f, fieldnames=articles[0].keys())
            writer.writeheader()
            writer.writerows(articles)
        print(f"✅ CSV 저장: {filename}")

🎮 4. 메인 프로그램

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# main.py
from scraper import NewsScraper
from analyzer import NewsAnalyzer
from storage import NewsStorage

NEWS_SOURCES = [
    {
        'name': 'Example News',
        'url': 'https://news.example.com',
        'article_selector': '.article',
        'title_selector': '.title',
        'link_selector': 'a'
    }
]

def main():
    print("📰 뉴스 스크래핑 시작...")

    scraper = NewsScraper(NEWS_SOURCES)
    articles = scraper.scrape_all()

    print(f"{len(articles)}개 수집")

    if articles:
        analyzer = NewsAnalyzer(articles)
        stats = analyzer.get_statistics()
        keywords = analyzer.extract_keywords()

        print(f"\n📊 통계: {stats['total']}")
        print(f"🔑 키워드: {keywords[:5]}")

        storage = NewsStorage()
        storage.save_json(articles)
        storage.save_csv(articles)

if __name__ == '__main__':
    main()

🎯 오늘의 학습 목표 4: 프로젝트 완성하고 Phase 6 마무리

축하합니다! 🎉

Day 51-60 복습

  1. Day 51: requests 기초
  2. Day 52: HTTP 메서드
  3. Day 53: BeautifulSoup
  4. Day 54: 스크래핑 고급
  5. Day 55: API 설계
  6. Day 56: RESTful API
  7. Day 57: API 인증
  8. Day 58: 웹 크롤러
  9. Day 59: Selenium
  10. Day 60: 뉴스 스크래퍼 프로젝트

이제와서 시작하는 Python 마스터하기 - Phase 6 완료! 🎉🎉🎉

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.