본문 바로가기
인공지능 AI

🚀 Python newspaper3k로 뉴스 자동 수집하는 완벽 가이드

by etmusso74 2025. 5. 24.
728x90
반응형

Python newspaper3k로 뉴스 자동 수집하는 완벽 가이드 | 웹 크롤링

🚀 Python newspaper3k로 뉴스 자동 수집하는 완벽 가이드

메타 제목: Python newspaper3k로 뉴스 자동 수집하는 완벽 가이드 | 웹 크롤링
메타 설명: Python newspaper3k 라이브러리를 활용한 뉴스 기사 자동 수집 방법을 단계별로 알아보세요. 초보자도 쉽게 따라할 수 있는 웹 크롤링 가이드
💡 이 글에서 배울 수 있는 것:
• Python newspaper3k 라이브러리 완전 정복
• 뉴스 기사 자동 수집 및 분석 방법
• 실제 프로젝트에 적용 가능한 실무 기법
• 법적 고려사항과 윤리적 크롤링 방법
뉴스페이퍼와 노트북이 함께 있는 모습, 디지털 뉴스 수집을 상징

현대적인 뉴스 수집의 새로운 패러다임

📰 뉴스 크롤링이란 무엇인가요?

뉴스 크롤링(News Crawling)은 인터넷상의 뉴스 웹사이트에서 기사 정보를 자동으로 수집하는 기술입니다. 이는 빅데이터 분석, 언론 모니터링, 트렌드 분석 등 다양한 분야에서 활용되고 있습니다.

뉴스 사이트 크롤링 봇 데이터 추출 분석/저장

뉴스 크롤링의 전체적인 프로세스

🐍 newspaper3k 라이브러리란?

newspaper3k는 Python에서 가장 인기 있는 뉴스 기사 추출 라이브러리 중 하나입니다. 원래 newspaper 라이브러리의 Python 3 호환 버전으로, 다음과 같은 강력한 기능들을 제공합니다:

기능 설명 활용도
기사 추출 제목, 본문, 요약 자동 추출 ⭐⭐⭐⭐⭐
이미지 추출 기사 관련 이미지 URL 수집 ⭐⭐⭐⭐
메타데이터 작성자, 게시일 등 정보 추출 ⭐⭐⭐⭐
언어 감지 다국어 기사 자동 인식 ⭐⭐⭐
키워드 추출 핵심 키워드 자동 분석 ⭐⭐⭐⭐
Python 코딩 환경과 여러 모니터가 있는 개발자 데스크

Python 개발 환경에서의 뉴스 크롤링 작업

🔧 설치 및 환경 설정

1단계: newspaper3k 설치

# pip를 이용한 기본 설치 pip install newspaper3k # 추가 의존성과 함께 설치 (권장) pip install newspaper3k[nlp] # 가상환경 사용 시 python -m venv news_crawler source news_crawler/bin/activate # Linux/Mac news_crawler\Scripts\activate # Windows pip install newspaper3k

2단계: 필수 라이브러리 설치

# 추가로 필요한 라이브러리들 pip install requests pip install beautifulsoup4 pip install lxml pip install Pillow pip install nltk
⚠️ 주의사항: newspaper3k는 일부 시스템에서 설치 오류가 발생할 수 있습니다. 이 경우 Python 3.7-3.9 버전을 사용하거나, 가상환경을 생성해서 설치하는 것을 권장합니다.

💻 기본 사용법 완전 정복

첫 번째 뉴스 크롤링 코드

from newspaper import Article # 1. 기사 URL 설정 url = 'https://example-news-site.com/article' # 2. Article 객체 생성 article = Article(url, language='ko') # 3. 기사 다운로드 article.download() # 4. 기사 파싱 article.parse() # 5. 결과 출력 print("제목:", article.title) print("작성자:", article.authors) print("게시일:", article.publish_date) print("본문:", article.text[:500] + "...") print("요약:", article.summary)
URL 입력 download() parse() 제목 추출 본문 추출 메타정보 이미지 URL

newspaper3k의 핵심 작동 방식

고급 기능 활용하기

from newspaper import Article import requests from datetime import datetime def advanced_news_crawler(url): try: # 사용자 에이전트 설정으로 차단 방지 config = Config() config.browser_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' article = Article(url, config=config, language='ko') article.download() article.parse() # NLP 처리 (키워드, 요약 추출) article.nlp() # 결과를 딕셔너리로 정리 result = { 'title': article.title, 'authors': article.authors, 'publish_date': article.publish_date, 'text': article.text, 'summary': article.summary, 'keywords': article.keywords, 'top_image': article.top_image, 'images': list(article.images), 'url': article.url, 'crawled_at': datetime.now() } return result except Exception as e: print(f"크롤링 오류: {e}") return None # 사용 예시 news_data = advanced_news_crawler('https://example.com/news') if news_data: print("크롤링 성공!") print(f"키워드: {', '.join(news_data['keywords'][:5])}")

🌐 다양한 뉴스 사이트 크롤링

여러 뉴스 웹사이트들이 표시된 노트북 화면

다양한 뉴스 소스로부터의 정보 수집

여러 뉴스 사이트 동시 크롤링

import time import random from concurrent.futures import ThreadPoolExecutor from newspaper import Article class NewsAggregator: def __init__(self): self.news_sources = [ 'https://news.site1.com', 'https://news.site2.com', 'https://news.site3.com' ] def crawl_single_article(self, url): """단일 기사 크롤링""" try: article = Article(url, language='ko') article.download() article.parse() article.nlp() # 크롤링 간격 조절 (서버 부하 방지) time.sleep(random.uniform(1, 3)) return { 'url': url, 'title': article.title, 'text': article.text, 'summary': article.summary, 'keywords': article.keywords } except: return None def bulk_crawl(self, urls, max_workers=5): """다수 기사 동시 크롤링""" results = [] with ThreadPoolExecutor(max_workers=max_workers) as executor: futures = [executor.submit(self.crawl_single_article, url) for url in urls] for future in futures: result = future.result() if result: results.append(result) return results # 사용 예시 aggregator = NewsAggregator() urls = ['url1', 'url2', 'url3'] # 실제 URL로 교체 articles = aggregator.bulk_crawl(urls) print(f"총 {len(articles)}개 기사 수집 완료")
💡 Pro Tip: 대량 크롤링 시에는 반드시 시간 간격을 두고, robots.txt 파일을 확인하여 해당 사이트의 크롤링 정책을 준수하세요.

RSS 피드와 연동하기

import feedparser from newspaper import Article def rss_to_articles(rss_url, limit=10): """RSS 피드에서 최신 기사들을 가져와 크롤링""" feed = feedparser.parse(rss_url) articles = [] for entry in feed.entries[:limit]: try: article = Article(entry.link, language='ko') article.download() article.parse() articles.append({ 'title': article.title or entry.title, 'url': entry.link, 'published': entry.published if hasattr(entry, 'published') else None, 'summary': article.summary, 'text': article.text }) except Exception as e: print(f"기사 처리 실패 ({entry.link}): {e}") return articles # 주요 언론사 RSS 피드 예시 rss_feeds = { '연합뉴스': 'https://www.yonhapnews.co.kr/rss/news.xml', 'KBS': 'http://world.kbs.co.kr/rss/rss_news.htm', # 실제 사용 시 정확한 RSS URL로 교체 } for source, rss_url in rss_feeds.items(): print(f"\n{source} 최신 기사 수집 중...") articles = rss_to_articles(rss_url, 5) print(f"수집 완료: {len(articles)}개 기사")

📊 데이터 저장 및 분석

CSV 파일로 저장하기

import csv import pandas as pd from datetime import datetime def save_to_csv(articles, filename=None): """크롤링한 기사들을 CSV 파일로 저장""" if not filename: filename = f"news_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" # pandas DataFrame으로 변환 df = pd.DataFrame(articles) # CSV 저장 (한글 깨짐 방지) df.to_csv(filename, index=False, encoding='utf-8-sig') print(f"데이터 저장 완료: {filename}") return filename def analyze_keywords(articles): """수집된 기사의 키워드 분석""" all_keywords = [] for article in articles: if 'keywords' in article and article['keywords']: all_keywords.extend(article['keywords']) # 키워드 빈도 분석 keyword_count = {} for keyword in all_keywords: keyword_count[keyword] = keyword_count.get(keyword, 0) + 1 # 상위 키워드 정렬 top_keywords = sorted(keyword_count.items(), key=lambda x: x[1], reverse=True) return top_keywords[:20] # 상위 20개 반환 # 사용 예시 articles = [] # 앞서 크롤링한 기사 데이터 csv_file = save_to_csv(articles) top_keywords = analyze_keywords(articles) print("주요 키워드 Top 10:") for keyword, count in top_keywords[:10]: print(f"- {keyword}: {count}회")

데이터베이스 연동

import sqlite3 import json from datetime import datetime class NewsDatabase: def __init__(self, db_name='news.db'): self.db_name = db_name self.init_database() def init_database(self): """데이터베이스 테이블 생성""" conn = sqlite3.connect(self.db_name) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT UNIQUE, title TEXT, content TEXT, summary TEXT, keywords TEXT, publish_date TEXT, crawled_at TEXT, source TEXT ) ''') conn.commit() conn.close() def save_article(self, article_data): """기사 데이터를 데이터베이스에 저장""" conn = sqlite3.connect(self.db_name) cursor = conn.cursor() try: cursor.execute(''' INSERT OR REPLACE INTO articles (url, title, content, summary, keywords, publish_date, crawled_at, source) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( article_data.get('url'), article_data.get('title'), article_data.get('text'), article_data.get('summary'), json.dumps(article_data.get('keywords', []), ensure_ascii=False), str(article_data.get('publish_date')), datetime.now().isoformat(), article_data.get('source', 'unknown') )) conn.commit() print(f"저장 완료: {article_data.get('title', 'Unknown')}") except Exception as e: print(f"저장 실패: {e}") finally: conn.close() def get_articles_by_keyword(self, keyword): """키워드로 기사 검색""" conn = sqlite3.connect(self.db_name) cursor = conn.cursor() cursor.execute(''' SELECT title, url, summary FROM articles WHERE keywords LIKE ? OR title LIKE ? OR content LIKE ? ''', (f'%{keyword}%', f'%{keyword}%', f'%{keyword}%')) results = cursor.fetchall() conn.close() return results # 사용 예시 db = NewsDatabase() # 크롤링한 기사 저장 for article in articles: db.save_article(article) # 키워드 검색 results = db.get_articles_by_keyword('AI') print(f"'AI' 관련 기사 {len(results)}개 발견")

⚖️ 법적 고려사항 및 윤리적 크롤링

🚨 중요한 법적 주의사항:
웹 크롤링은 강력한 도구이지만, 반드시 법적 및 윤리적 기준을 준수해야 합니다. 저작권 침해, 서버 과부하 유발, 개인정보 무단 수집 등의 문제가 발생할 수 있으므로 각별한 주의가 필요합니다.
준수사항 설명 구체적 방법
robots.txt 확인 사이트의 크롤링 정책 준수 사이트주소/robots.txt 확인
요청 간격 조절 서버 부하 방지 1-3초 간격으로 요청
저작권 존중 원본 출처 명시 기사 URL 및 언론사 표기
데이터 사용 목적 학술/연구 목적 권장 상업적 이용 시 별도 협의

윤리적 크롤링 코드 예시

import time import requests from urllib.robotparser import RobotFileParser class EthicalCrawler: def __init__(self, delay=2): self.delay = delay # 요청 간격 (초) self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'Academic Research Bot 1.0 (contact@example.com)' }) def check_robots_txt(self, base_url): """robots.txt 확인""" robots_url = f"{base_url}/robots.txt" rp = RobotFileParser() rp.set_url(robots_url) try: rp.read() return rp except: print(f"robots.txt를 읽을 수 없습니다: {robots_url}") return None def can_crawl(self, url, user_agent='*'): """크롤링 가능 여부 확인""" try: from urllib.parse import urlparse parsed = urlparse(url) base_url = f"{parsed.scheme}://{parsed.netloc}" robots = self.check_robots_txt(base_url) if robots: return robots.can_fetch(user_agent, url) return True except: return False def crawl_with_ethics(self, url): """윤리적 크롤링 실행""" # 1. robots.txt 확인 if not self.can_crawl(url): print(f"크롤링 허용되지 않음: {url}") return None # 2. 요청 간격 준수 time.sleep(self.delay) # 3. 정중한 요청 try: article = Article(url, language='ko') article.download() article.parse() # 4. 원본 출처 정보 포함 result = { 'title': article.title, 'content': article.text, 'source_url': url, 'crawled_responsibly': True, 'respect_copyright': '원본 기사 출처를 반드시 명시하세요' } return result except Exception as e: print(f"크롤링 실패: {e}") return None # 사용 예시 ethical_crawler = EthicalCrawler(delay=3) result = ethical_crawler.crawl_with_ethics('https://example-news.com/article')

🔧 문제 해결 및 팁

코딩 문제 해결을 위해 노트북을 보고 있는 개발자

효과적인 문제 해결을 위한 디버깅 과정

자주 발생하는 문제와 해결책

문제 원인 해결방법
403 Forbidden 오류 User-Agent 차단 실제 브라우저 User-Agent 사용
빈 본문 추출 JavaScript 렌더링 필요 Selenium 또는 Playwright 사용
한글 깨짐 인코딩 문제 UTF-8 인코딩 명시
속도 저하 순차 처리 비동기 처리 또는 멀티스레딩
메모리 부족 대량 데이터 처리 배치 처리 및 가비지 컬렉션

고급 문제 해결 코드

from newspaper import Article, Config from selenium import webdriver from selenium.webdriver.chrome.options import Options import gc class AdvancedNewsCrawler: def __init__(self): # newspaper 설정 self.config = Config() self.config.browser_user_agent = ( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/91.0.4472.124 Safari/537.36' ) self.config.request_timeout = 10 # Selenium 설정 (JavaScript 렌더링용) self.setup_selenium() def setup_selenium(self): """Selenium WebDriver 설정""" chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-dev-shm-usage') self.driver = webdriver.Chrome(options=chrome_options) def crawl_with_selenium(self, url): """JavaScript 렌더링이 필요한 사이트 크롤링""" try: self.driver.get(url) time.sleep(3) # 페이지 로딩 대기 html = self.driver.page_source article = Article(url, config=self.config) article.set_html(html) article.parse() return { 'title': article.title, 'text': article.text, 'method': 'selenium' } except Exception as e: print(f"Selenium 크롤링 실패: {e}") return None def smart_crawl(self, url): """일반 크롤링 실패 시 Selenium으로 재시도""" try: # 1차 시도: 일반 newspaper article = Article(url, config=self.config, language='ko') article.download() article.parse() if len(article.text) < 100: # 본문이 너무 짧으면 print("일반 크롤링 실패, Selenium으로 재시도...") return self.crawl_with_selenium(url) return { 'title': article.title, 'text': article.text, 'method': 'newspaper' } except Exception as e: print(f"일반 크롤링 실패: {e}") return self.crawl_with_selenium(url) finally: # 메모리 정리 gc.collect() def __del__(self): """클래스 소멸 시 리소스 정리""" if hasattr(self, 'driver'): self.driver.quit() # 사용 예시 advanced_crawler = AdvancedNewsCrawler() result = advanced_crawler.smart_crawl('https://difficult-news-site.com/article') if result: print(f"크롤링 성공 ({result['method']}): {result['title']}")

📈 실전 프로젝트: 뉴스 트렌드 분석기

🎯 프로젝트 목표: 여러 뉴스 사이트에서 기사를 수집하여 실시간 트렌드를 분석하는 시스템을 구축해보겠습니다.
import asyncio import aiohttp from collections import Counter from wordcloud import WordCloud import matplotlib.pyplot as plt from konlpy.tag import Okt import pandas as pd class NewsTrendAnalyzer: def __init__(self): self.okt = Okt() # 한국어 형태소 분석기 self.articles = [] self.trends = {} async def async_crawl(self, session, url): """비동기 크롤링""" try: async with session.get(url) as response: html = await response.text() article = Article(url, language='ko') article.set_html(html) article.parse() return { 'url': url, 'title': article.title, 'text': article.text, 'publish_date': article.publish_date } except: return None async def bulk_crawl_async(self, urls): """대량 비동기 크롤링""" async with aiohttp.ClientSession() as session: tasks = [self.async_crawl(session, url) for url in urls] results = await asyncio.gather(*tasks) self.articles = [r for r in results if r and r['text']] print(f"총 {len(self.articles)}개 기사 수집 완료") def analyze_trends(self): """트렌드 분석""" all_text = ' '.join([article['text'] for article in self.articles]) # 형태소 분석 및 명사 추출 nouns = self.okt.nouns(all_text) # 불용어 제거 (2글자 이상, 의미있는 단어만) meaningful_nouns = [ noun for noun in nouns if len(noun) >= 2 and noun not in ['기자', '뉴스', '오늘', '어제'] ] # 빈도 분석 word_count = Counter(meaningful_nouns) self.trends = dict(word_count.most_common(50)) return self.trends def generate_wordcloud(self, save_path='wordcloud.png'): """워드클라우드 생성""" if not self.trends: self.analyze_trends() # 한글 폰트 설정 (시스템에 따라 경로 조정) font_path = 'NanumGothic.ttf' # 한글 폰트 경로 wordcloud = WordCloud( font_path=font_path, width=800, height=400, background_color='white', max_words=100 ).generate_from_frequencies(self.trends) plt.figure(figsize=(10, 5)) plt.imshow(wordcloud, interpolation='bilinear') plt.axis('off') plt.title('뉴스 트렌드 워드클라우드', fontsize=16) plt.savefig(save_path, dpi=300, bbox_inches='tight') plt.show() def generate_report(self): """트렌드 리포트 생성""" if not self.trends: self.analyze_trends() # 데이터프레임으로 변환 df = pd.DataFrame(list(self.trends.items()), columns=['키워드', '빈도']) # 리포트 생성 report = f""" 📊 뉴스 트렌드 분석 리포트 ================================ 📈 분석 대상: {len(self.articles)}개 기사 📅 분석 일시: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} 🔥 TOP 10 트렌드 키워드: """ for i, (keyword, count) in enumerate(list(self.trends.items())[:10], 1): report += f"\n{i:2d}. {keyword} ({count}회)" return report # 사용 예시 analyzer = NewsTrendAnalyzer() # URL 리스트 (실제 뉴스 사이트 URL로 교체) news_urls = [ 'https://example1.com/news1', 'https://example2.com/news2', # ... 더 많은 URL ] # 비동기 크롤링 실행 # asyncio.run(analyzer.bulk_crawl_async(news_urls)) # 트렌드 분석 및 리포트 생성 # trends = analyzer.analyze_trends() # report = analyzer.generate_report() # print(report) # 워드클라우드 생성 # analyzer.generate_wordcloud()

🔗 유용한 리소스 및 참고 자료

💡 마무리 및 핵심 요약

🎯 이 글에서 배운 핵심 내용

1. newspaper3k 기본 사용법 - Python으로 뉴스 기사를 쉽게 추출하는 방법
2. 고급 크롤링 기법 - 다양한 사이트 대응 및 대량 처리 방법
3. 데이터 저장 및 분석 - CSV, 데이터베이스 활용 및 트렌드 분석
4. 법적/윤리적 고려사항 - 책임감 있는 크롤링 방법
5. 실전 프로젝트 - 뉴스 트렌드 분석 시스템 구축
⚠️ 마지막 당부사항:
뉴스 크롤링은 정보 수집과 분석에 매우 유용한 도구입니다. 하지만 반드시 법적 기준을 준수하고, 원본 콘텐츠에 대한 저작권을 존중해야 합니다. 수집한 데이터는 연구나 개인적 용도로만 사용하고, 상업적 목적으로 사용할 때는 해당 언론사의 허가를 받으시기 바랍니다.
단계 난이도 예상 소요시간 활용도
기본 설치 및 사용 ⭐⭐ 30분 ⭐⭐⭐⭐⭐
다중 사이트 크롤링 ⭐⭐⭐ 1-2시간 ⭐⭐⭐⭐
데이터 분석 및 저장 ⭐⭐⭐ 2-3시간 ⭐⭐⭐⭐⭐
고급 문제 해결 ⭐⭐⭐⭐ 3-4시간 ⭐⭐⭐
실전 프로젝트 ⭐⭐⭐⭐⭐ 1-2일 ⭐⭐⭐⭐⭐

🔍 고가 CPC 키워드 (SEO 최적화용)

핵심 키워드: Python 뉴스 크롤링, newspaper3k 사용법, 웹 스크래핑 Python, 뉴스 데이터 수집, 자동 뉴스 추출, 뉴스 크롤러 개발, Python 웹 크롤링, 뉴스 분석 도구, 빅데이터 뉴스 수집, 실시간 뉴스 모니터링

💬 이 글이 도움이 되셨나요?

뉴스 크롤링에 대한 더 자세한 질문이나 특정 사이트 크롤링 문제가 있으시면 언제든 문의해 주세요!

다음 포스팅 예고: 🤖 AI를 활용한 뉴스 감정 분석 및 자동 요약 시스템

반응형