#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 정당 보도자료 크롤러 - 메인 진입점 지원 정당: 더불어민주당, 국민의힘, 조국혁신당, 개혁신당, 기본소득당, 진보당 사용법: python main.py # 전체 정당 증분 업데이트 python main.py --party minjoo # 더불어민주당만 python main.py --party ppp # 국민의힘만 python main.py --party rebuilding # 조국혁신당만 python main.py --party reform # 개혁신당만 python main.py --party basic_income # 기본소득당만 python main.py --party jinbo # 진보당만 python main.py --start-date 2024-01-01 # 날짜 범위 지정 python main.py --party ppp --start-date 2024-01-01 --end-date 2024-06-30 """ import asyncio import argparse import logging from datetime import datetime from minjoo_crawler_async import MinjooAsyncCrawler from ppp_crawler_async import PPPAsyncCrawler from rebuilding_crawler_async import RebuildingAsyncCrawler from reform_crawler_async import ReformAsyncCrawler from basic_income_crawler_async import BasicIncomeAsyncCrawler from jinbo_crawler_async import JinboAsyncCrawler logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', handlers=[ logging.FileHandler('main.log', encoding='utf-8'), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) PARTY_LABELS = { 'minjoo': '더불어민주당', 'ppp': '국민의힘', 'rebuilding': '조국혁신당', 'reform': '개혁신당', 'basic_income':'기본소득당', 'jinbo': '진보당', 'all': '전체 (6개 정당)', } ALL_PARTIES = ['minjoo', 'ppp', 'rebuilding', 'reform', 'basic_income', 'jinbo'] def parse_args(): parser = argparse.ArgumentParser( description='정당 보도자료 크롤러', formatter_class=argparse.RawTextHelpFormatter ) parser.add_argument( '--party', choices=list(PARTY_LABELS.keys()), default='all', help=( '크롤링할 정당 선택 (기본값: all)\n' ' minjoo : 더불어민주당\n' ' ppp : 국민의힘\n' ' rebuilding : 조국혁신당\n' ' reform : 개혁신당\n' ' basic_income : 기본소득당\n' ' jinbo : 진보당\n' ' all : 전체 동시 크롤링' ) ) parser.add_argument( '--start-date', metavar='YYYY-MM-DD', default=None, help='수집 시작 날짜 (예: 2024-01-01)\n미입력 시 마지막 크롤링 이후부터 (증분 업데이트)' ) parser.add_argument( '--end-date', metavar='YYYY-MM-DD', default=None, help='수집 종료 날짜 (예: 2024-12-31)\n미입력 시 오늘 날짜' ) return parser.parse_args() def get_crawler(party: str): """정당 코드에 맞는 크롤러 인스턴스 반환""" return { 'minjoo': MinjooAsyncCrawler, 'ppp': PPPAsyncCrawler, 'rebuilding': RebuildingAsyncCrawler, 'reform': ReformAsyncCrawler, 'basic_income': BasicIncomeAsyncCrawler, 'jinbo': JinboAsyncCrawler, }[party]() async def run_party(party: str, start_date=None, end_date=None): """단일 정당 크롤링 실행""" crawler = get_crawler(party) if start_date or end_date: df = await crawler.collect_all(start_date, end_date) if not df.empty: crawler.save_local(df) crawler.upload_to_huggingface(df) else: await crawler.run_incremental() async def main(): args = parse_args() start_time = datetime.now() target_parties = ALL_PARTIES if args.party == 'all' else [args.party] logger.info("=" * 60) logger.info("정당 보도자료 크롤러 시작") logger.info(f"대상 정당 : {PARTY_LABELS[args.party]}") logger.info(f"수집 기간 : {args.start_date or '증분 업데이트'} ~ {args.end_date or '오늘'}") logger.info("=" * 60) if len(target_parties) == 1: await run_party(target_parties[0], args.start_date, args.end_date) else: results = await asyncio.gather( *[run_party(p, args.start_date, args.end_date) for p in target_parties], return_exceptions=True ) for party, result in zip(target_parties, results): if isinstance(result, Exception): logger.error(f"{PARTY_LABELS[party]} 크롤링 실패: {result}") else: logger.info(f"{PARTY_LABELS[party]} 크롤링 완료") duration = (datetime.now() - start_time).total_seconds() logger.info("=" * 60) logger.info(f"전체 완료! 소요 시간: {duration:.1f}초 ({duration / 60:.1f}분)") logger.info("=" * 60) if __name__ == "__main__": asyncio.run(main())