라이브러리 임포트
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import schedule
코드
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
from datetime import datetime
import schedule
# 기존 데이터프레임 로드 (없으면 새로 생성)
try:
df = pd.read_csv('ecommerce_news.csv', encoding='utf-8', index_col=0)
except FileNotFoundError:
df = pd.DataFrame(columns=['Title', 'Press', 'Link', 'Crawled_Time'])
# 중복 제거를 위한 저장소 (set 사용)
existing_articles = set(df['Link'])
# 네이버 뉴스 검색 URL
url = "https://search.naver.com/search.naver?ssc=tab.news.all&where=news&sm=tab_jum&query=%EC%9D%B4%EC%BB%A4%EB%A8%B8%EC%8A%A4"
# HTTP 요청 헤더
headers = {
"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"
}
# 뉴스 데이터 수집 함수
def fetch_news():
global df, existing_articles # 전역 변수 사용
response = requests.get(url, headers=headers)
# HTTP 요청 성공 여부 확인
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
else:
print("Failed to retrieve the webpage.")
return
# 기사 제목, 뉴스 채널, 링크 추출
articles = []
for item in soup.select('.news_wrap.api_ani_send'):
title_tag = item.select_one('.news_tit') # 기사 제목 태그
press_tag = item.select_one('.info.press') # 뉴스 채널 태그
if title_tag and press_tag:
title = title_tag.get_text(strip=True) # 기사 제목 텍스트
press = press_tag.get_text(strip=True).replace('언론사 선정', '') # 뉴스 채널 텍스트
link = title_tag['href'] # 기사 링크 추출
# 중복 여부 확인 후 추가
if link not in existing_articles:
articles.append({
'Title': title,
'Press': press,
'Link': link,
'Crawled_Time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 크롤링 시간 추가
})
existing_articles.add(link) # 중복 방지를 위해 링크 저장
# 새로운 데이터를 데이터프레임에 추가
if articles: # 새로 추가된 기사가 있을 경우만 처리
new_df = pd.DataFrame(articles)
df = pd.concat([df, new_df], ignore_index=True)
print("New articles added:")
print(new_df)
# 업데이트된 데이터프레임을 CSV 파일로 저장
df.to_csv('ecommerce_news.csv', encoding='utf-8')
else:
print("No new articles found.")
# 스케줄 설정: 1시간마다 실행
schedule.every(1).hours.do(fetch_news)
# 스케줄 실행 루프
while True:
schedule.run_pending()
time.sleep(1)
- 중복 제거를 위한 저장소
# 중복 제거를 위한 저장소 (set 사용)
existing_articles = set(df['Link'])
•`set()`: 중복된 기사를 제거하기 위해 링크(URL)를 저장하는 자료구조입니다.
•`set`은 중복된 값을 허용하지 않으므로, 이미 수집된 기사 링크를 저장하고 새로운 기사와 비교할 때 효율적입니다.
- 네이버 뉴스 검색 '이커머스' URL 설정
url = "https://search.naver.com/search.naver?ssc=tab.news.all&where=news&sm=tab_jum&query=%EC%9D%B4%EC%BB%A4%EB%A8%B8%EC%8A%A4"
headers = {
"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"
}
•`url`: 네이버 뉴스 검색 페이지의 URL입니다. 여기서 `query=%EC%9D%B4%EC%BB%A4%EB%A8%B8%EC%8A%A4`는 “이커머스”라는 검색어를 URL 인코딩한 값입니다.
•`headers`: HTTP 요청 헤더로, `User-Agent`를 설정하여 브라우저에서 요청한 것처럼 보이게 합니다. 이는 일부 서버가 봇 요청을 차단하기 때문입니다.
- 뉴스 데이터 수집 함수
# 함수 정의
def fetch_news():
global existing_articles # 전역 변수 사용
•`fetch_news()`: 네이버 뉴스에서 기사를 수집하는 함수입니다.
•`global existing_articles`: 함수 내부에서 전역 변수 `existing_articles`를 수정하기 위해 선언합니다.
# HTTP 요청 보내기
response = requests.get(url, headers=headers)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
else:
print("Failed to retrieve the webpage.")
return
•`requests.get(url, headers=headers)`: 지정된 URL로 HTTP GET 요청을 보냅니다.
•HTTP 상태 코드 확인 (`response.status_code`):
•`200`: 요청 성공 시, HTML 응답 데이터를 `BeautifulSoup`으로 파싱합니다.
•그 외 상태 코드: 실패 메시지를 출력하고 함수를 종료합니다.
# 기사 제목, 언론사, 링크 추출
articles = []
for item in soup.select('.news_wrap.api_ani_send'):
title_tag = item.select_one('.news_tit') # 기사 제목 태그
press_tag = item.select_one('.info.press') # 뉴스 채널 태그
if title_tag and press_tag:
title = title_tag.get_text(strip=True) # 기사 제목 텍스트
press = press_tag.get_text(strip=True).replace('언론사 선정', '') # 뉴스 채널 텍스트
link = title_tag['href'] # 기사 링크 추출
# 중복 여부 확인 후 추가
if link not in existing_articles:
articles.append({
'Title': title,
'Press': press,
'Link': link,
'Crawled_Time': datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 크롤링 시간 추가
})
existing_articles.add(link) # 중복 방지를 위해 링크 저장
•HTML 요소 선택:
•`.news_wrap.api_ani_send`: 각 뉴스 기사를 포함하는 HTML 요소.
•`.news_tit`: 기사 제목과 링크가 포함된 `<a>` 태그.
•`.info.press`: 언론사 이름이 포함된 태그.
•데이터 추출 및 정리:
•`get_text(strip=True)`: 텍스트만 추출하고 공백 제거.
•`title_tag'href'`: `<a>` 태그의 `href` 속성에서 기사 링크 추출.
•중복 제거:
•이미 `existing_articles`에 저장된 링크는 무시하고 새로운 기사만 리스트에 추가.
# 새로운 데이터를 데이터프레임에 추가
if articles: # 새로 추가된 기사가 있을 경우만 처리
new_df = pd.DataFrame(articles)
df = pd.concat([df, new_df], ignore_index=True)
print("New articles added:")
print(new_df)
# 업데이트된 데이터프레임을 CSV 파일로 저장
df.to_csv('ecommerce_news.csv', encoding='utf-8')
else:
print("No new articles found.")
• 새로 수집한 데이터를 데이터프레임(`new_df`)으로 변환하고 기존 데이터프레임(`df`)에 추가합니다.
• 업데이트된 데이터프레임을 다시 CSV 파일로 저장합니다.
- 스케줄 설정 및 실행
schedule.every(3).hours.do(fetch_news)
while True:
schedule.run_pending()
time.sleep(1)
• 스케줄 설정: `fetch_news()` 함수를 매 3시간마다 실행하도록 설정합니다.
• 루프 실행: 스케줄러가 계속 동작하도록 무한 루프를 실행하며 매초마다 대기(`time.sleep(1)`)합니다.
'[업무 지식] > Crawling' 카테고리의 다른 글
[ETL] ETL(Extract, Transform, Load) 프로세스 스케줄링 (1) | 2025.01.03 |
---|---|
[서울시 열린데이터] 서울시 상권분석서비스(소득소비-상권) (0) | 2025.01.03 |
[NAVER API] 쇼핑인사이트 (0) | 2025.01.03 |
[Selenium] CGV review Crawling (0) | 2025.01.03 |
[ETL] Weather, MySQL 클래스를 객체화 (0) | 2025.01.02 |