python 공부 2024.04.08
데이터베이스
gui버전으로 sqlitebrowser.org가 존재하는데 cmd로 다운.
다운받는법 만약 받을거면 이 블로그 참고
일단 sqlite.org이 사이트에 가서 다운로드에 맨 밑에 꺼 다운받고 c드라이버로 옮겨줌 압축해제한거.
- 쿼리문은 db마다 조금씩 다름
sqlite 문법
.open naverDB (데이터베이스이름) 이름이 없다면 생성하고 있으면 db에 접속.
CREATE TABLE 테이블이름(열이름1 데이터형식, 열이름2 데이터형식,_) ;
예시
1
CREATE TABLE userTable (id char(4), userName char(15), email char(15), birthYear int);
앞서 계획한 회원 테이블을 생성하고 확인하는 코드.
.table
테이블 하나 볼 수 있음 s붙이면 테이블들.schema userTable
특정 테이블의 스키마(구조)를 확인하는 목적으로 사용.INSERT INTO userTable VALUES (‘jon’, ‘John Bann’, ‘john@naver.com’, 1990);
이건 테이블에 값을 넣는거select * from userTable;
userTable의 전체를 확인. 조건문으로 특정 부분만 확인도 가능
연습해보기
.header on
.mode column (;입력하면 안되고 하나 치고 엔터)
그리고 select * from userTable; 하면 이쁘게 표시됨
1
2
3
4
5
6
.header on
sqlite> .mode column;
Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl
sqlite> .mode column
sqlite> select * from productTable;
pCode pName price amount
파이썬과 db연결
- 데이터베이스에 적기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sqlite3 # SQLite3 모듈을 가져옵니다.
## 변수 선언 부분 ##
con, cur = None, None # SQLite3 연결 객체와 커서 객체를 초기화합니다.
data1, data2, data3, data4 = "","","","" # 사용자 입력을 저장할 변수를 초기화합니다.
sql = "" # SQL 쿼리를 저장할 변수를 초기화합니다.
## 메인 코드 부분 ##
con = sqlite3.connect("C:/sqlite-tools-win-x64-3450200/naverDB") # SQLite3 데이터베이스에 연결합니다.
cur = con.cursor() # 커서 객체를 생성합니다.
while(True): # 무한 반복문을 시작합니다.
data1 = input("사용자ID ==> ") # 사용자로부터 사용자 ID를 입력받습니다.
if data1 == "": # 사용자가 아무 입력도 하지 않으면 반복문을 종료합니다.
break
data2 = input("사용자 이름 ==> ") # 사용자로부터 이름을 입력받습니다.
data3 = input("이메일 ==> ") # 사용자로부터 이메일을 입력받습니다.
data4 = input("출생연도 ==> ") # 사용자로부터 출생 연도를 입력받습니다.
sql = "INSERT INTO userTable VALUES('"+ data1 + "', '"+ data2 + "', '"+ data3 + "', '"+ data4 + "')" # 입력받은 데이터를 이용하여 SQL 쿼리를 생성합니다.
cur.execute(sql) # 생성된 SQL 쿼리를 실행합니다.
con.commit() # 데이터베이스에 반영된 작업을 커밋합니다.
con.close() # 데이터베이스 연결을 닫습니다.
# 포트번호 password 있어야하는데 이 db는 가볍기 때문에 그냥 경로만 두면 된다? 설정하는 방법이 존재하지 않을까 ?
- 데이터베이스 읽어오기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import sqlite3 # SQLite3 모듈을 가져옵니다.
## 변수 선언 부분 ##
con, cur = None, None # SQLite3 연결 객체와 커서 객체를 초기화합니다.
data1, data2, data3, data4 = "","","","" # 사용자 입력을 저장할 변수를 초기화합니다.
sql = "" # SQL 쿼리를 저장할 변수를 초기화합니다.
## 메인 코드 부분 ##
con = sqlite3.connect("C:/sqlite-tools-win-x64-3450200/naverDB") # SQLite3 데이터베이스에 연결합니다.
cur = con.cursor() # 커서 객체를 생성합니다.
cur.execute("SELECT * FROM userTable") # userTable 테이블에서 모든 열을 선택합니다.
print("사용자ID\t사용자이름\t이메일\t 출생연도")
print("------------------------------------------------")
while True:
row = cur.fetchone() # 결과 집합에서 다음 행을 가져옵니다.
if row == None: # 행이 더 이상 없으면 반복문을 종료합니다.
break
data1 = row[0] # 각 열의 데이터를 변수에 저장합니다.
data2 = row[1]
data3 = row[2]
data4 = row[3]
print("%5s %15s %20s %d" % (data1, data2, data3, data4)) # 결과를 출력합니다.
con.close() # 데이터베이스 연결을 닫습니다.
- 데이터베이스 읽고 쓰기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import sqlite3 # SQLite3 모듈을 가져옵니다.
from tkinter import * # tkinter 모듈에서 모든 것을 가져옵니다.
from tkinter import messagebox # messagebox 모듈을 가져옵니다.
# 함수 선언 부분 #
def insertData():
con, cur = None, None # SQLite3 연결 객체와 커서 객체를 초기화합니다.
data1, data2, data3, data4 = "", "", "", "" # 사용자 입력을 저장할 변수를 초기화합니다.
sql = "" # SQL 쿼리를 저장할 변수를 초기화합니다.
con = sqlite3.connect("C:/sqlite-tools-win-x64-3450200/naverDB") # SQLite3 데이터베이스에 연결합니다.
cur = con.cursor() # 커서 객체를 생성합니다.
data1 = edt1.get(); data2 = edt2.get(); data3 = edt3.get(); data4 = edt4.get() # 사용자로부터 입력을 받습니다.
try:
sql = "INSERT INTO userTable VALUES('" + data1 + "', '" + data2 + "', '" + data3 + "', '" + data4 + "')" # 입력받은 데이터로 SQL 쿼리를 생성합니다.
cur.execute(sql) # SQL 쿼리를 실행합니다.
except:
messagebox.showerror('오류', '데이터 입력 오류가 발생함') # 예외가 발생하면 오류 메시지를 출력합니다.
else:
messagebox.showinfo('성공', '데이터 입력 성공') # 예외가 발생하지 않으면 성공 메시지를 출력합니다.
con.commit() # 데이터베이스에 반영된 작업을 커밋합니다.
con.close() # 데이터베이스 연결을 닫습니다.
def selectData():
strData1, strData2, strData3, strData4 = [], [], [], [] # 결과를 저장할 리스트를 초기화합니다.
con = sqlite3.connect("C:/sqlite-tools-win-x64-3450200/naverDB") # SQLite3 데이터베이스에 연결합니다.
cur = con.cursor() # 커서 객체를 생성합니다.
cur.execute("SELECT * FROM userTable") # userTable 테이블에서 모든 열을 선택합니다.
# 열 이름을 리스트에 추가합니다.
strData1.append("사용자ID"); strData2.append("사용자이름")
strData3.append("이메일"); strData4.append("출생연도")
strData1.append("-----------"); strData2.append("-----------")
strData3.append("-----------"); strData4.append("-----------")
while (True):
row = cur.fetchone() # 결과 집합에서 다음 행을 가져옵니다.
if row == None: # 행이 더 이상 없으면 반복문을 종료합니다.
break
# 가져온 행의 데이터를 리스트에 추가합니다.
strData1.append(row[0]); strData2.append(row[1])
strData3.append(row[2]); strData4.append(row[3])
# 리스트박스를 초기화합니다.
listData1.delete(0, listData1.size() - 1); listData2.delete(0, listData2.size() - 1)
listData3.delete(0, listData3.size() - 1); listData4.delete(0, listData4.size() - 1)
# 리스트에 있는 데이터를 리스트박스에 추가합니다.
for item1, item2, item3, item4 in zip(strData1, strData2, strData3, strData4):
listData1.insert(END, item1); listData2.insert(END, item2)
listData3.insert(END, item3); listData4.insert(END, item4)
con.close() # 데이터베이스 연결을 닫습니다.
# 메인 코드 부분 #
window = Tk() # tkinter 윈도우를 생성합니다.
window.geometry("600x300") # 윈도우의 크기를 설정합니다.
window.title("GUI 데이터 입력") # 윈도우의 제목을 설정합니다.
edtFrame = Frame(window); edtFrame.pack() # 데이터 입력 프레임을 생성하고 배치합니다.
listFrame = Frame(window); listFrame.pack(side=BOTTOM, fill=BOTH, expand=1) # 리스트 프레임을 생성하고 배치합니다.
# 데이터 입력용 엔트리 위젯을 생성하고 배치합니다.
edt1 = Entry(edtFrame, width=10); edt1.pack(side=LEFT, padx=10, pady=10)
edt2 = Entry(edtFrame, width=10); edt2.pack(side=LEFT, padx=10, pady=10)
edt3 = Entry(edtFrame, width=10); edt3.pack(side=LEFT, padx=10, pady=10)
edt4 = Entry(edtFrame, width=10); edt4.pack(side=LEFT, padx=10, pady=10)
# 데이터 입력 버튼을 생성하고 배치합니다.
btnInsert = Button(edtFrame, text="입력", command=insertData)
btnInsert.pack(side=LEFT, padx=10, pady=10)
# 데이터 조회 버튼을 생성하고 배치합니다.
btnSelect = Button(edtFrame, text="조회", command=selectData)
btnSelect.pack(side=LEFT, padx=10, pady=10)
# 리스트박스 위젯을 생성하고 배치합니다.
listData1 = Listbox(listFrame, bg='yellow'); listData1.pack(side=LEFT, fill=BOTH, expand=1)
listData2 = Listbox(listFrame, bg='yellow'); listData2.pack(side=LEFT, fill=BOTH, expand=1)
listData3 = Listbox(listFrame, bg='yellow'); listData3.pack(side=LEFT, fill=BOTH, expand=1)
listData4 = Listbox(listFrame, bg='yellow'); listData4.pack(side=LEFT, fill=BOTH, expand=1)
window.mainloop() # GUI 이벤트 루프를 시작합니다.
웹크롤링
- html 가져오기
1
2
3
4
5
6
7
8
import urllib.request
import bs4
nateUrl = "https://www.nate.com"
htmlObject = urllib.request.urlopen(nateUrl)
bsObject = bs4.BeautifulSoup(htmlObject, 'html.parser')
print(bsObject)
- csv에 날짜와 시간적기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import csv # CSV 모듈을 가져옵니다.
import time # 시간 관련 모듈을 가져옵니다.
import datetime # 날짜 및 시간 관련 모듈을 가져옵니다.
# CSV 파일 경로를 지정합니다.
csvName = 'C:/Users/user123/Desktop/learn-py/basic/source/CSV/datetime.csv'
# CSV 파일을 쓰기 모드로 엽니다.
with open(csvName, 'w', newline="") as csvFp:
csvWriter = csv.writer(csvFp) # CSV writer 객체를 생성합니다.
csvWriter.writerow(['연월일', '시분초']) # 헤더를 CSV 파일에 씁니다.
count = 10 # 반복 횟수를 지정합니다.
while count > 0:
count -= 1 # 반복 횟수를 감소시킵니다.
now = datetime.datetime.now() # 현재 날짜와 시간을 가져옵니다.
yymmdd = now.strftime('%Y-%m-%d') # 연월일 포맷으로 변환합니다.
hhmmss = now.strftime('%H:%M:%S') # 시분초 포맷으로 변환합니다.
time_list = [yymmdd, hhmmss] # 날짜와 시간을 리스트로 만듭니다.
print(time_list) # 리스트를 출력합니다.
# CSV 파일을 추가 모드로 엽니다.
with open(csvName, 'a', newline="") as csvFp:
csvWriter = csv.writer(csvFp) # CSV writer 객체를 생성합니다.
csvWriter.writerow(time_list) # 시간 정보를 CSV 파일에 씁니다.
time.sleep(3) # 3초 동안 대기합니다.
- 날씨 받아와서 csv에 적기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import csv # CSV 파일을 다루기 위한 모듈을 가져옵니다.
import time # 시간을 다루기 위한 모듈을 가져옵니다.
import datetime # 날짜와 시간을 다루기 위한 모듈을 가져옵니다.
import bs4 # BeautifulSoup 모듈을 가져옵니다. 웹 스크래핑에 사용됩니다.
import urllib.request # 웹페이지 요청을 보내기 위한 모듈을 가져옵니다.
# CSV 파일 경로를 지정합니다.
csvName = 'C:/Users/user123/Desktop/learn-py/basic/source/CSV/jinju_weather.csv'
# CSV 파일을 쓰기 모드로 엽니다.
with open(csvName, 'w', newline='') as csvFp:
csvWriter = csv.writer(csvFp) # CSV writer 객체를 생성합니다.
csvWriter.writerow(['연월일', '시분초', '온도', '습도', '강수량', '풍향']) # 헤더를 CSV 파일에 씁니다.
# 네이트 날씨 웹페이지 URL을 지정합니다.
nateUrl = "https://news.nate.com/weather?areaCode=11H20701"
# 무한 반복문을 시작합니다.
while True:
# 웹페이지에 요청을 보내고 HTML 코드를 가져옵니다.
htmlObject = urllib.request.urlopen(nateUrl)
webPage = htmlObject.read()
# BeautifulSoup 객체를 생성합니다.
bsObject = bs4.BeautifulSoup(webPage, 'html.parser')
# 웹페이지에서 속초 날씨 정보를 포함한 태그를 찾습니다.
tag = bsObject.find('div', {'class': 'right_today'})
# 온도, 습도, 강수량, 풍향 정보를 추출합니다.
temper = tag.find('p', {'class': 'celsius'}).text
humi = tag.find('p', {'class': 'humidity'}).text
rain = tag.find('p', {'class': 'rainfall'}).text
wind = tag.find('p', {'class': 'wind'}).text
# 현재 날짜와 시간을 가져와서 포맷팅합니다.
now = datetime.datetime.now()
yymmdd = now.strftime('%Y-%m-%d')
hhmmss = now.strftime('%H:%M:%S')
# 날씨 정보를 리스트로 만듭니다.
weather_list = [yymmdd, hhmmss, temper, humi, rain, wind]
# CSV 파일에 날씨 정보를 추가합니다.
with open(csvName, 'a', newline='') as csvFp:
csvWriter = csv.writer(csvFp) # CSV writer 객체를 생성합니다.
csvWriter.writerow(weather_list) # 날씨 정보를 CSV 파일에 씁니다.
print(weather_list)
# 3초 동안 대기합니다.
time.sleep(3)
영화순위 20웹 크롤러
- 단순히 텍스트만 가져오는 버전
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 영화 순위 크롤러
import requests
from bs4 import BeautifulSoup
import tkinter as tk
from tkinter import ttk
def fetch_movie_data():
URL = "https://m.moviechart.co.kr/rank/realtime/index/image"
page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
movie_items = soup.find_all('li', class_='movieBox-item')[:20] # 상위 20개 영화만 선택
movie_data = []
for index, item in enumerate(movie_items, start=1): # 순위를 1부터 시작
title = item.find('h3').text.strip() # 영화 제목
rate = item.find('li', class_='ticketing').find('span').text.strip() # 예매율
release_date = item.find('li', class_='movie-launch').text.strip().replace('개봉일 ', '') # 개봉일
movie_data.append((index, title, rate, release_date)) # 순위 정보 추가
return movie_data
def display_movies(root, movies):
tree = ttk.Treeview(root, columns=('순위', '제목', '예매율', '개봉일'), show='headings', height=len(movies))
tree.heading('순위', text='순위')
tree.heading('제목', text='제목')
tree.heading('예매율', text='예매율')
tree.heading('개봉일', text='개봉일')
tree.column('순위', anchor='center', width=40)
tree.column('제목', anchor='w', width=200)
tree.column('예매율', anchor='center', width=100)
tree.column('개봉일', anchor='center', width=100)
for movie in movies:
tree.insert('', tk.END, values=movie)
tree.pack(pady=20, expand=True)
def main():
root = tk.Tk()
root.title("실시간 영화 순위")
# 20개의 영화 정보를 표시하기 위해 윈도우 크기와 높이 조절
window_height = 20 * 25 # 가정하는 영화 한 줄의 높이를 20px로 설정
root.geometry(f"450x{window_height}")
movies = fetch_movie_data()
display_movies(root, movies)
root.mainloop()
if __name__ == "__main__":
main()
- 포스터도 가져오는 버전
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import sys # 시스템 관련 모듈을 임포트합니다.
import requests # 웹페이지 요청을 보내는 모듈을 임포트합니다.
from bs4 import BeautifulSoup # HTML 파싱을 위한 모듈을 임포트합니다.
from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem, QLabel, QVBoxLayout, QWidget # PyQt5의 위젯 및 레이아웃을 임포트합니다.
from PyQt5.QtGui import QPixmap # 이미지를 표시하기 위한 모듈을 임포트합니다.
from PyQt5.QtCore import Qt # PyQt5의 핵심 모듈을 임포트합니다.
# 사용자 에이전트 설정: 일부 웹사이트가 비브라우저 트래픽을 차단하는 것을 방지하기 위해
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
# 영화 데이터를 가져오는 함수
def fetch_movie_data():
# 실시간 영화 순위 페이지 URL
URL = "https://m.moviechart.co.kr/rank/realtime/index/image"
# 페이지 요청 및 응답 저장
page = requests.get(URL, headers=HEADERS)
# BeautifulSoup 객체 생성하여 HTML 파싱
soup = BeautifulSoup(page.content, 'html.parser')
# 영화 목록 아이템을 찾음
movie_items = soup.find_all('li', class_='movieBox-item')[:20] # 상위 20개 영화 정보만 가져옵니다.
movie_data = []
# 영화 목록 아이템을 순회하며 필요한 정보 추출
for index, item in enumerate(movie_items, start=1): # 영화 순위를 1부터 시작합니다.
title = item.find('h3').text.strip() # 영화 제목을 추출합니다.
rate = item.find('li', class_='ticketing').find('span').text.strip() # 예매율을 추출합니다.
release_date = item.find('li', class_='movie-launch').text.strip().replace('개봉일 ', '') # 개봉일을 추출합니다.
img_path = item.find('img')['src'].split('source=')[1] # 이미지 경로를 추출합니다.
full_img_path = f"https:{img_path}" if not img_path.startswith('http') else img_path # 완전한 이미지 경로를 생성합니다.
movie_data.append((index, title, rate, release_date, full_img_path)) # 영화 데이터를 리스트에 추가합니다.
return movie_data # 영화 데이터를 반환합니다.
# 이미지를 다운로드하는 함수
def download_image(url):
try:
response = requests.get(url, headers=HEADERS) # 이미지 다운로드를 위해 요청을 보냅니다.
response.raise_for_status() # 요청이 성공적으로 이루어졌는지 확인합니다.
pixmap = QPixmap() # QPixmap 객체를 생성합니다.
pixmap.loadFromData(response.content) # 이미지 데이터를 QPixmap에 로드합니다.
return pixmap # QPixmap 객체를 반환합니다.
except Exception as e:
print(f"이미지 다운로드 중 오류 발생: {e}") # 오류 메시지를 출력합니다.
return QPixmap() # 빈 QPixmap 객체를 반환합니다.
# 영화 테이블을 표시하는 클래스
class MovieTable(QTableWidget):
def __init__(self, data):
super().__init__()
self.setRowCount(len(data)) # 테이블의 행 수를 데이터 길이로 설정합니다.
self.setColumnCount(5) # 테이블의 열 수를 5로 설정합니다.
self.setHorizontalHeaderLabels(['순위', '포스터', '제목', '예매율', '개봉일']) # 가로 헤더 레이블을 설정합니다.
self.set_data(data) # 데이터를 테이블에 설정합니다.
self.resizeColumnsToContents() # 열의 크기를 콘텐츠에 맞게 조정합니다.
# 행 번호(왼쪽에 있는 인덱스 숫자)를 숨깁니다.
self.verticalHeader().setVisible(False)
# 테이블 데이터 설정 함수
def set_data(self, data):
for row, (index, title, rate, release_date, img_path) in enumerate(data):
self.setItem(row, 0, QTableWidgetItem(str(index))) # 순위 정보를 셀에 추가합니다.
self.setItem(row, 2, QTableWidgetItem(title)) # 제목 정보를 셀에 추가합니다.
self.setItem(row, 3, QTableWidgetItem(rate)) # 예매율 정보를 셀에 추가합니다.
self.setItem(row, 4, QTableWidgetItem(release_date)) # 개봉일 정보를 셀에 추가합니다.
pixmap = download_image(img_path) # 이미지를 다운로드합니다.
if not pixmap.isNull(): # QPixmap이 유효한 이미지인지 확인합니다.
label = QLabel() # QLabel을 생성합니다.
label.setPixmap(pixmap.scaled(95, 95, Qt.KeepAspectRatio)) # 이미지를 셀에 맞게 크기 조정하여 설정합니다.
self.setCellWidget(row, 1, label) # 셀에 QLabel을 추가합니다.
def main():
app = QApplication(sys.argv) # PyQt 애플리케이션 객체를 생성합니다.
movie_data = fetch_movie_data() # 영화 데이터를 가져옵니다.
table = MovieTable(movie_data) # 영화 테이블을 생성합니다.
layout = QVBoxLayout() # 수직 레이아웃을 생성합니다.
layout.addWidget(table) # 테이블을 레이아웃에 추가합니다.
window = QWidget() # 위젯을 생성합니다.
window.setLayout(layout) # 레이아웃을 위젯에 설정합니다.
window.setWindowTitle("실시간 영화 순위") # 창의 제목을 설정합니다.
window.resize(606, 975) # 창의 크기를 설정합니다.
window.show() # 창을 표시합니다.
sys.exit(app.exec_()) # 애플리케이션 이벤트 루프를 시작하고 프로그램을 실행합니다.
if __name__ == "__main__":
main() # 메인 함수를 호출하여 프로그램을 실행합니다.
크롤링 하면서 배운것
프스터 없이 크롤링하는건 너무 쉬웠는데 포스터에서 막혔었다.
treeview를 계속 쓰면서 표 안에 이미지 들어가는게 안되는 줄 모르고 삽질했다.
PyQt라이브러리로 바꾸고 코드도 그에 맞춰서 코드도 바꾸니까 정상작동했다.
This post is licensed under CC BY 4.0 by the author.