기술블로그

📌 MySQL 데이터베이스 정리 (with 크롤링 in Selenium, PymySQL)

Chansman 2025. 3. 25. 14:10

📌 개념 정리

이번 포스팅에서는 Python과 Selenium을 이용하여 웹에서 책 정보를 크롤링하고 PyMySQL을 통해 MySQL 데이터베이스에 저장하는 과정을 프로세스별로 세부적으로 정리합니다.


🚦 전체 프로세스 흐름 및 구조

이 작업은 다음과 같은 순서로 진행됩니다:

  1. MySQL 연결 → 2. 웹 페이지 접속 → 3. 데이터 추출 → 4. 데이터 정제 및 변환 → 5. 예외 처리 → 6. MySQL 저장 → 7. 반복 및 지연

각 프로세스를 단계별로 설명합니다.

 

 


💻 프로세스별 코드 흐름 설명

 

import pymysql
import time
import re
from datetime import datetime

# MySQL 데이터베이스 연결 설정
conn = pymysql.connect(
    host='localhost',
    user='root',
    password='7722',
    db='yes24',
    charset='utf8mb4',
    cursorclass=pymysql.cursors.DictCursor
)

with conn.cursor() as cur:
    for link in link_list:
        # 웹 페이지로 이동
        browser.get(link)
        
        # 기본 정보 추출
        title = browser.find_element(By.CLASS_NAME, 'gd_name').text
        author = browser.find_element(By.CLASS_NAME, 'gd_auth').text
        publisher = browser.find_element(By.CLASS_NAME, 'gd_pub').text

        # 출간일 데이터를 YYYY-MM-DD 형태로 변환
        publishing = browser.find_element(By.CLASS_NAME, 'gd_date').text
        match = re.search(r'(\d+)년 (\d+)월 (\d+)일', publishing)
        if match:
            year, month, day = match.groups()
            data_obj = datetime(int(year), int(month), int(day))
            publishing = data_obj.strftime("%Y-%m-%d")
        else:
            publishing = "2023-01-01"  # 예외 발생 시 기본값 지정

        # 평점 데이터 처리 (숫자 변환 및 예외 처리)
        rating_text = browser.find_element(By.CLASS_NAME, 'yes_b').text.strip()
        if rating_text == '':
            rating = 0.0
        else:
            try:
                rating = float(rating_text)
            except ValueError:
                rating = 0.0

        # 리뷰 개수 처리 (콤마 제거 및 숫자 변환)
        review_text = browser.find_element(By.CLASS_NAME, 'txC_blue').text.replace(",", "")
        try:
            review = int(review_text)
        except ValueError:
            review = 0

        # 판매량 데이터 처리 (콤마 제거 및 숫자 변환)
        sales = browser.find_element(By.CLASS_NAME, 'gd_sellNum').text.split(" ")[2]
        sales = int(sales.replace(",", ""))

        # 가격 데이터 처리 (콤마 및 단위 제거 후 숫자 변환)
        price = browser.find_element(By.CLASS_NAME, 'yes_m').text[:-1]
        price = int(price.replace(",", ""))

        # 순위 데이터 추출 및 예외 처리
        gd_best_text = browser.find_element(By.CLASS_NAME, 'gd_best').text

        # 순위(ranking) 추출
        try:
            ranking = gd_best_text.split(" | ")[0].split(" ")[2][:-1]
        except IndexError:
            ranking = "0"

        # 순위 유지 주간(ranking_weeks) 추출
        try:
            ranking_weeks = gd_best_text.split(" | ")[1].split(" ")[2][:-1]
        except IndexError:
            ranking_weeks = 0

        # MySQL 데이터베이스에 저장
        sql = '''
            INSERT INTO Books(
                title, author, publisher, publishing, rating, review, sales, price, ranking, ranking_weeks
            )
            VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
        '''
        cur.execute(sql, (title, author, publisher, publishing, rating, review, sales, price, ranking, ranking_weeks))
        conn.commit()

        # 페이지 요청 간격 유지
        time.sleep(2)

Step 1: MySQL 연결

conn = pymysql.connect(
    host='localhost',
    user='root',
    password='7722',
    db='yes24',
    charset='utf8mb4',
    cursorclass=pymysql.cursors.DictCursor
)
  • 로컬 MySQL DB에 연결하여 데이터 저장 준비를 합니다.
  • 한글 데이터를 위해 charset을 utf8mb4로 지정합니다.

Step 2: 웹 페이지 접속

for link in link_list:
    browser.get(link)
  • 반복문을 이용하여 크롤링할 각 페이지로 이동합니다.

Step 3: 데이터 추출 (HTML 클래스 기반)

title = browser.find_element(By.CLASS_NAME, 'gd_name').text
author = browser.find_element(By.CLASS_NAME, 'gd_auth').text
publisher = browser.find_element(By.CLASS_NAME, 'gd_pub').text
  • Selenium을 이용하여 웹 페이지에서 책의 제목, 저자, 출판사 정보를 클래스명을 기준으로 가져옵니다.

Step 4: 데이터 정제 및 변환

출판일 데이터 변환

publishing = browser.find_element(By.CLASS_NAME, 'gd_date').text
match = re.search(r'(\d+)년 (\d+)월 (\d+)일', publishing)
if match:
    year, month, day = match.groups()
    data_obj = datetime(int(year), int(month), int(day))
    publishing = data_obj.strftime("%Y-%m-%d")
else:
    publishing = "2023-01-01"
  • 출간일은 'YYYY년 MM월 DD일' 형식에서 YYYY-MM-DD 형식으로 변환합니다.
  • 형식이 맞지 않으면 기본값(2023-01-01)으로 저장합니다.

평점 데이터 처리

rating_text = browser.find_element(By.CLASS_NAME, 'yes_b').text.strip()
if rating_text == '':
    rating = 0.0
else:
    try:
        rating = float(rating_text)
    except ValueError:
        rating = 0.0
  • 평점 텍스트를 숫자로 변환합니다.
  • 데이터가 없거나 숫자가 아닌 경우 0.0으로 저장합니다.

리뷰 개수 처리

review_text = browser.find_element(By.CLASS_NAME, 'txC_blue').text.replace(",", "")
try:
    review = int(review_text)
except ValueError:
    review = 0
  • 리뷰 개수에서 콤마를 제거한 뒤 숫자로 변환합니다.
  • 숫자가 아닌 경우 0으로 처리합니다.

판매량 데이터 처리

sales = browser.find_element(By.CLASS_NAME, 'gd_sellNum').text.split(" ")[2]
sales = int(sales.replace(",", ""))
  • 판매량에서 콤마를 제거하고 숫자로 변환합니다.

가격 데이터 처리

price = browser.find_element(By.CLASS_NAME, 'yes_m').text[:-1]
price = int(price.replace(",", ""))
  • 가격에서 '원' 단위를 제거하고 콤마를 삭제하여 숫자 값으로 변환합니다.

Step 5: 순위 데이터 추출 및 예외 처리

순위(ranking)

gd_best_text = browser.find_element(By.CLASS_NAME, 'gd_best').text

try:
    ranking = gd_best_text.split(" | ")[0].split(" ")[2][:-1]
except IndexError:
    ranking = "0"
  • 베스트셀러 순위를 추출하며 데이터 형식이 다른 경우 예외 처리를 통해 0으로 처리합니다.

순위 유지 주간(ranking_weeks)

try:
    ranking_weeks = gd_best_text.split(" | ")[1].split(" ")[2][:-1]
except IndexError:
    ranking_weeks = 0
  • 순위 유지 기간을 추출하며 예외가 발생하면 기본값을 0으로 저장합니다.

Step 6: MySQL 데이터베이스에 저장

sql = '''
    INSERT INTO Books(
        title, author, publisher, publishing, rating, review, sales, price, ranking, ranking_weeks
    )
    VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
'''
cur.execute(sql, (title, author, publisher, publishing, rating, review, sales, price, ranking, ranking_weeks))
conn.commit()
  • 추출한 모든 데이터를 MySQL의 Books 테이블에 저장합니다.
  • commit()을 통해 DB에 변경사항을 적용합니다.

Step 7: 페이지 요청 간격 유지

time.sleep(2)
  • 웹사이트 서버에 과부하를 주지 않고, IP차단 등을 방지하기 위해 각 요청마다 2초간 지연을 줍니다.

🧪 실전 사례

  • 도서 정보를 자동 수집하여 주간 베스트셀러 분석 시스템에 활용 가능
  • 가격 및 판매량 추이를 추적하여 마케팅 자료로 활용 가능

🧠 고급 팁 및 자주 하는 실수

✔️ 고급 팁

  • WebDriverWait를 활용해 동적 페이지의 로딩 문제를 해결할 수 있습니다.
  • 데이터 저장 시 bulk insert를 활용하면 성능을 높일 수 있습니다.

자주 하는 실수

  • 데이터 정제 과정에서 예외 처리를 놓치는 경우가 많으므로, 항상 try-except를 이용하여 코드의 견고성을 높이세요.
  • SQL 컬럼명이나 데이터 타입이 불일치하여 오류가 발생할 수 있으니 주의가 필요합니다.

마무리 요약 및 복습 포인트

  • 웹 페이지에서 데이터를 추출하고 MySQL에 저장하는 전체 과정을 세부적으로 살펴보았습니다.
  • 각 단계별로 데이터의 정확성과 안정성을 높이기 위한 다양한 처리 방법을 적용하였습니다.
  • 이 프로세스는 실무에서도 바로 활용 가능한 구조입니다. 본 가이드를 참고하여 자신의 크롤링 시스템을 더욱 효과적으로 구성해 보세요! 🚀