[실무 강의] Playwright로 동적 웹페이지 실시간 정보 크롤링 후 엑셀(CSV) 자동 저장 및 알림 시스템 구축하기 완벽 마스터 튜토리얼

Playwright로 동적 웹페이지 실시간 정보 크롤링 후 엑셀(CSV) 자동 저장 및 알림 시스템 구축하기

오늘 우리는 웹 개발의 복잡한 영역 중 하나인 동적 웹페이지에서 실시간 데이터를 추출하는 방법을 마스터할 것입니다. 특히 자바스크립트에 의해 렌더링되는 콘텐츠가 많은 최신 웹사이트에서 Playwright는 여러분의 강력한 동반자가 될 것입니다. 이 강의는 단순히 데이터를 긁어오는 것을 넘어, 추출된 데이터를 엑셀(CSV) 파일로 자동 저장하고, 주기적인 실행을 통해 실시간 정보를 추적하며, 중요한 알림까지 받아볼 수 있는 견고한 시스템을 구축하는 데 초점을 맞춥니다. 실무에서 바로 적용 가능한 기술들을 단계별로 상세히 다룰 예정이니, 저와 함께 지금 바로 시작해봅시다.

학습 목표

이 강의를 통해 여러분은 다음과 같은 핵심 역량을 갖추게 될 것입니다.

  • Playwright 이해 및 활용: 동적 웹페이지의 요소를 정확하게 식별하고, 상호작용하며, 데이터를 추출하는 Playwright의 강력한 기능을 숙달합니다.
  • 실시간 데이터 크롤링: 자바스크립트 기반의 동적 콘텐츠, 무한 스크롤, 버튼 클릭 등 복잡한 웹페이지에서도 원하는 정보를 안정적으로 가져오는 방법을 배웁니다.
  • 데이터 처리 및 저장: 추출된 데이터를 Python의 Pandas 라이브러리를 활용하여 효율적으로 처리하고, 엑셀 호환 가능한 CSV 파일 형식으로 자동 저장하는 시스템을 구축합니다.
  • 자동화 및 스케줄링: 크롤링 작업을 특정 주기로 자동 실행하도록 스케줄링하고, 시스템의 안정성을 확보하는 방법을 익힙니다.
  • 알림 시스템 구축: 크롤링 결과 또는 발생한 문제에 대해 이메일과 같은 형태로 자동으로 알림을 받을 수 있는 시스템을 연동합니다.
  • 견고한 크롤러 개발: 예외 처리, 타임아웃 설정, 다양한 대기 전략을 통해 웹페이지 변경에도 강건하게 작동하는 크롤러를 설계하는 노하우를 습득합니다.

사전 준비 사항

본격적인 실습에 앞서, 원활한 진행을 위해 다음 환경 설정을 완료해 주시기 바랍니다.

  • 통합 개발 환경 (IDE): Visual Studio Code (VS Code)를 권장합니다. Python 확장 프로그램을 설치하여 사용하시면 더욱 편리합니다.
  • 운영체제 (OS): Windows 10/11, macOS (Ventura 이상), Linux (Ubuntu 20.04 이상) 등 주요 운영체제 모두 가능합니다.
  • Python 버전: Python 3.9 이상 버전을 설치해야 합니다. 2026년 현재 최신 안정화 버전인 Python 3.10 또는 3.11을 사용하시는 것을 강력히 권장합니다.
  • 필수 설치 라이브러리: 터미널 또는 명령 프롬프트에서 다음 명령어를 실행하여 필요한 라이브러리들을 설치합니다.
# 1. 프로젝트 폴더 생성 및 이동 (선택 사항이지만 권장합니다)
mkdir playwright_live_crawler
cd playwright_live_crawler

# 2. 가상 환경 생성 및 활성화
python -m venv venv
# Windows 사용자:
.\venv\Scripts\activate
# macOS/Linux 사용자:
source venv/bin/activate

# 3. 필수 Python 라이브러리 설치
pip install playwright pandas openpyxl apscheduler

# 4. Playwright 브라우저 설치 (Chromium, Firefox, WebKit)
playwright install

참고: openpyxl은 Pandas가 .xlsx 파일을 처리할 때 필요한 라이브러리이지만, 우리는 CSV를 사용할 것이므로 필수는 아닙니다. 그러나 향후 확장성을 위해 설치해두는 것이 좋습니다. apscheduler는 작업을 스케줄링하는 데 사용되며, 알림 시스템을 위한 smtplib는 Python 표준 라이브러리에 포함되어 별도 설치가 필요 없습니다.

단계별 실습 과정

1단계: 프로젝트 환경 설정 및 Playwright 설치 확인

사전 준비 사항에서 안내된 대로 프로젝트 폴더 생성, 가상 환경 설정 및 필수 라이브러리 설치를 완료합니다. 특히 playwright install 명령어를 통해 Playwright가 지원하는 브라우저들이 제대로 설치되었는지 확인하는 것이 중요합니다. 이 과정이 완료되면, 여러분은 Playwright를 사용하여 웹 자동화를 시작할 준비가 된 것입니다.

2단계: 동적 웹페이지 크롤링 기본 코드 작성

이제 Playwright를 사용하여 동적 웹페이지에서 데이터를 추출하는 기본 스크립트를 작성해봅시다. Playwright는 비동기(async/await) 방식을 사용하므로, 코드를 작성할 때 이를 염두에 두어야 합니다. 여기서는 가상의 동적 상품 목록 페이지에서 상품명과 가격을 추출하는 예시를 다룹니다.

import asyncio
from playwright.async_api import async_playwright, TimeoutError

async def scrape_dynamic_page(url: str) -> list[dict]:
    """
    주어진 URL의 동적 웹페이지에서 상품 정보(제목, 가격)를 크롤링합니다.
    """
    async with async_playwright() as p:
        browser = None
        try:
            # headless=True: 브라우저 UI 없이 백그라운드에서 실행 (운영 환경 권장)
            # headless=False: 브라우저 UI를 띄워 시각적으로 확인 (디버깅 시 유용)
            browser = await p.chromium.launch(headless=True)
            page = await browser.new_page()
            
            print(f"페이지 로딩 중: {url}")
            # 페이지 로딩 대기: 'domcontentloaded'는 DOM 트리가 구성되면 발생
            # 'networkidle'은 500ms 동안 네트워크 활동이 없을 때 발생 (더 느릴 수 있음)
            await page.goto(url, wait_until='domcontentloaded', timeout=30000) # 30초 타임아웃
            
            # 동적 콘텐츠가 로드될 때까지 기다립니다.
            # 예: 상품 목록 컨테이너가 나타날 때까지 기다림
            await page.wait_for_selector('div.product-list-container', timeout=15000) # 15초 타임아웃
            
            print("데이터 추출 시작...")
            # 모든 상품 요소를 선택합니다.
            # 실제 웹페이지의 CSS 셀렉터에 맞춰 수정해야 합니다.
            product_elements = await page.locator('div.product-item').all()
            scraped_data = []
            
            for i, element in enumerate(product_elements):
                try:
                    # 각 상품 요소 내에서 제목과 가격을 추출합니다.
                    title = await element.locator('.product-title').inner_text()
                    price = await element.locator('.product-price').inner_text()
                    scraped_data.append({'Title': title.strip(), 'Price': price.strip()})
                    print(f"  - 추출 완료: {title}")
                except Exception as e:
                    print(f"  - 상품 {i+1} 추출 중 오류 발생: {e}. 해당 요소 건너뜜.")
                    continue # 오류 발생 시 다음 요소로 건너뜁니다.
            
            print(f"총 {len(scraped_data)}개의 데이터 추출 완료.")
            return scraped_data
            
        except TimeoutError:
            print(f"타임아웃 발생: {url} 페이지 로딩 또는 요소 대기 시간 초과.")
            return []
        except Exception as e:
            print(f"크롤링 중 예상치 못한 오류 발생: {e}")
            return []
        finally:
            if browser:
                await browser.close() # 브라우저 인스턴스 종료

async def main_scrape_test():
    # 실제 동적 웹페이지 URL로 변경하세요.
    # 예: 주식 실시간 차트 페이지, 뉴스 피드, 쇼핑몰 상품 목록 등
    target_url = "https://www.example.com/dynamic-products" 
    
    print(f"Playwright 크롤링 테스트 시작: {target_url}")
    results = await scrape_dynamic_page(target_url)
    
    if results:
        print("\n--- 크롤링 결과 (상위 5개) ---")
        for item in results[:5]:
            print(item)
    else:
        print("크롤링된 데이터가 없거나 오류가 발생했습니다.")

if __name__ == "__main__":
    # 비동기 함수 실행
    asyncio.run(main_scrape_test())

위 코드에서 target_url.product-list-container, .product-item, .product-title, .product-price와 같은 CSS 셀렉터는 여러분이 크롤링하고자 하는 실제 웹페이지의 구조에 맞게 변경해야 합니다. Playwright의 Inspector 도구를 사용하면 웹페이지의 요소를 쉽게 검사하고 적절한 셀렉터를 찾을 수 있습니다.

Playwright Inspector를 사용하여 웹페이지 요소를 선택하고 CSS 셀렉터를 확인하는 모습은 동적 웹페이지 크롤링의 핵심 과정 중 하나입니다.

3단계: 추출된 데이터 CSV 파일로 저장

추출된 데이터를 Python의 강력한 데이터 분석 라이브러리인 Pandas를 사용하여 DataFrame으로 변환하고, 이를 CSV 파일로 저장하는 기능을 추가합니다. CSV 파일은 엑셀에서 쉽게 열어볼 수 있으며, 데이터 분석에 활용하기 좋습니다.

import asyncio
import pandas as pd
from playwright.async_api import async_playwright, TimeoutError
from datetime import datetime

# scrape_dynamic_page 함수는 2단계 코드와 동일하게 사용합니다.
# (위에서 정의된 scrape_dynamic_page 함수를 여기에 복사하거나 import하여 사용)

async def main_scrape_and_save():
    target_url = "https://www.example.com/dynamic-products" # 실제 URL로 변경
    print(f"데이터 크롤링 및 CSV 저장 시작: {target_url}")
    scraped_data = await scrape_dynamic_page(target_url)
    
    if scraped_data:
        df = pd.DataFrame(scraped_data)
        
        # 파일명에 현재 시간을 포함하여 중복 방지 및 기록 용이
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        file_name = f"dynamic_products_data_{timestamp}.csv"
        
        # CSV 파일로 저장 (한글 깨짐 방지를 위해 'utf-8-sig' 인코딩 사용)
        df.to_csv(file_name, index=False, encoding='utf-8-sig')
        print(f"데이터가 '{file_name}'으로 성공적으로 저장되었습니다.")
    else:
        print("크롤링된 데이터가 없거나 저장할 데이터가 없습니다.")

if __name__ == "__main__":
    asyncio.run(main_scrape_and_save())

이 코드를 실행하면 현재 디렉터리에 dynamic_products_data_YYYYMMDD_HHMMSS.csv 형식의 파일이 생성됩니다. 이 파일을 엑셀로 열어보면 추출된 데이터가 깔끔하게 정리되어 있는 것을 확인할 수 있습니다.

4단계: 실시간 정보 업데이트 및 알림 시스템 구축

크롤링 작업을 주기적으로 실행하고, 그 결과를 이메일로 받아볼 수 있는 자동화 및 알림 시스템을 구축합니다. 여기서는 Python의 APScheduler 라이브러리를 사용하여 작업을 스케줄링하고, smtplib를 사용하여 이메일 알림을 보냅니다.

import asyncio
import pandas as pd
from playwright.async_api import async_playwright, TimeoutError
from datetime import datetime
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import os

# scrape_dynamic_page 함수는 2단계 코드와 동일하게 사용합니다.
# (위에서 정의된 scrape_dynamic_page 함수를 여기에 복사하거나 import하여 사용)

# --- 이메일 알림 설정 --- #
# 보안을 위해 환경 변수로 관리하는 것을 강력히 권장합니다.
# 예: SENDER_EMAIL="your_email@gmail.com", SENDER_PASSWORD="your_app_password"
SENDER_EMAIL = os.getenv("SENDER_EMAIL", "your_sender_email@gmail.com") # 실제 발신 이메일 주소
SENDER_PASSWORD = os.getenv("SENDER_PASSWORD", "your_email_app_password") # Gmail 앱 비밀번호 또는 해당 메일 서비스 비밀번호
RECEIVER_EMAIL = os.getenv("RECEIVER_EMAIL", "your_receiver_email@example.com") # 수신자 이메일 주소

async def send_notification_email(subject: str, body: str, attachment_path: str = None):
    """
    이메일 알림을 보냅니다. 파일 첨부 기능 포함.
    """
    if SENDER_EMAIL == "your_sender_email@gmail.com" or SENDER_PASSWORD == "your_email_app_password":
        print("경고: 이메일 발신자 정보(SENDER_EMAIL, SENDER_PASSWORD)가 설정되지 않았습니다. 알림을 건너뜁니다.")
        print("환경 변수를 설정하거나 코드 내의 플레이스홀더를 실제 정보로 변경해주세요.")
        return

    msg = MIMEMultipart()
    msg['From'] = SENDER_EMAIL
    msg['To'] = RECEIVER_EMAIL
    msg['Subject'] = subject
    msg.attach(MIMEText(body, 'plain', 'utf-8'))

    if attachment_path and os.path.exists(attachment_path):
        with open(attachment_path, 'rb') as f:
            part = MIMEText(f.read().decode('utf-8-sig'), 'csv', 'utf-8-sig') # CSV 파일 첨부
            part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment_path))
            msg.attach(part)

    try:
        # Gmail SMTP 서버 예시. 다른 메일 서비스의 경우 해당 서버 정보로 변경
        with smtplib.SMTP('smtp.gmail.com', 587) as server:
            server.starttls() # TLS 보안 연결 시작
            server.login(SENDER_EMAIL, SENDER_PASSWORD)
            server.send_message(msg)
        print(f"알림 이메일이 '{RECEIVER_EMAIL}'으로 성공적으로 전송되었습니다.")
    except Exception as e:
        print(f"이메일 전송 중 오류 발생: {e}")

async def scheduled_crawler_job():
    """
    스케줄러에 의해 주기적으로 실행될 크롤링 및 저장, 알림 작업입니다.
    """
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"\n[{current_time}] 스케줄된 크롤링 작업 시작...")
    
    target_url = "https://www.example.com/dynamic-products" # 실제 URL로 변경
    file_name = None
    
    try:
        scraped_data = await scrape_dynamic_page(target_url)
        
        if scraped_data:
            df = pd.DataFrame(scraped_data)
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            file_name = f"dynamic_products_data_{timestamp}.csv"
            df.to_csv(file_name, index=False, encoding='utf-8-sig')
            print(f"데이터가 '{file_name}'으로 성공적으로 저장되었습니다.")
            
            # 성공 알림 이메일 전송
            await send_notification_email(
                subject=f"[Playwright 크롤링] 성공 알림 - {current_time}",
                body=f"새로운 동적 웹페이지 데이터가 성공적으로 크롤링되어 저장되었습니다. 첨부 파일을 확인해주세요.\n크롤링 URL: {target_url}",
                attachment_path=file_name
            )
        else:
            print("크롤링된 데이터가 없거나 저장할 데이터가 없습니다.")
            # 데이터 없음 알림 이메일 전송
            await send_notification_email(
                subject=f"[Playwright 크롤링] 경고: 데이터 없음 - {current_time}",
                body=f"크롤링 작업은 완료되었으나, 추출된 데이터가 없습니다. 웹페이지 구조 변경을 확인하세요.\n크롤링 URL: {target_url}"
            )
            
    except Exception as e:
        print(f"스케줄된 크롤링 작업 중 오류 발생: {e}")
        # 오류 알림 이메일 전송
        await send_notification_email(
            subject=f"[Playwright 크롤링] 오류 발생 - {current_time}",
            body=f"크롤링 작업 중 심각한 오류가 발생했습니다:\n{e}\n크롤링 URL: {target_url}"
        )

if __name__ == "__main__":
    # APScheduler 초기화
    scheduler = AsyncIOScheduler()
    
    # 매 1시간마다 scheduled_crawler_job 함수를 실행하도록 스케줄링
    # 테스트를 위해 'seconds=10' 등으로 짧게 설정할 수 있습니다.
    scheduler.add_job(scheduled_crawler_job, 'interval', hours=1) 
    # scheduler.add_job(scheduled_crawler_job, 'interval', seconds=30) # 테스트용: 30초마다 실행
    
    print("스케줄러가 시작되었습니다. 첫 작업은 스케줄링된 시간에 시작됩니다.")
    scheduler.start()

    # 메인 이벤트 루프를 계속 실행하여 스케줄러가 백그라운드에서 작동하도록 합니다.
    try:
        asyncio.get_event_loop().run_forever()
    except (KeyboardInterrupt, SystemExit):
        print("스케줄러가 종료됩니다.")
        scheduler.shutdown()

이 스크립트를 실행하면, 지정된 시간 간격(예: 매 1시간)마다 Playwright 크롤링 작업이 자동으로 실행되고, 추출된 데이터는 CSV 파일로 저장되며, 그 결과에 대한 알림 이메일이 설정된 주소로 발송됩니다.

이메일 수신함에 Playwright 크롤링 결과와 첨부된 CSV 파일이 도착한 모습은 여러분이 구축한 시스템이 성공적으로 작동하고 있음을 보여줄 것입니다.

Gmail 앱 비밀번호 설정 안내: Google 계정에서 ‘2단계 인증’을 활성화한 후, ‘앱 비밀번호’를 생성하여 사용해야 합니다. 일반 Gmail 비밀번호로는 SMTP 로그인이 거부될 수 있습니다. 환경 변수를 설정하는 방법은 운영체제마다 다르지만, 일반적으로 Linux/macOS에서는 export SENDER_EMAIL="...", Windows에서는 ‘시스템 속성 -> 환경 변수’에서 설정할 수 있습니다.

5단계: 예외 처리 및 견고한 크롤러 구축

웹 크롤링은 웹사이트 구조 변경, 네트워크 오류, 타임아웃 등 다양한 예외 상황에 직면할 수 있습니다. 견고한 크롤러는 이러한 상황을 예측하고 적절히 처리하여 안정적인 작동을 보장해야 합니다. 2단계의 scrape_dynamic_page 함수에 이미 기본적인 예외 처리가 포함되어 있지만, 더 상세한 고려사항을 추가해봅시다.

  • 타임아웃(Timeout) 설정: page.goto(), page.wait_for_selector() 등에 충분한 타임아웃을 설정하여 무한 대기를 방지합니다.
  • 재시도(Retry) 로직: 일시적인 네트워크 오류나 웹사이트 응답 지연에 대비하여 실패 시 일정 횟수만큼 재시도하는 로직을 추가할 수 있습니다 (이 강의에서는 다루지 않지만, 고려할 수 있는 고급 기법입니다).
  • 로깅(Logging): 상세한 로그를 남겨 문제 발생 시 원인을 파악하기 쉽게 합니다.
  • headless=False 디버깅: 개발 단계에서는 browser.launch(headless=False)로 설정하여 브라우저가 실제로 어떻게 동작하는지 시각적으로 확인하며 디버깅하는 것이 매우 유용합니다.
# 예외 처리 및 로깅을 위한 개선된 scrape_dynamic_page 함수 예시
import asyncio
import pandas as pd
from playwright.async_api import async_playwright, TimeoutError
from datetime import datetime
import logging
import os

# 로깅 설정
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

async def scrape_robustly(url: str, headless_mode: bool = True) -> list[dict]:
    """
    주어진 URL의 동적 웹페이지에서 상품 정보(제목, 가격)를 견고하게 크롤링합니다.
    """
    async with async_playwright() as p:
        browser = None
        try:
            browser = await p.chromium.launch(headless=headless_mode)
            page = await browser.new_page()
            
            logging.info(f"페이지 로딩 시도: {url}")
            await page.goto(url, wait_until='domcontentloaded', timeout=45000) # 45초로 타임아웃 증가
            
            logging.info("동적 콘텐츠 로딩 대기 중...")
            await page.wait_for_selector('div.product-list-container', timeout=20000) # 20초로 타임아웃 증가
            
            logging.info("데이터 추출 시작...")
            product_elements = await page.locator('div.product-item').all()
            scraped_data = []
            
            if not product_elements:
                logging.warning(f"'{url}'에서 'div.product-item' 요소를 찾을 수 없습니다. 셀렉터 확인 필요.")
                return []

            for i, element in enumerate(product_elements):
                try:
                    title = await element.locator('.product-title').inner_text()
                    price = await element.locator('.product-price').inner_text()
                    scraped_data.append({'Title': title.strip(), 'Price': price.strip()})
                    # logging.debug(f"  - 추출 완료: {title}") # 너무 많은 로그를 방지하기 위해 debug 레벨로 설정
                except Exception as e:
                    logging.error(f"상품 {i+1} 추출 중 오류 발생: {e}. 해당 요소 건너뜜.")
                    continue
            
            logging.info(f"총 {len(scraped_data)}개의 데이터 추출 완료.")
            return scraped_data
            
        except TimeoutError:
            logging.error(f"타임아웃 발생: {url} 페이지 로딩 또는 요소 대기 시간 초과.")
            return []
        except Exception as e:
            logging.error(f"크롤링 중 예상치 못한 심각한 오류 발생: {e}", exc_info=True) # 예외 정보 포함
            return []
        finally:
            if browser:
                await browser.close()
                logging.info("브라우저 인스턴스 종료.")

# scheduled_crawler_job 함수 내에서 scrape_dynamic_page 대신 scrape_robustly를 호출하도록 수정합니다.
# 예: scraped_data = await scrape_robustly(target_url, headless_mode=True)

# 디버깅을 위해 단일 실행 시 headless_mode를 False로 설정할 수 있습니다.
async def debug_scrape():
    target_url = "https://www.example.com/dynamic-products" # 실제 URL로 변경
    print(f"디버깅 모드 크롤링 시작: {target_url}")
    results = await scrape_robustly(target_url, headless_mode=False) # 디버깅 시 False
    if results:
        print("\n--- 디버깅 크롤링 결과 (상위 3개) ---")
        for item in results[:3]:
            print(item)
    else:
        print("디버깅 크롤링된 데이터가 없거나 오류가 발생했습니다.")

if __name__ == "__main__":
    # 디버깅을 위해 단일 실행 (브라우저 창이 열림)
    # asyncio.run(debug_scrape())
    
    # 스케줄러 실행 (백그라운드에서 headless 모드로)
    scheduler = AsyncIOScheduler()
    scheduler.add_job(scheduled_crawler_job, 'interval', minutes=1) # 테스트용: 1분마다 실행
    print("스케줄러가 시작되었습니다. 1분마다 작업이 실행됩니다.")
    scheduler.start()
    try:
        asyncio.get_event_loop().run_forever()
    except (KeyboardInterrupt, SystemExit):
        print("스케줄러가 종료됩니다.")
        scheduler.shutdown()

scrape_robustly 함수는 더 긴 타임아웃과 상세한 로깅을 포함하여 견고성을 높였습니다. headless_mode=False로 설정하여 Playwright가 실제 브라우저를 띄워 크롤링 과정을 시각적으로 보여주는 것은 디버깅에 매우 효과적입니다.

Playwright가 실제 Chromium 브라우저를 실행하여 웹페이지를 탐색하고 데이터를 추출하는 디버깅 화면은 여러분이 크롤러의 동작을 이해하고 문제를 해결하는 데 큰 도움을 줄 것입니다.

결과 확인

모든 단계가 성공적으로 완료되었다면, 다음을 확인하여 여러분이 구축한 시스템의 작동 여부를 검증할 수 있습니다.

  1. CSV 파일 확인: 스크립트가 실행되는 디렉터리에 dynamic_products_data_YYYYMMDD_HHMMSS.csv 형식의 파일이 생성되었는지 확인합니다. 파일을 열어보면 웹페이지에서 추출된 데이터가 표 형태로 잘 정리되어 있어야 합니다.
  2. 이메일 알림 확인: RECEIVER_EMAIL로 설정한 이메일 계정의 받은 편지함을 확인합니다. 크롤링 성공 또는 실패(오류 발생, 데이터 없음)에 대한 알림 이메일이 도착해 있어야 하며, 성공 시에는 CSV 파일이 첨부되어 있을 것입니다.
  3. 터미널/콘솔 로그 확인: 스크립트를 실행한 터미널 또는 콘솔 창에 출력된 로그 메시지를 확인합니다. 각 단계의 진행 상황, 추출된 데이터 수, 발생한 경고나 오류 메시지 등이 명확하게 표시되어야 합니다.

이러한 확인 과정을 통해 여러분의 Playwright 기반 실시간 크롤링 및 알림 시스템이 완벽하게 작동하고 있음을 확신할 수 있을 것입니다.

마무리하며

오늘 우리는 Playwright를 활용하여 동적 웹페이지에서 실시간 정보를 크롤링하고, 이를 CSV 파일로 자동 저장하며, 주기적인 업데이트와 알림 시스템까지 구축하는 완벽한 튜토리얼을 마쳤습니다. Playwright의 강력한 기능과 비동기 프로그래밍, Pandas를 활용한 데이터 처리, APScheduler를 통한 자동화, 그리고 SMTPLib를 이용한 알림 시스템까지, 실무에서 요구되는 다양한 IT/코딩 기술들을 한데 모아 적용해보았습니다. 이 지식과 경험은 여러분이 더 복잡한 웹 크롤링 프로젝트를 수행하거나, 데이터 기반의 자동화 시스템을 구축하는 데 튼튼한 기반이 될 것입니다. 웹은 끊임없이 변화하므로, 지속적인 학습과 셀렉터 업데이트를 통해 여러분의 크롤러를 항상 최신 상태로 유지하는 것이 중요합니다. 다음 강의에서는 이 시스템을 데이터베이스와 연동하거나, 대시보드를 구축하는 등 더욱 확장된 활용 방안을 다루어보겠습니다. 수고 많으셨습니다!

댓글 남기기