본문 바로가기
웹 크롤링(Web Crawling)/크롤링 프로젝트(시행 착오 노트)

[Python] 크롤링한 데이터 DB에 저장하기

by 현군의 coding&IT story 2024. 9. 22.

목표

- 크롤링한 데이터들을 mysql의 데이터베이스에 데이터를 넣는다.

 

준비물

- mysql이 설치 되어 있어야 한다.

mysql 계정은 root, 비밀번호는 1234 라고 가정한다.

 

방법

1. 명령 프롬프트(cmd)를 킵니다.

 

2. 아래 명령어로 데이터베이스를 생성합니다.

mysql -u root -p # root 계정으로 접속
<자신의 비밀번호 입력>

CREATE DATABASE dabang_data; # dabang_data DB 생성

show databases; # DB 조회

 

3. Python에서 mysql을 접속합니다. 그리고 테이블을 생성합니다.

- 터미널에서 mysqlclient 라이브러리 설치 (Python으로 mysql에 접속을 도와주는 라이브러리)

pip install mysqlclient

 

- Python 코드에서 mysql 접속하여 테이블 생성하는 코드 작성

# DB 연결
import MySQLdb

conn = MySQLdb.connect(
    user="root", # user명
    passwd="1234", #pw명
    host="localhost", 
    db="dabang_data" #연결할 DB명
    # charset="utf-8"
)
print(type(conn)) # 정상 연결 시 : <class 'MySQLdb.connections.Connection'>
cursor = conn.cursor()
print(type(cursor)) # 정상 연결 시 : <class 'MySQLdb.cursors.Cursor'>
# DB 구문 수행
cursor.execute("CREATE TABLE IF NOT EXISTS coliving (room_no INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(70))")
conn.commit()

 

- 테이블 생성 확인

명령 프롬프트 (cmd) 에서 진행

# mysql 접속
mysql -u root -p
<비밀번호 입력>

# dabang_data 데이터베이스 안에 있는 테이블 확인
use dabang_data;
show tables;

만든 테이블(coliving)이 잘 있다.

 

테이블의 각 필드 지정도 잘 되었는지 확인합니다.

describe coliving;

 

4. 테이블에 크롤링한 데이터를 INSERT 합니다.

// 크롤링 로직 내에 삽입
cursor.execute("INSERT INTO coliving (name) VALUES (%s)", (house["NAME"],)) # 자리 표시자 (%s) 활용

// 넣은 다음에는 항상 commit을 해줘야 반영이 안정적으로 된다. (auto commit이 아닐 수도 있으므로)
conn.commit()

 

주의 : SQL injection을 고려해야 한다.

cursor.execute(f"INSERT INTO coliving (name) VALUES ('{house_name}')")

위 코드는 SQL injection 공격에 취약하다.

house_name 값에 사용자가 입력한 값이 SQL 쿼리의 일부로 해석되기 때문이다.

 

조금 더 쉽게 설명하기 위해 예를 들자면, house_name 값에 아래와 같은 값이 들어갔다고 가정하자.

house_name = "'; DROP TABLE coliving; --"

 

그러면 최종적으로 생성되는 SQL 쿼리 문은 다음과 같다.

INSERT INTO coliving (name) VALUES (''; DROP TABLE coliving; --')

그러면 의도한 것과 다르게 coliving 테이블을 삭제하는 명령이 되어 버린다.

 

-> 이 방법을 방지하기 위해 자리 표시자를 활용한다.

자리 표시자의 경우 SQL 쿼리에서 값을 안전하게 삽입하도록 도와준다. (SQL Injection 공격 방지)

cursor.execute("INSERT INTO coliving (name) VALUES (%s)", (house["NAME"],))

 

이러면 house["NAME"] 값에

"'; DROP TABLE coliving; --"

과 같이 들어가도, 자리 표시자가 따옴표를 떼고 문자열(%s)로 표현한다.

자동으로 작은 따옴표로 감싼 다음 필요한 경우 이스케이프 처리를 한다.

'; DROP TABLE coliving; -- # 작은 따옴표를 뗀다.
''; DROP TABLE coliving; --' # 작은 따옴표로 감싼다.
'\'; DROP TABLE coliving; --' # 이스케이프 처리를 한다.

데이터베이스는 이 문자열을 단순한 데이터로 인식하기 때문에 '; DROP TABLE coliving; -- 문자열이 INSERT 되게 된다. (SQL 쿼리 실행이 아니다.)

 

어려우니 쉽게 요약하면, 항상 SQL에 데이터를 삽입할 때 직접 값을 삽입하는 것보다 자리 표시자(%s, %d 등) 을 이용하는 것이 좋다.

 

5. 데이터가 잘 추가 되었는지 확인합니다.

 

방법 1) mysql에서 직접 조회select * from coliving; 명령어를 통해 데이터를 전체 조회 합니다.

 

방법 2) python을 통해 조회한다.

cursor.execute("SELECT * FROM coliving") # SELECT * FROM coliving 쿼리 결과들이 cursor에 저장됨.
results = cursor.fetchall() # 한 개만 가져올 때는 fetchone() 메서드 사용 (결과들이 저장된 cursor 객체에서 결과를 가져와 result에 저장)
for result in results: # 결과를 하나씩 꺼내 출력
    print(result)

 

참고 - 담기는 것은 리스트 안에 튜플들이 담기는 구조로 담기게 된다.

# 결과는 리스트 안에 튜플 형태
[
    (1, '꼬모쉐 홍제역점')
    (2, '단잠스테이 원룸텔')
    (3, '명문게스트하우스')
    (4, 'HJ HOUSE')
    (5, '패시브스테이 50')
    (6, '레지던스 라움')
    (7, '레지던스 라움 노량진역점')
    (8, '숲속휴식')
    (9, 'JJ빌리지')
    (10, '홍제스테이')
]