MySQL_크롤링 후 데이터베이스에 저장
- -
Gmarket의 BEST 항목을 MySQL을 이용해 데이터베이스에 저장하고자 한다.
1. Schema 정의
ranking 테이블과 상품 정보를 담고있는 items 테이블을 정의한다.
ranking 테이블의 경우 카테고리마다 랭킹이 있으므로 PRIMARY KEY를 랭킹 정보로 사용할 수는 없다.
따라서 따로 num이라는 칼럼을 PRIMARY KEY로 설정한다.
items 테이블의 item_code를 외래키로 참조한다.
CREATE TABLE ranking (
num INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
main_category VARCHAR(50) NOT NULL,
sub_category VARCHAR(50) NOT NULL,
item_ranking TINYINT UNSIGNED NOT NULL,
item_code VARCHAR(20) NOT NULL,
FOREIGN KEY(item_code) REFERENCES items(item_code)
);
items 테이블은 해당 item에 대한 정보를 담고 있는 테이블이다.
CREATE TABLE items (
item_code VARCHAR(20) NOT NULL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
ori_price INT NOT NULL,
dis_price INT NOT NULL,
discount_percent INT NOT NULL,
provider VARCHAR(100)
);
2. Schema 구현
터미널 환경이나 Workbench에서 데이터베이스를 생성한다.
CREATE DATABASE bestproducts;
USE bestproducts;
그 이후부터는 pymysql에서 작업을 하겠다.
✋주의사항✋
테이블을 생성할 때, ranking 테이블을 먼저 생성해서 안된다. FOREIGN KEY로 사용할 items 테이블의 item_code가 아직 정의되어있지 않기 때문이다.
따라서 items 테이블을 먼저 생성한다.
import pymysql
db = pymysql.connect(host='localhost', port=3306, user='root', password='rlaqufgml!23', db='bestproducts', charset='utf8')
cursor = db.cursor()
sql = '''
CREATE TABLE items (
item_code VARCHAR(10) NOT NULL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
ori_price INT NOT NULL,
dis_price INT NOT NULL,
discount_percent INT NOT NULL,
provider VARCHAR(100)
);
'''
cursor.execute(sql)
sql = '''
CREATE TABLE ranking (
num INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
main_category VARCHAR(50) NOT NULL,
sub_category VARCHAR(50) NOT NULL,
item_ranking TINYINT UNSIGNED NOT NULL,
item_code VARCHAR(20) NOT NULL,
FOREIGN KEY(item_code) REFERENCES items(item_code)
);
'''
cursor.execute(sql)
db.commit()
db.close()
3. 데이터 크롤링
3.1 main category 정보 크롤링
import requests
from bs4 import BeautifulSoup
res = requests.get('http://corners.gmarket.co.kr/Bestsellers')
soup = BeautifulSoup(res.content, 'html.parser')
categories = soup.select('div.gbest-cate ul.by-group li a')
for category in categories:
print('http://corners.gmarket.co.kr/' + category['href'], category.get_text())
output
3.2 sub category 정보 크롤링
sub category는 main category를 클릭하면 밑에서 확인할 수 있다.
따라서 requests.get('http://corners.gmarket.co.kr/Bestsellers?viewType=G&groupCode=G01')로 부터 정보를 가져와야 한다.
따라서 링크와 카테고리 이름을 입력하면,
sub_category의 이름과 링크를 출력하는 함수를 정의하였다.
def get_category(category_link, category_name):
# 큰 카테고리 링크와 이름
print(category_link, category_name)
res = requests.get(category_link)
soup = BeautifulSoup(res.content, 'html.parser')
sub_categories = soup.select('div.navi.group ul li a')
for sub_category in sub_categories:
print('http://corners.gmarket.co.kr/'+ sub_category['href'], sub_category.get_text())
category 정보를 가져와 get_category 함수를 이용해 sub_category 정보를 가져왔다.
res = requests.get('http://corners.gmarket.co.kr/Bestsellers')
soup = BeautifulSoup(res.content, 'html.parser')
categories = soup.select('div.gbest-cate ul.by-group li a')
for category in categories:
get_category('http://corners.gmarket.co.kr/' + category['href'], category.get_text())
output
3.3 상품 정보 크롤링
def get_items(html, category_name, sub_category_name):
items_result = list()
best_item = html.select('div.best-list')
for idx, item in enumerate(best_item[1].select('li')):
ranking = idx + 1
title = item.select_one('a.itemname').get_text()
ori_price = item.select_one('div.o-price')
dis_price = item.select_one('div.s-price strong span')
discount_percent = item.select_one('div.s-price em')
if ori_price == None or ori_price.get_text() == '':
ori_price = dis_price
if dis_price == None:
ori_price, dis_price = 0, 0
else:
ori_price = ori_price.get_text().replace(',', '').replace('원','')
dis_price = dis_price.get_text().replace(',','').replace('원','')
if discount_percent == None or discount_percent.get_text() == '':
discount_percent = 0
else:
discount_percent = discount_percent.get_text().replace('%','')
# item code와 판매자 정보
product_link = item.select_one('div.thumb > a')
item_code = product_link.attrs['href'].split('=')[1].split('&')[0]
res = requests.get(product_link.attrs['href'])
soup = BeautifulSoup(res.content, 'html.parser')
provider = soup.select_one('div.item-topinfo_headline > p span.text')
if provider == None:
provider = ''
else:
provider = provider.get_text()
print(category_name, sub_category_name, ranking, title, ori_price, dis_price, discount_percent, item_code, provider)
def get_category(category_link, category_name):
print(category_link, category_name)
res = requests.get(category_link)
soup = BeautifulSoup(res.content, 'html.parser')
# 메인 카테고리 정보 추출
get_items(soup, category_name, 'ALL')
# 서브 카테고리 정보 추출
sub_categories = soup.select('div.navi.group ul li > a')
for sub_category in sub_categories:
res = requests.get('http://corners.gmarket.co.kr/'+ sub_category['href'])
soup = BeautifulSoup(res.content, 'html.parser')
get_items(soup, category_name, sub_category.get_text())
res = requests.get('http://corners.gmarket.co.kr/Bestsellers')
soup = BeautifulSoup(res.content, 'html.parser')
categories = soup.select('div.gbest-cate ul.by-group li a')
for category in categories:
get_category('http://corners.gmarket.co.kr/' + category['href'], category.get_text())
output
4. 크롤링 데이터 DB에 저장
def get_items(html, category_name, sub_category_name):
items_result = list()
best_item = html.select('div.best-list')
for idx, item in enumerate(best_item[1].select('li')):
data_dict = dict()
ranking = idx + 1
title = item.select_one('a.itemname').get_text()
ori_price = item.select_one('div.o-price')
dis_price = item.select_one('div.s-price strong span')
discount_percent = item.select_one('div.s-price em')
if ori_price == None or ori_price.get_text() == '':
ori_price = dis_price
if dis_price == None:
ori_price, dis_price = 0, 0
else:
ori_price = ori_price.get_text().replace(',', '').replace('원','')
dis_price = dis_price.get_text().replace(',','').replace('원','')
if discount_percent == None or discount_percent.get_text() == '':
discount_percent = 0
else:
discount_percent = discount_percent.get_text().replace('%','')
# item code와 판매자 정보
product_link = item.select_one('div.thumb > a')
item_code = product_link.attrs['href'].split('=')[1].split('&')[0]
res = requests.get(product_link.attrs['href'])
soup = BeautifulSoup(res.content, 'html.parser')
provider = soup.select_one('div.item-topinfo_headline > p span.text')
if provider == None:
provider = ''
else:
provider = provider.get_text()
data_dict['category_name'] = category_name
data_dict['sub_category_name'] = sub_category_name
data_dict['ranking'] = ranking
data_dict['title'] = title
data_dict['ori_price'] = ori_price
data_dict['dis_price'] = dis_price
data_dict['discount_percent'] = discount_percent
data_dict['item_code'] = item_code
data_dict['provider'] = provider
print(data_dict)
아래와 같은 형식으로 출력된다.
output
{'category_name': 'ALL', 'sub_category_name': 'ALL', 'ranking': 1, 'title': '[동원]직화구이 매콤 닭꼬치 800g2개(10+10)/쿠폰12900원', 'ori_price': '31800', 'dis_price': '15900', 'discount_percent': '50', 'item_code': '2322860362', 'provider': '동원'}
해당 형식의 데이터를 이용해서 데이터를 데이터베이스에 입력한다.
foreign key 때문에 ranking 테이블에 정보를 입력하기 전에 item 테이블에 먼저 정보를 입력해야 한다.
sql = """INSERT INTO items VALUES(
'""" + item_info['item_code'] + """',
'""" + item_info['title'] + """',
""" + item_info['ori_price'] + """,
""" + item_info['dis_price'] + """,
""" + item_info['discount_percent'] + """,
'""" + item_info['provider'] + """')"""
sql = """INSERT INTO ranking(main_category, sub_category, item_ranking, item_code) VALUES('
""" + item_info['category_name'] + """',
'""" + item_info['sub_category_name'] + """',
'""" + str(item_info['ranking']) + """',
'""" + item_info['item_code'] + """')"""
따라서 다음과 같은 sql문을 실행하는 함수를 정의한다.
def save_data(item_info):
sql = """SELECT COUNT(*) FROM items WHERE item_code = '""" + item_info['item_code'] + """';"""
cursor.execute(sql)
result = cursor.fetchone()
if result[0] == 0:
sql = """INSERT INTO items VALUES(
'""" + item_info['item_code'] + """',
'""" + item_info['title'] + """',
""" + item_info['ori_price'] + """,
""" + item_info['dis_price'] + """,
""" + item_info['discount_percent'] + """,
'""" + item_info['provider'] + """')"""
cursor.execute(sql)
sql = """INSERT INTO ranking(main_category, sub_category, item_ranking, item_code) VALUES('
""" + item_info['category_name'] + """',
'""" + item_info['sub_category_name'] + """',
'""" + str(item_info['ranking']) + """',
'""" + item_info['item_code'] + """')"""
cursor.execute(sql)
get_items 함수에 save_data함수를 이용하는 코드를 추가한다.
def get_items(html, category_name, sub_category_name):
items_result = list()
best_item = html.select('div.best-list')
for idx, item in enumerate(best_item[1].select('li')):
data_dict = dict()
ranking = idx + 1
title = item.select_one('a.itemname').get_text()
ori_price = item.select_one('div.o-price')
dis_price = item.select_one('div.s-price strong span')
discount_percent = item.select_one('div.s-price em')
if ori_price == None or ori_price.get_text() == '':
ori_price = dis_price
if dis_price == None:
ori_price, dis_price = 0, 0
else:
ori_price = ori_price.get_text().replace(',', '').replace('원','')
dis_price = dis_price.get_text().replace(',','').replace('원','')
if discount_percent == None or discount_percent.get_text() == '':
discount_percent = 0
else:
discount_percent = discount_percent.get_text().replace('%','')
# item code와 판매자 정보
product_link = item.select_one('div.thumb > a')
item_code = product_link.attrs['href'].split('=')[1].split('&')[0]
res = requests.get(product_link.attrs['href'])
soup = BeautifulSoup(res.content, 'html.parser')
provider = soup.select_one('div.item-topinfo_headline > p span.text')
if provider == None:
provider = ''
else:
provider = provider.get_text()
data_dict['category_name'] = category_name
data_dict['sub_category_name'] = sub_category_name
data_dict['ranking'] = ranking
data_dict['title'] = title
data_dict['ori_price'] = ori_price
data_dict['dis_price'] = dis_price
data_dict['discount_percent'] = discount_percent
data_dict['item_code'] = item_code
data_dict['provider'] = provider
save_data(data_dict)
이제 아래 코드를 실행하면 데이터를 크롤링하면서 데이터베이스에 저장한다.
import pymysql
db = pymysql.connect(host='localhost', port=3306, user='root', password='비밀번호', db='bestproducts', charset='utf8')
cursor = db.cursor()
res = requests.get('http://corners.gmarket.co.kr/Bestsellers')
soup = BeautifulSoup(res.content, 'html.parser')
categories = soup.select('div.gbest-cate ul.by-group li a')
for category in categories:
get_category('http://corners.gmarket.co.kr/' + category['href'], category.get_text())
5. 해당 방법의 문제점
지금까지는 크롤링 결과를 코드 by 코드로 확인하기 위해 주피터노트북에서 실행하였는데 너무 느리다는 것이 단점이다.
1. pyCharm 에디터로 실행
2. 터미널에서 실행
'Database > MySQL' 카테고리의 다른 글
[MySQL] DBeaver UI로 Database & Table 생성 (0) | 2023.03.02 |
---|---|
MySQL & DBeaver 설치 (윈도우) (0) | 2023.03.02 |
MySQL_Foreign key (0) | 2022.04.11 |
MySQL 파일로 실행 (0) | 2022.04.11 |
PyMySQL (0) | 2022.04.11 |