想用tkinter写个桌面程序
tkinter参考资料主要有官方文档,还有一本台湾人写的书tkinter菜鸟编程.此外还有一堆抄来抄去的书.我觉得只要多练就行了,看看官方写的代码
主要解决问题:
- tkinter的控件布局.整洁好看,不过这并不是最重要的
- 调用程序,触发一个选项后要有调用的函数
- 多线程.不然界面会出现未响应
一些小问题 控件的大小,字体颜色与大小 利用python打开资源管理器Python调Windows的资源管理器打开指定目录 - famiover - OSCHINA - 中文开源技术交流社区
1.布局问题
tkinter布局一般,不像PyQt拖拽式那样简单.
一般用到的控件Label,Entry,Button,messagebox,menu,text,toplevel(打开新窗口)
像按钮啥的暂时用不上
同时还有添加图像时有时图片太大,可以利用
from PIL import Image
photo = Image.open("小猫.jpg") #括号里为需要显示在图形化界面里的图片
photo = photo.resize((400,400)) #规定图片大小
python 使用图形化界面tkinter显示图片 规定大小!_地中海的博客-CSDN博客_tkinter设置图片大小
2.调用程序
tkinter两种方法
command调用与bind绑定
不过我发现
控件command=callback传参不方便,只能利用
-
lambda函数
-
IntVar() StringVar()等这种变量设置
而bind会传一个参数event
可以得到相关参数(例如鼠标点击位置啥的)
建议一个空间不要同时用这两个调用
3.多线程
主要是要将桌面主程序与爬虫等程序分开
上次讲了python多线程利用threading模块的两种写法
import thread
import time
class Mythread(threading.Thread):
def __init__(self,name=None):
super().__init__(name=name)
def run(self):
for i in range(5):
n = threading.currentThread()
time.sleep(1)
print("现在是{0}的第{1}次".format(n.name,i))
print("子线程执行完了")
if __name__ == "__main__":
mythread = Mythread("张三")
mythread.setDaemon(True) #守护线程,当主线程执行完后,子线程强制关闭
mythread.start()
mythread.join() #必须当这个子线程执行完,主线程才开始执行
for i in range(5):
time.sleep(1)
n = threading.currentThread()
print("现在是{0}的第{1}次".format(n.name, i))
可以看出join之后子线程先执行完,若去掉join
注意主线程与子线程同时执行并且当主线程执行完,子线程关闭
遇到的问题
特别注意的是,我添加图片时,如果在函数里添加,那么图片就没了(程序没有报错,但图片显示空白)
我把那段代码改在主函数里就行了,猜测可能是因为GC机制回收了
完整代码
import time
from tkinter.ttk import *
import tkinter as tk
from tkinter import *
import requests
from tkinter import messagebox
from lxml import etree
import os
import os.path
import threading
from PIL import Image, ImageTk
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.button = tk.Button(self, text="确定", ) # command=self.get_info)
self.entry = tk.Entry(self, font="times 15")
self.endbtn = Button(self, text="结束", command=stop)
self.label1 = tk.Label(self, text="请输入爬取的页数范围:\n例子:1,2", font="times 15", relief="raised")
self.create_widget()
self.pack()
def create_widget(self):
self.entry.insert(0, "1,2")
self.label1.pack(side=LEFT, fill=BOTH)
self.entry.pack(fill=X)
self.button.pack(fill=BOTH)
self.button.bind("<Button-1>", self.get_info)
self.entry.bind("<Return>", self.get_info)
self.endbtn.pack(fill=X)
def get_info(self, event):
entry_info = self.entry.get()
try:
fir_page = int(entry_info.split(",")[0])
sec_page = int(entry_info.split(",")[1])
except IndexError as e:
messagebox.showwarning("提示", "输入格式错误\n%s" % e)
return
except ValueError as e:
messagebox.showwarning("提示", "输入格式错误\n%s" % e)
return
except Exception as e:
messagebox.showwarning("提示", "输入格式错误\n%s" % e)
return
spider = Spider(fir_page, sec_page)
spider.setDaemon(True)
var.set("正在爬取...")
spider.start()
# spider.join() 这里如果join了运行爬虫桌面程序多半会卡
class Spider(threading.Thread):
# global info
# location = os.getcwd() + '/fake_useragent.json'
# ua = UserAgent(path=location)
__headers = {'user_agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55", "Connection": "close"}
# __base_url = "https://konachan.net/"
# __url = "https://konachan.net/post?page={}"
__url = "https://gelbooru.com/index.php?page=post&s=list&tags=all&pid={}"
flag = False
def __init__(self, fir_page, sec_page):
Spider.flag = False
super().__init__(None)
# self.fir_page = fir_page
# self.sec_page = sec_page
self.fir_page = (fir_page - 1) * 42
self.sec_page = sec_page * 42
self.tag = True
def run(self):
pb.start()
self.parse()
pb.stop()
var.set("爬取完毕")
messagebox.showinfo("提示消息", "爬取结束了")
def parse(self):
text.delete("1.0", END)
requests.adapters.DEFAULT_RETRIES = 5
text.insert(END, "下载至{}\n".format(os.getcwd() + r'\images或\videos'))
# info += "下载至{}\n".format(os.getcwd() + r'\images或\videos')
# msg_var.set(info)
for n in range(self.fir_page, self.sec_page + 1):
if Spider.flag:
break
time.sleep(1.5)
try:
res = requests.get(self.__url.format(n), headers=self.__headers)
except requests.exceptions.ConnectionError as e:
messagebox.showinfo("出现问题", "爬取频繁,请连接代理\n%s" % e)
pb.stop()
var.set("爬取完毕")
return
selector = etree.HTML(res.text)
# images_urls = selector.xpath("//ul[@id='post-list-posts']/li//a[@class='thumb']/@href")
images_urls = selector.xpath("//article//a/@href")
for image_url in images_urls:
if Spider.flag:
break
self.parse_next(image_url)
def parse_next(self, image_url):
# image_id = image_url.split("/")[3]
# next_url = self.__base_url + image_url
image_id = image_url.split("=")[-1]
next_url = image_url
time.sleep(1.5)
res = requests.get(next_url, headers=self.__headers)
selector = etree.HTML(res.text)
# img = selector.xpath("//img[@id='image']/@src")[0]
try:
img = selector.xpath("//img[@id='image']/@src")[0]
except IndexError:
img = selector.xpath("//video/source[1]/@src")[0] # 这是图片
self.tag = False
self.download(img, image_id)
def download(self, img, image_id):
if Spider.flag:
return
time.sleep(0.5)
suffix = img.split(".")[-1]
res = requests.get(img, headers=self.__headers)
text.insert(END, "正在下载:%s\n" % img)
# info += "正在下载:%s\n" % img
# msg_var.set(info)
if self.tag:
if not os.path.exists("./images"):
os.mkdir("./images")
with open('images/{0}.{1}'.format(image_id, suffix), 'wb+') as f:
f.write(res.content)
else:
if not os.path.exists("./videos"):
os.mkdir("./videos")
with open('videos/{0}.{1}'.format(image_id, suffix), 'wb+') as f:
f.write(res.content)
text.insert(END, "下载成功:%s\n" % img)
# info += "下载成功:%s\n" % img
# msg_var.set(info)
def stop():
Spider.flag = True
def open_current():
base_path = os.getcwd()
if not os.path.exists("./images"):
is_cre = messagebox.askyesno("提示", "不存在图片文件夹,是否创建?")
if is_cre:
os.mkdir("./images")
path = base_path + r"\images"
else:
path = base_path
else:
path = base_path + r"\images"
os.system("explorer.exe %s" % path)
def show_myinfo():
my_info = """
website:http://sekyoro.top/
github:https://github.com/drowning-in-codes
一起学习
"""
toplevel = Toplevel()
toplevel.title("关于我")
toplevel.iconbitmap("th.ico")
toplevel.geometry("400x350")
info_label = Label(toplevel, font="times 15", text=my_info, image=info_tk_image, compound="top", justify="left")
info_label.pack()
def set_window():
root.title("桌面爬虫")
root.geometry("400x450")
root.iconbitmap("th.ico")
label.pack()
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="Open", command=open_current)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.destroy)
helpmenu = Menu(menubar, tearoff=0)
helpmenu.add_command(label="About me", command=show_myinfo)
menubar.add_cascade(label="Help", menu=helpmenu)
root.config(menu=menubar)
text_label = Label(root, textvariable=var).pack()
if __name__ == "__main__":
root = tk.Tk()
image = Image.open("OIP-C.gif")
image = image.resize((200, 200))
# info = "爬取信息\n"
image_tk = ImageTk.PhotoImage(image)
label = tk.Label(root, font="20", fg="blue", text="欢迎使用", image=image_tk, compound="top")
var = StringVar()
set_window()
pb = Progressbar(root, mode="indeterminate", length=200, name="进度")
pb["value"] = 0
pb["maximum"] = 100
pb.pack()
app = Application(root)
info_image = Image.open("info.png")
info_image = info_image.resize((200, 200))
info_tk_image = ImageTk.PhotoImage(info_image)
# msg_var = StringVar()
# msg = Message(root, textvariable=msg_var, relief="raised")
# msg.pack(padx=10, pady=10)
# msg_var.set(info)
# 待滚轮的text
yscrollbar = Scrollbar(root)
text = Text(root)
yscrollbar.pack(side=RIGHT, fill=Y)
text.pack()
yscrollbar.config(command=text.yview)
text.config(yscrollcommand=yscrollbar.set)
app.mainloop()
最后pyinstaller -w -F name.py打包就行了
大概长这样,看来要多多尝试