[일지] 2026.02.14

김재만·2026년 2월 14일
post-thumbnail

작업한 것

  • in-c

    • 반복 구현(without docs)

      • 프로젝트 세팅
        • FastAPI 서버 설정
          # 1. backend 폴더를 만들고 들어갑니다.
          mkdir backend
          cd backend
          
          # 2. backend 폴더 안에서 가상환경을 만듭니다.
          python -m venv venv
          
          # 3. 가상환경 활성화
          source venv/bin/activate
          
          # 4. 필수 라이브러리 설치
          pip install fastapi uvicorn
          • 구조 설정
            # app 폴더를 만들고 그 안에 main.py를 생성합니다.
            mkdir app
            touch app/main.py
            
            // app/main.py
            from fastapi import FastAPI
            app = FastAPI()
            @app.get("/")
            def root():
                return {"message": "Hello from Backend Folder!"}
                
            # 현재 위치가 backend/ 인지 확인하고 실행하세요.
            uvicorn app.main:app --reload
      • 연주회 정보 수집기 구조
        • backend - scraper
          mkdir app/scrapers
          
          touch app/scrapers/base.py
          
          // app/scrapers/base.py
          
          from abc import ABC, abstractmethod
          from typing import List, Dict, Any
          class BaseScraper(ABC):
              @abstractmethod
              def scrape(self) -> List[Dict[Any, Any]]:
                  """외부 사이트에서 데이터를 긁어와 리스트 형식으로 반환합니다."""
                  pass
          touch app/scrapers/sac_scraper.py
          
          // app/scrapers/sac_scraper.py
          
          from .base import BaseScraper
          
          class SACScraper(BaseScraper):
              def scrape(self):
                  # 실제 구현은 나중에 하고, 지금은 '동작' 확인을 위해 가짜 데이터를 리턴합니다.
                  print("예술의 전당 사이트 접속 중...")
                  return [
                      {"title": "베토벤 교향곡 9번", "date": "2024-12-25", "genre": "Classic"},
                      {"title": "재즈 페스티벌", "date": "2024-12-30", "genre": "Jazz"}
                  ]
          touch app/scrapers/factory.py
          
          // app/scrapers/factory.py
          
          from .sac_scraper import SACScraper
          class ScraperFactory:
              @staticmethod
              def get_scraper(scraper_type: str):
                  if scraper_type == "SEOUL_ARTS_CENTER":
                      return SACScraper()
                  raise ValueError(f"지원하지 않는 스크래퍼 타입입니다: {scraper_type}")
      • 수집기 호출 api 설정
        // app/main.py
        
        from fastapi import FastAPI
        # (중요) 상위 패키지 구조를 유지하기 위해 상대 임포트를 사용합니다.
        from .scrapers.factory import ScraperFactory 
        
        app = FastAPI(title="In-C 수련 서버")
        @app.get("/")
        def home():
            return {"message": "서버가 정상 동작 중입니다!"}
        @app.get("/collect")
        def collect_concerts(hall: str = "SEOUL_ARTS_CENTER"):
            """
            쿼리 파라미터로 hall 이름을 받아 적절한 스크래퍼를 찾아 실행합니다.
            """
            try:
                # 1. 팩토리에 마법을 부려달라고 합니다. (어떤 객체인지 몰라도 '스크래퍼'인 건 확실함)
                scraper = ScraperFactory.get_scraper(hall)
                
                # 2. 약속된 이름인 scrape()를 호출합니다.
                raw_data = scraper.scrape()
                
                # 3. 브라우저로 예쁘게 결과를 돌려줍니다.
                return {
                    "success": True,
                    "hall_requested": hall,
                    "data": raw_data
                }
            except ValueError as e:
                # 우리가 팩토리에서 만든 에러 처리가 여기서 빛을 발합니다.
                return {"success": False, "error": str(e)}
      • SAC 스크래퍼 기능 구현
        pip install requests
        
        // app/scrapers/sac_scraper.py
        import requests
        import re
        from .base import BaseScraper
        
        class SACScraper(BaseScraper):
            def scrape(self):
                # 1. 예술의 전당 내부 데이터 API 주소
                url = "https://www.sac.or.kr/site/main/show/dataList"
                
                # 2. 파라미터 설정 (카테고리 000005가 '클래식'입니다)
                params = {
                    "CATEGORY_SECONDARY": "000005",
                    "pageSize": "10",
                    "cPage": "1"
                }
                
                # 3. 브라우저인 척 하기 위한 헤더 (없으면 거부당할 수 있어요!)
                headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
                    "X-Requested-With": "XMLHttpRequest"
                }
                print(f"SAC API 호출 중: {url}")
                response = requests.get(url, params=params, headers=headers)
                response.raise_for_status() # 에러 시 예외 발생
                
                raw_data = response.json()
                results = raw_data.get("paging", {}).get("result", [])
                
                # 4. 데이터 가공 (우리 입맛에 맞게)
                concerts = []
                for item in results:
                    concerts.append({
                        "title": item.get("PROGRAM_SUBJECT"),
                        "start_date": item.get("BEGIN_DATE", "").replace(".", "-"),
                        "end_date": item.get("END_DATE", "").replace(".", "-"),
                        "venue": item.get("CATEGORY_PRIMARY_NAME"),
                        "genre": "클래식"
                    })
                    
                return concerts

다음 작업

  • 신규 공연 수집 및 기존 정보 중복 저장 방지
  • 반복 구현 연습

마무리

젬니와 함께한 토요일

profile
듣는 것을 좋아하는 개발자입니다

0개의 댓글