728x90
반응형
🚀 Python newspaper3k로 뉴스 자동 수집하는 완벽 가이드
💡 이 글에서 배울 수 있는 것:
• Python newspaper3k 라이브러리 완전 정복
• 뉴스 기사 자동 수집 및 분석 방법
• 실제 프로젝트에 적용 가능한 실무 기법
• 법적 고려사항과 윤리적 크롤링 방법
• Python newspaper3k 라이브러리 완전 정복
• 뉴스 기사 자동 수집 및 분석 방법
• 실제 프로젝트에 적용 가능한 실무 기법
• 법적 고려사항과 윤리적 크롤링 방법
현대적인 뉴스 수집의 새로운 패러다임
📰 뉴스 크롤링이란 무엇인가요?
뉴스 크롤링(News Crawling)은 인터넷상의 뉴스 웹사이트에서 기사 정보를 자동으로 수집하는 기술입니다. 이는 빅데이터 분석, 언론 모니터링, 트렌드 분석 등 다양한 분야에서 활용되고 있습니다.
뉴스 크롤링의 전체적인 프로세스
🐍 newspaper3k 라이브러리란?
newspaper3k는 Python에서 가장 인기 있는 뉴스 기사 추출 라이브러리 중 하나입니다. 원래 newspaper 라이브러리의 Python 3 호환 버전으로, 다음과 같은 강력한 기능들을 제공합니다:
기능 | 설명 | 활용도 |
---|---|---|
기사 추출 | 제목, 본문, 요약 자동 추출 | ⭐⭐⭐⭐⭐ |
이미지 추출 | 기사 관련 이미지 URL 수집 | ⭐⭐⭐⭐ |
메타데이터 | 작성자, 게시일 등 정보 추출 | ⭐⭐⭐⭐ |
언어 감지 | 다국어 기사 자동 인식 | ⭐⭐⭐ |
키워드 추출 | 핵심 키워드 자동 분석 | ⭐⭐⭐⭐ |
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)
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를 활용한 뉴스 감정 분석 및 자동 요약 시스템
반응형
'인공지능 AI' 카테고리의 다른 글
🎬 FlexClip AI 동영상 제작기 완벽 가이드 (0) | 2025.05.24 |
---|---|
Kapwing으로 고화질 비디오 제작하기 (0) | 2025.05.24 |
🎥 Pictory AI: 텍스트를 전문 동영상으로 자동 변환하는 혁신적 도구 (0) | 2025.05.24 |
🎬 AI로 영상 자동 생성하는 완벽 가이드 (0) | 2025.05.24 |
🐍 Python 설치부터 활용까지 완벽 가이드 (0) | 2025.05.24 |
2025년 디지털 노마드, 어디서든 일하는 5가지 필수 준비 (0) | 2025.05.14 |
AI 챗봇이 일상 바꾼다: 2025년 꼭 알아야 할 5가지 활용법 (0) | 2025.05.14 |
✨ AI로 완성하는 블랙헤드 케어 루틴 - 맑고 깨끗한 모공으로 빛나는 피부 만들기 (0) | 2025.05.09 |