1.背景
之前写过一个Python调用IDM批量下载GOCI数据的博客。但是使用脚本下载不是太方便。使用Tkinter做了一个图形用户界面,这样更加直观的进行下载。其原理和之前的博客一致,需要IDM下载器支持。
软件配置:
python:3.6.5
tkinter:8.6
2.功能介绍
客户端主要有三个下载选项:‘指定一天’、‘连续多天’、‘指定多日’。需要在底部选择IDMan.exe位置(因为每个人安装IDM的位置不一样,所以这里进行路径选择)和数据要保存的位置。在选择文件或者文件夹的路径时,为了保证路径正确,这里设置无法手动输入,只能在对话框选择。
2.1.指定一天
在软件运行后,选择指定一天选项卡,输入指定日期,就可以完成下载。设计界面如下:
2.2.连续多天
在连续多天选项卡中,输入开始日期和结束日期,完成下载。设计界面如下:
2.3.指定多日
有时候,需要挑选特定的几天,所以这里也提供了该功能。首先将所要的日期填入excel表中,然后由软件读取excel表。excel表的文件格式如下:
设计下载界面如下:
3.主要代码
直接保存代码,运行即可。
from tkinter import Tk
from tkinter import ttk
from tkinter import Menu
from tkinter import Button
from tkinter import Toplevel
from tkinter import filedialog
from tkinter import messagebox
from tkinter import Label
from tkinter import Entry
from tkinter import StringVar
from tkinter import Frame
import pandas as pd
import datetime
import os
from urllib.error import URLError,HTTPError,ContentTooShortError
from bs4 import BeautifulSoup
import urllib
from subprocess import call
def downseq(DAYLIST):
save=SavePath.get()
idm=IDMPath.get()
#根据日期,定位到某一日的数据存储位置,注意日期和月份应该用两位数字表示
for dl in DAYLIST:
urllist=[]
dayfiledir=save+'/'+dl
os.makedirs(dayfiledir)
ymd=dl.split('-')
DayUrl='http://222.236.46.45/nfsdb/COMS/GOCI/1.0/'+str(ymd[0])+'/'+str(ymd[1]).zfill(2)+'/'+str(ymd[2]).zfill(2)+'/L1B/'
#开始爬取
try:
DayHTML= urllib.request.urlopen(DayUrl).read()
soup=BeautifulSoup(DayHTML,'html.parser')
alink=soup.find_all('a') #获取界面下所有标签为a的元素
for A in alink:
fileUrl=A.get('href') #数据的下载链接
filename=fileUrl.split('/')[-1]
#该判断用于剔除返回上一级目录的链接
if filename=='':
continue
else:
urllist.append('http://222.236.46.45'+fileUrl) #将有效的链接加入到列表中
except(URLError,HTTPError,ContentTooShortError):
messagebox.showerror('错误',dl+'数据问题')
print(dl+'数据存在问题')
return
for ul in urllist:
call([idm, '/d',ul, '/p',dayfiledir,'/n','/a'])
call([idm,'/s'])
def IDMFind():
idmpath_= filedialog.askopenfilename(filetypes=[('EXE', '*.exe')])
IDMPath.set(idmpath_)
def SaveFind():
savepath_=filedialog.askdirectory()
SavePath.set(savepath_)
def OpenExcel():
excelpath_=filedialog.askopenfilename(filetypes=[('EXCEL', '*.xlsx')])
excelfile.set(excelpath_)
def somday():
excelpath=excelfile.get()
dayframe=pd.read_excel(excelpath,header=0,index_col=None)
dayarray=dayframe.values
daylist=[]
for sv in dayarray:
date=str(sv[0])+'-'+str(sv[1])+'-'+str(sv[2])
try:
datetime.datetime.strptime(date,'%Y-%m-%d')
daylist.append(date)
except ValueError:
messagebox.showerror('错误','输入日期有误')
return
#为了保证输入的日期不重复,先将列表转集合,再转回列表
dls=set(daylist)
daylist=list(dls)
return daylist
def contday():
styear=sty.get()
stmon=stm.get()
stday=std.get()
startdate=styear+'-'+stmon+'-'+stday
edyear=edy.get()
edmon=edm.get()
edday=edd.get()
enddate=edyear+'-'+edmon+'-'+edday
daylist=[]
try:
start_date=datetime.datetime.strptime(startdate,'%Y-%m-%d')
end_date=datetime.datetime.strptime(enddate,'%Y-%m-%d')
if start_date>end_date:
messagebox.showerror('错误','起始日期和结束日期输入错误')
return
else:
while start_date<=end_date:
datestr=start_date.strftime('%Y-%m-%d')
daylist.append(datestr)
start_date=start_date+datetime.timedelta(days=1)
return daylist
except ValueError:
messagebox.showerror('错误','输入日期有误')
return
def oneday():
syear=sy.get()
smon=sm.get()
sday=sd.get()
date=syear+'-'+smon+'-'+sday
try:
datetime.datetime.strptime(date,'%Y-%m-%d')
daylist=[date]
return daylist
except ValueError:
messagebox.showerror('错误','输入日期有误')
return
def StartDowmload():
#首先判断哪种下载类型
#再根据下载类型构建日期列表
idm=IDMPath.get()
save=SavePath.get()
if idm=='':
messagebox.showerror('错误','请选择IDM位置')
return
modelindex=notebook.index('current')
if save=='':
messagebox.showerror('错误','请选择保存路径')
return
daylist=[]
if modelindex==0:
daylist=oneday()
elif modelindex==1:
daylist=contday()
else:
daylist=somday()
if daylist:
downseq(daylist)
else:
messagebox.showerror('错误','输入日期有误')
return
root=Tk()
root.title('GOCI--Download')
root.geometry("500x380") #小写x
root.resizable(0,0)
#建立三个Frame
notebook = ttk.Notebook(root)
frameOne = Frame()
frameTwo = Frame()
frameThr = Frame()
#指定一天的Frame
#---------------------------------------------------------#
sy=StringVar()
sm=StringVar()
sd=StringVar()
explainlabel0=Label(frameOne,text='输入日期:')
explainlabel0.place(x=70,y=70,anchor='nw')
syearentry=Entry(frameOne,textvariable=sy)
syearentry.place(x=140,y=70,anchor='nw',height=25,width=50)
syearlabel=Label(frameOne,text='年',anchor='w')
syearlabel.place(x=195,y=70,anchor='nw',height=25,width=15)
smonentry=Entry(frameOne,textvariable=sm)
smonentry.place(x=220,y=70,anchor='nw',height=25,width=50)
smonlabel=Label(frameOne,text='月',anchor='w')
smonlabel.place(x=275,y=70,anchor='nw',height=25,width=15)
sdayentry=Entry(frameOne,textvariable=sd)
sdayentry.place(x=300,y=70,anchor='nw',height=25,width=50)
sdaylabel=Label(frameOne,text='日',anchor='w')
sdaylabel.place(x=355,y=70,anchor='nw',height=25,width=15)
#---------------------------------------------------------#
#连续多日的Frame
#---------------------------------------------------------#
sty=StringVar()
stm=StringVar()
std=StringVar()
edy=StringVar()
edm=StringVar()
edd=StringVar()
explainlabel1=Label(frameTwo,text='开始日期:')
explainlabel1.place(x=70,y=40,anchor='nw')
styearentry=Entry(frameTwo,textvariable=sty)
styearentry.place(x=140,y=40,anchor='nw',height=25,width=50)
styearlabel=Label(frameTwo,text='年',anchor='w')
styearlabel.place(x=195,y=40,anchor='nw',height=25,width=15)
stmonentry=Entry(frameTwo,textvariable=stm)
stmonentry.place(x=220,y=40,anchor='nw',height=25,width=50)
stmonlabel=Label(frameTwo,text='月',anchor='w')
stmonlabel.place(x=275,y=40,anchor='nw',height=25,width=15)
stdayentry=Entry(frameTwo,textvariable=std)
stdayentry.place(x=300,y=40,anchor='nw',height=25,width=50)
stdaylabel=Label(frameTwo,text='日',anchor='w')
stdaylabel.place(x=355,y=40,anchor='nw',height=25,width=15)
explainlabel2=Label(frameTwo,text='结束日期:')
explainlabel2.place(x=70,y=95,anchor='nw')
edyearentry=Entry(frameTwo,textvariable=edy)
edyearentry.place(x=140,y=95,anchor='nw',height=25,width=50)
edyearlabel=Label(frameTwo,text='年',anchor='w')
edyearlabel.place(x=195,y=95,anchor='nw',height=25,width=15)
edmonentry=Entry(frameTwo,textvariable=edm)
edmonentry.place(x=220,y=95,anchor='nw',height=25,width=50)
edmonlabel=Label(frameTwo,text='月',anchor='w')
edmonlabel.place(x=275,y=95,anchor='nw',height=25,width=15)
eddayentry=Entry(frameTwo,textvariable=edd)
eddayentry.place(x=300,y=95,anchor='nw',height=25,width=50)
eddaylabel=Label(frameTwo,text='日',anchor='w')
eddaylabel.place(x=355,y=95,anchor='nw',height=25,width=15)
#---------------------------------------------------------#
#指定多日的Frame
#---------------------------------------------------------#
excelfile=StringVar()
excellabel=Label(frameThr,text='Excel文件位置:')
excellabel.place(x=20,y=70,anchor='nw',height=25,width=100)
excelentry=Entry(frameThr,textvariable=excelfile,state='disabled')
excelentry.place(x=130,y=70,anchor='nw',height=25,width=230)
excelbutton=Button(frameThr,text='浏览文件',command=OpenExcel)
excelbutton.place(x=370,y=70,anchor='nw',height=25,width=80)
#---------------------------------------------------------#
notebook.add(frameOne, text='指定一天')
notebook.add(frameTwo, text='连续多日')
notebook.add(frameThr, text='指定多日')
notebook.place(x=10,y=10,anchor='nw',height=200,width=480)
#选择IDM位置和文件保存位置
IDMPath=StringVar()
SavePath=StringVar()
IDMLabel=Label(root,text='IDM程序位置: ',anchor='w')
IDMLabel.place(x=10,y=230,anchor='nw',width=100,height=30)
IDMEntry=Entry(root,textvariable=IDMPath,state='disabled')
IDMEntry.place(x=120,y=230,anchor='nw',width=240,height=30)
IDMButton=Button(root,text='浏览位置',command=IDMFind)
IDMButton.place(x=380,y=230,anchor='nw',width=100,height=30)
SaveLabel=Label(root,text='保存文件位置:',anchor='w')
SaveLabel.place(x=10,y=275,anchor='nw',width=100,height=30)
SaveEntry=Entry(root,textvariable=SavePath,state='disabled')
SaveEntry.place(x=120,y=275,anchor='nw',width=240,height=30)
SaveButton=Button(root,text='浏览位置',command=SaveFind)
SaveButton.place(x=380,y=275,anchor='nw',width=100,height=30)
StartButton=Button(root,text='开始下载',command=StartDowmload)
StartButton.place(x=200,y=330,anchor='nw',width=100,height=40)
root.mainloop()
4.结束
(a)程序会根据输入的日期,按照日期新建文件夹,将每天的数据放在同一个文件夹里。
(b)程序没有对输入的日期进行时间范围检查。请大家注意。
(c)如果有的日期没有下载到数据,可以手动检查一下,可能那天真的没有数据。
(d)程序还有不足的地方,请不吝赐教。
(e)界面设计真的是个大问题。