open API + docx + GUI + GUI 메뉴 탭 + tab2에 새 내용 넣기 + 그래프 그려서 word 리포트 만들기 + tab에 그래프 그리기
# open API + docx 함수 정의
def naverBlogOpenAPI_to_docx(x,y,z,m) :
# x = 검색어
# y = start_point
# z = display_count
# m = word 파일 내에서 페이지 나누는 기준 건수
import requests
from urllib.parse import urlparse
import docx
# docx 파일 생성
wordfile = docx.Document()
# 헤더 생성
wordfile.add_heading('open API 활용 네이버 블로그 검색 결과 크롤링', 0)
wordfile.add_heading("검색어 : " + str(x) + "\t/" + "검색 결과 : 총 " + str(y * z) + "개", 1)
keyword = str(x)
i = 1
cnt = 0
for i in range(1, y+1) :
if i == 1 :
url = "https://openapi.naver.com/v1/search/blog?query=" + \
keyword + "&display=" + str(z) + "&start=" + str(i)
elif i > 1 :
url = "https://openapi.naver.com/v1/search/blog?query=" + \
keyword + "&display=" + str(z) + "&start=" + str((i-1)*z + 1)
result = requests.get(urlparse(url).geturl(),
headers={"X-Naver-Client-Id":"____",
"X-Naver-Client-Secret":"____"})
json_data = result.json()
for item in json_data['items']:
cnt += 1
globals()['blog_result{}'.format(cnt)] = \
wordfile.add_heading(item['title'].replace("<b>", "").replace("</b>", ""), 4)
globals()['blog_result{}'.format(cnt)] = \
wordfile.add_paragraph(item['description'].replace("<b>", "").replace("</b>","") + "\n")
if (cnt) % m == 0 :
next_page = globals()['blog_result{}'.format(cnt)].add_run()
next_page.add_break(docx.text.run.WD_BREAK.PAGE)
wordfile.save("C:/Users/student/Desktop/python/P_3week/연습2(openAPI+docx+GUI+menu).docx")
# < GUI 만들기 >
import tkinter as tk
from tkinter import ttk
# 인스턴스 만들기
win = tk.Tk()
# 타이틀 정하기
win.title("Bigdata GUI")
# 창 사이즈
win.geometry("640x480")
# 사이즈 조절 가능 여부 설정 (세로, 가로)
win.resizable(True, True) # (세로 고정, 가로 조절 가능)
# =============================================================================
# tab 여러개 만들기
# =============================================================================
tabControl = ttk.Notebook(win) # Create Tab Control
tab1 = ttk.Frame(tabControl) # Create a tab
tabControl.add(tab1, text='Naver 블로그 검색')
tab2 = ttk.Frame(tabControl)
tabControl.add(tab2, text='서울시 구별 CCTV 현황 분석')
tabControl.pack(expand=1, fill="both") # Pack to make visible
# =============================================================================
# 첫 번째 탭 만들기
# =============================================================================
# < label frame 만들기 >
# tab 1에 레이블 프레임 (srch) 만들기
srch = ttk.LabelFrame(tab1, text='검색조건 입력')
srch.grid(column=0, row=0, padx=20, pady=20)
# 레이블 추가 (레이블 프레임 안에)
label = ttk.Label(srch, text = "검색어를 입력하세요 :")
label.grid(column = 0, row = 1)
label2 = ttk.Label(srch, text = "start_point를 입력하세요 :")
label2.grid(column = 0, row = 2)
label3 = ttk.Label(srch, text = "display_count를 입력하세요 :")
label3.grid(column = 0, row = 3)
label4 = ttk.Label(srch, text = "페이지 나눌 기준 건수 :")
label4.grid(column = 0, row = 4)
# 텍스트 박스 추가 (레이블 프레임 안에)
## 첫번째 텍스트 박스 : 검색어 값
name = tk.StringVar()
name_entered = ttk.Entry(srch, width = 12, textvariable = name)
name_entered.grid(column=1, row=1)
## 두번째 텍스트 박스 : start_point 값
name2 = tk.StringVar()
name2_entered = ttk.Entry(srch, width = 12, textvariable = name2)
name2_entered.grid(column=1, row=2)
## 세번째 텍스트 박스 : display_count 값
name3 = tk.StringVar()
name3_entered = ttk.Entry(srch, width = 12, textvariable = name3)
name3_entered.grid(column=1, row=3)
## 네번째 텍스트 박스 : 페이지 나눌 기준 건수 값
name4 = tk.StringVar()
name4_entered = ttk.Entry(srch, width = 12, textvariable = name4)
name4_entered.grid(column=1, row=4)
# 버튼 클릭 함수 정의 (에러 체크 까지)
def click_me() :
name_err = "T"
label.configure(text = '완료', foreground = 'blue')
if name.get() == "": # 검색어가 오류면
name_err = "F"
label.configure(text='한 글자 이상 입력하세요.', \
foreground='red')
name2_err = "T"
label2.configure(text = '완료', foreground = 'blue')
if int(name2.get()) > 1000 or int(name2.get()) < 1 : # start_point 가 오류면
name2_err = "F"
label2.configure(text = '1 ~ 1000 사이의 값을 입력해주세요.', \
foreground = 'red')
name3_err = "T"
label3.configure(text = '완료', foreground = 'blue')
if int(name3.get()) > 100 or int(name3.get()) < 10 : # display_count 가 오류면
name3_err = "F"
label3.configure(text = '10 ~ 100 사이의 값을 입력해주세요.',\
foreground = 'red')
name4_err = "T"
label4.configure(text = '완료', foreground = 'blue')
if name4.get() == "" or int(name4.get()) == 0 : # 페이지 나눌 기준 건수 가 오류면
name4_err = "F"
label4.configure(text = '0 이상의 숫자값을 입력해주세요.',\
foreground = 'red')
if name_err == "T" and name2_err == "T" and name3_err == "T" and name4_err == "T": # 오류 없으면
action.configure(text = name.get() + " 관련 블로그를 " + \
str(int(name2.get()) * int(name3.get())) + "개 크롤링 합니다.") # 버튼에 나타나는 글자
naverBlogOpenAPI_to_docx(name.get(), int(name2.get()), int(name3.get()), int(name4.get()))
else: # 하나라도 오류면
action.configure(text = "입력값 수정 후 다시 누르세요.") # 버튼에 나타나는 글자
# 버튼 추가
action = ttk.Button(srch, text = "검색을 시작합니다!", command = click_me)
action.grid(column = 1, row = 5)
# =============================================================================
# 두번째 탭 만들기
# =============================================================================
# < 파일 다이아로그 띄우기 >
from tkinter import filedialog
# < Tab2 에 레이블 프레임 (grph) 만들기 >
grph = ttk.LabelFrame(tab2, text='관련 파일을 선택하세요!')
grph.grid(column=0, row=0, padx=20, pady=20)
# 버튼 클릭 함수 정의 2
def file_get1():
# srch.filename = filedialog.askopenfilename(initialdir = "c:/project-data/",title = "choose your file",filetypes = (("excel files","*.xlsx"),("all files","*.*")))
# print (srch.filename)
file1.text = filedialog.askopenfilename(initialdir = "c:/Users/student/Desktop/python/P_4week", title = "choose your file", filetypes = (("csv files","*.csv"),("all files","*.*")))
file1_entered.insert(0,file1.text)
#open_file(file1.text)
def file_get2():
# srch.filename = filedialog.askopenfilename(initialdir = "c:/project-data/",title = "choose your file",filetypes = (("excel files","*.xlsx"),("all files","*.*")))
# print (srch.filename)
file2.text = filedialog.askopenfilename(initialdir = "c:/Users/student/Desktop/python/P_4week", title = "choose your file",filetypes = (("excel files","*.xls"),("all files","*.*")))
file2_entered.insert(0,file2.text)
#open_file(file2.text)
def file_get3():
# srch.filename = filedialog.askopenfilename(initialdir = "c:/project-data/",title = "choose your file",filetypes = (("excel files","*.xlsx"),("all files","*.*")))
# print (srch.filename)
file3.set(" ")
file3.text = filedialog.askopenfilename(initialdir = "c:/Users/student/Desktop/python/P_4week", title = "choose your file",filetypes = (("text files","*.txt"),("all files","*.*")))
file3_entered.insert(0,file3.text)
open_file(file3.text) # 개요 파일 읽어서 내용 보이는 함수
def graph_and_print(x, y) :
# 버튼 눌렀을 때 탭 생성
tab3 = ttk.Frame(tabControl)
tabControl.add(tab3, text='그래프1')
tab4 = ttk.Frame(tabControl)
tabControl.add(tab4, text='그래프2')
tab5 = ttk.Frame(tabControl)
tabControl.add(tab5, text='그래프3')
tab6 = ttk.Frame(tabControl)
tabControl.add(tab6, text='그래프4')
tab7 = ttk.Frame(tabControl)
tabControl.add(tab7, text='그래프5')
tab8 = ttk.Frame(tabControl)
tabControl.add(tab8, text='그래프6')
# 각 탭에 frame 만들기
tab3_frame = tk.Frame(tab3, bg='blue')
tab3_frame.pack(side = "top", pady = 10)
tab4_frame = tk.Frame(tab4, bg='blue')
tab4_frame.pack(side = "top", pady = 10)
tab5_frame = tk.Frame(tab5, bg='blue')
tab5_frame.pack(side = "top", pady = 10)
tab6_frame = tk.Frame(tab6, bg='blue')
tab6_frame.pack(side = "top", pady = 10)
tab7_frame = tk.Frame(tab7, bg='blue')
tab7_frame.pack(side = "top", pady = 10)
tab8_frame = tk.Frame(tab8, bg='blue')
tab8_frame.pack(side = "top", pady = 10)
# 데이터 핸들링
import pandas as pd
cctv = pd.read_csv(x ,encoding = 'UTF-8')
cctv.rename(columns={cctv.columns[0]:'구별'},inplace = True) # inplace: 변수의 내용을 갱신
pop = pd.read_excel(y,
header=2, # 세번째 줄부터 읽는 옵션
usecols = 'B,D,G,J,N') # B, D, G, J, N 열만 읽는 옵션
pop.rename(columns={pop.columns[0] : '구별',
pop.columns[1] : '인구수',
pop.columns[2] : '한국인',
pop.columns[3] : '외국인',
pop.columns[4] : '고령자'},
inplace = True) # inplace: 변수의 내용을 갱신
pop.drop([0], inplace = True) # 합계 행 지우기
pop.drop([26], inplace = True) # nan 값 있는 행 지우기
data_result = pd.merge(cctv, pop, on = '구별') # 두 데이터 합치기
# 의미 없는 칼럼 지우기
del data_result['2013년도 이전']
del data_result['2014년']
del data_result['2015년']
del data_result['2016년']
# index 를 '구별'로 설정하기
data_result.set_index('구별', inplace = True)
# matplotlib 폰트를 한글로 변경하기
import platform
import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus'] = False
if platform.system() == 'Darwin':
rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
path = "c:/Windows/Fonts/malgun.ttf"
font_name = font_manager.FontProperties(fname=path).get_name()
rc('font', family=font_name)
else:
print('Unknown system... sorry~~~~')
# 그래프 만들고 탭에 그리고 png로 저장
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
## 탭3에 그래프 1 그리고 png로 저장
tab3_graph = plt.figure()
plt.title("그래프 1. 구별 CCTV 현황", fontdict = { 'fontsize' : 15, 'fontweight' : 'bold'}, pad = 20)
data_result['소계'].plot(kind = 'barh', grid = True, figsize = (7,6))
canvas = FigureCanvasTkAgg(tab3_graph, master=tab3_frame)
canvas.get_tk_widget().grid()
plt.savefig('C:/Users/student/Desktop/python/P_4week/cctv_pop_graph1.png')
## 탭4에 그래프 2 그리고 png로 저장
tab4_graph = plt.figure()
plt.title("그래프 2. 구별 CCTV 현황_내림차순정렬", fontdict = { 'fontsize' : 15, 'fontweight' : 'bold'}, pad = 20)
data_result['소계'].sort_values().plot(kind = 'barh', grid = True, figsize = (7,6))
canvas = FigureCanvasTkAgg(tab4_graph, master=tab4_frame)
canvas.get_tk_widget().grid()
plt.savefig('C:/Users/student/Desktop/python/P_4week/cctv_pop_graph2.png')
## 탭5에 그래프 3 그리고 png로 저장
## 인구 대비 CCTV 비율 계산해서 정렬
tab5_graph = plt.figure()
data_result['CCTV비율'] = data_result['소계'] / data_result['인구수'] * 100
data_result['CCTV비율'].sort_values().plot(kind='barh', grid=True, figsize=(7,6))
plt.title("그래프 3. 구별 인구당 CCTV 비율 현황",fontdict = { 'fontsize' : 15, 'fontweight' : 'bold'}, pad = 20)
canvas = FigureCanvasTkAgg(tab5_graph, master=tab5_frame)
canvas.get_tk_widget().grid()
plt.savefig('C:/Users/student/Desktop/python/P_4week/cctv_pop_graph3.png')
## 탭6에 그래프 4 그리고 png로 저장
## scatter
tab6_graph = plt.figure(figsize=(7,6))
plt.title("그래프 4. 인구 수별 CCTV 개수(산포도)", fontdict = { 'fontsize' : 15, 'fontweight' : 'bold'}, pad = 20)
plt.scatter(data_result['인구수'], data_result['소계'], s=50)
plt.xlabel('인구수')
plt.ylabel('CCTV')
canvas = FigureCanvasTkAgg(tab6_graph, master=tab6_frame)
canvas.get_tk_widget().grid()
plt.savefig('C:/Users/student/Desktop/python/P_4week/cctv_pop_graph4.png')
## 탭7에 그래프 5 그리고 png로 저장
## scatter 함수 위에 직선 그리기
import numpy as np
fp1 = np.polyfit(data_result['인구수'], data_result['소계'], 1) # 다항식 만들기
f1 = np.poly1d(fp1) # f1() : y값 구하는 식 (직선 그리기)
fx = np.linspace(100000, 700000, 100) # x축
tab7_graph = plt.figure(figsize=(7,6))
plt.title("그래프 5. 인구 수별 CCTV 개수(산점도+추세선)", fontdict = { 'fontsize' : 15, 'fontweight' : 'bold'}, pad = 20)
plt.scatter(data_result['인구수'], data_result['소계'], s=50)
plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g') # y = f1(fx)
plt.xlabel('인구수')
plt.ylabel('CCTV')
plt.grid()
canvas = FigureCanvasTkAgg(tab7_graph, master=tab7_frame)
canvas.get_tk_widget().grid()
plt.savefig('C:/Users/student/Desktop/python/P_4week/cctv_pop_graph5.png')
## 탭8에 그래프 6 그리고 png로 저장
# 좀 더 설득력 있는 그래프 만들기
## 1. 직선에서 멀리 있는 값들은 이름이 같이 나타나게
## 2. 직선에서 멀어질수록 다른 색을 나타내도록
data_result['오차'] = np.abs(data_result['소계'] - f1(data_result['인구수'])) # 오차 계산
df_sort = data_result.sort_values(by='오차', ascending=False)
## color map 입히기
tab8_graph = plt.figure(figsize=(7,6))
plt.title("그래프 6. 인구 수별 CCTV 개수(산점도+추세선+색상)", fontdict = { 'fontsize' : 15, 'fontweight' : 'bold'}, pad = 20)
plt.scatter(data_result['인구수'], data_result['소계'], c=data_result['오차'], s=50)
plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g')
for n in range(10):
plt.text(df_sort['인구수'][n]*1.02, df_sort['소계'][n]*0.98,
df_sort.index[n], fontsize=10)
plt.xlabel('인구수')
plt.ylabel('인구당비율')
plt.colorbar()
canvas = FigureCanvasTkAgg(tab8_graph, master=tab8_frame)
canvas.get_tk_widget().grid()
plt.savefig('C:/Users/student/Desktop/python/P_4week/cctv_pop_graph6.png')
def tab2_click_me():
file1_err = "T"
if file1.get() == "":
file1_err = "F"
file2_err = "T"
if file2.get() == "":
file2_err = "F"
file3_err = "T"
if file3.get() == "":
file3_err = "F"
if file1_err == "T" and file2_err == "T" and file3_err == "T" :
action.configure(text="** 처리가 완료되었습니다. **")
save_file(file3.get(), scr) # 개요 파일 수정한거 저장하는 함수
graph_and_print(file1.get(), file2.get()) # 선택한 파일로 그래프 만들고 저장
# docx 문서 만들기
import docx
final_report = docx.Document()
with open(file3.get(), "r", encoding = "UTF-8") as T:
lines = T.readlines()
cont = []
for line in lines :
cont.append(line) # 개요사항 파일 내용 읽어오기
final_report.add_heading(cont[0], 0) # 개요사항 첫번 째 줄은 헤더 0
final_report.add_heading(cont[1:-1], 1) # 두번째 줄부터 마지막에서 두번째 줄까지 헤더 1
final_report.add_heading(cont[-1], 3) # 마지막 줄은 헤더3
## 그래프 넣기
final_report.add_picture("C:/Users/student/Desktop/python/P_4week/cctv_pop_graph1.png", \
width = docx.shared.Cm(14), \
height = docx.shared.Cm(11))
final_report.add_picture("C:/Users/student/Desktop/python/P_4week/cctv_pop_graph2.png", \
width = docx.shared.Cm(14), \
height = docx.shared.Cm(11))
final_report.add_picture("C:/Users/student/Desktop/python/P_4week/cctv_pop_graph3.png", \
width = docx.shared.Cm(14), \
height = docx.shared.Cm(11))
final_report.add_picture("C:/Users/student/Desktop/python/P_4week/cctv_pop_graph4.png", \
width = docx.shared.Cm(14), \
height = docx.shared.Cm(11))
final_report.add_picture("C:/Users/student/Desktop/python/P_4week/cctv_pop_graph5.png", \
width = docx.shared.Cm(14), \
height = docx.shared.Cm(11))
final_report.add_picture("C:/Users/student/Desktop/python/P_4week/cctv_pop_graph6.png", \
width = docx.shared.Cm(14), \
height = docx.shared.Cm(11))
final_report.add_paragraph('<결론> : \n 1. 서울시에서 다른 구와 비교했을 때, 강남구, 양천구, 서초구, 은평구는 CCTV가 많지만 \n2. 송파구, 강서구, 도봉구, 마포구는 다른 구에 비해 CCTV 비율이 낮다')
final_report.save(report_name.get() + ".docx")
else:
action.configure(text="** 다시 입력 해주세요 **")
# 버튼 추가
## cctv file 찾는 버튼
action = ttk.Button(grph,text="CCTV file 선택(csv) : ", width=15, command=file_get1)
action.grid(column=0, row=1,sticky='W')
## 인구 file 찾는 버튼
action = ttk.Button(grph,text="인구 file 선택(xls) : ", width=15, command=file_get2)
action.grid(column=0, row=2,sticky='W')
## 개요 file 찾는 버튼
action = ttk.Button(grph,text="개요 file 선택(txt) : ", width=15, command=file_get3)
action.grid(column=0, row=3,sticky='W')
## 실행 버튼
action = ttk.Button(grph, text="<<리포트 만들기>>", command=tab2_click_me)
action.grid(column=2, row=4,sticky='W')
# 레이블 추가
t2_label = ttk.Label(grph, text = "파일명을 지정하세요 :" , width=20,)
t2_label.grid(column = 0, row = 4)
t2_label2 = ttk.Label(grph, text = "마지막 줄의 enter를 지워주세요" , width=30,)
t2_label2.grid(column = 1, row = 5)
# 텍스트 박스 추가 (레이블 프레임 안에)
file1 = tk.StringVar()
file1_entered = ttk.Entry(grph, width=40, textvariable=file1)
file1_entered.grid(column=1, row=1)
file2 = tk.StringVar()
file2_entered = ttk.Entry(grph, width=40, textvariable=file2)
file2_entered.grid(column=1, row=2)
file3 = tk.StringVar()
file3.set("신규 파일이면 검색할 때 신규 생성하고 선택하세요")
file3_entered = ttk.Entry(grph, width=40, textvariable=file3)
file3_entered.grid(column=1, row=3)
report_name = tk.StringVar()
report_name_entered = ttk.Entry(grph, width=40, textvariable=report_name)
report_name_entered.grid(column=1, row=4)
# 스크롤 텍스트 박스
from tkinter import scrolledtext
import os
from tkinter.constants import END
scrol_w = 60 # 스크롤 박스 크기 지정
scrol_h = 20
scr = scrolledtext.ScrolledText(grph,width = scrol_w,
height = scrol_h,
wrap = tk.WORD) # wrap = tk.WORD - 단어단위 줄바꿈 지정
scr.grid(column=0, columnspan=10)
#개요 파일 읽어서 내용 보이는 함수
def open_file(file) :
if os.path.isfile(file) :
with open(file, "r", encoding = 'UTF-8') as f :
scr.insert(END, f.read())
#개요 파일 수정한거 저장하는 함수
def save_file(file, scr) :
with open(file, "w", encoding = "UTF-8") as f :
f.write(scr.get(1.0, END))
# =============================================================================
# 세번째 탭 만들기
# =============================================================================
# =============================================================================
# # < frame 만들기 >
# # tab 3에 프레임 만들기
#
# tab3_frame = tk.Frame(tab3, bg='blue')
# tab3_frame.pack(side = "top", pady = 10)
#
# =============================================================================
# =============================================================================
# 메뉴 만들기
# =============================================================================
# Creating a Menu Bar
from tkinter import Menu
from tkinter import messagebox as msg
menu_bar = Menu(win) # 취상위 메뉴 = menu_bar
win.config(menu=menu_bar) # 최상위 메뉴 만들기
# Add menu items
file_menu = Menu(menu_bar, tearoff=0) # 최상위 메뉴 아래에 file_menu 만들기
menu_bar.add_cascade(label="File", menu=file_menu) # file_menu를 "File" 이라는 이름으로 메뉴 만들기
# .add_cascade -> 메뉴를 수직으로 정렬
# Exit 함수 만들기
def _quit():
win.quit()
win.destroy()
exit()
file_menu.add_command(label="New") # file 메뉴에 "New" 탭 추가
file_menu.add_separator() # 메뉴 구분
file_menu.add_command(label="Exit", command=_quit) # file 메뉴에 "Exit" 탭 추가 + 명령함수 (_quit)
# Display a Message Box
def _msgBox():
msg.showinfo('Information', '멀티캠퍼스 프로젝트 (author : 이혁수)\n만든년도 2020.')
# Add another Menu to the Menu Bar and an item
help_menu = Menu(menu_bar, tearoff=0) # 최상위 메뉴 아래에 help_menu 만들기
menu_bar.add_cascade(label="Help", menu=help_menu) # help_menu를 "Help"라는 이름으로 메뉴 만들기
help_menu.add_command(label="About", command=_msgBox) # display messagebox when clicked
# =============================================================================
# 실행 아이콘 만들기
# =============================================================================
# Change the main windows icon 아이콘 변경
win.iconbitmap('C:/Users/student/Desktop/python/P_3week/Sonya-Swarm-Cat.ico') # ico 파일
# =============================================================================
# 실행
# =============================================================================
win.mainloop()