思路分析
首先是获取三个或以上的url(带参数的url)
然后通过字符串方法将url中的基础url跟参数分离开
通过对比多个url中的同一个参数的值,
将参数分成三类
一类为不变的参数,一类为会改变的参数,还有一类是时有时无(可有可无)的参数
最后做成GUI,界面设想如下
在左上方的text窗输入url,点击加入,在右侧列表窗会显示已添加的url,如果存在希望删除的url,点击列表窗中对应的url,点击删除即可从列表窗中移除,点击解析,即对url进行解析
代码实现
GUI部分
QT界面虽易做,可惜还没时间去研究QT的gui后台代码怎么实现,所以还是用tkinter好了
以下是界面代码
from tkinter import *
import tkinter.messagebox
import re
from urlparser import URLparser
from threading import Timer
import time
import json
def ListboxClick(event):
keyname = listbox_result.get(ACTIVE)
content = json.loads(label_hidden["text"])
label_result["text"] = content[keyname]
def timmer():
now = "现在时间 >>> "
now += time.strftime("%Y - %m - %d %H : %M : %S")
label_time["text"] = now
timer = Timer(1, timmer)
timer.start()
def Button_rebootClick(event):
result = tkinter.messagebox.askquestion(title="提示", message="是否重置?")
if result == "no":
return None
text_input.delete(0.0, END)
listbox_show.delete(0, 29)
label_result["text"] = ""
label_number["text"] = "url个数:0"
def Button_joinClick(event):
num = int(label_number["text"].split(":")[-1])
if num == 30:
return None
# 获得输入框内容
url = text_input.get(0.0, END)[0:-1]
# 删除输入框内容
text_input.delete(0.0, END)
# 匹配正则表达式,是否为空
space_reg = re.compile(r"^\s*$")
if space_reg.match(url):
return None
# 匹配正则表达式,是否为正常的url格式
url_reg = re.compile(r"^(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]$")
if not url_reg.match(url):
result = tkinter.messagebox.askquestion(title="url匹配提示", message="您输入的url格式可能不正确,确定要添加?")
if result == "no":
return None
# 加入列表框
listbox_show.insert(END, url)
num += 1
# 修改个数
label_number["text"] = "url个数:" + str(num)
def Button_clearClick(event):
num = int(label_number["text"].split(":")[-1])
if num == 0:
return
# 删除列表框选中内容
listbox_show.delete(ACTIVE)
num -= 1
# 修改个数
label_number["text"] = "url个数:" + str(num)
def Button_parseClick(event):
# 第一步,取得列表框存放的所有url
reg = re.compile(r"^\s*$")
url_list = []
index = 0
while True:
url = listbox_show.get(index)
if reg.match(url):
break
url_list.append(url)
index += 1
# 第二步,传入后台处理,返回结果
parser = URLparser.UrlParser()
result = parser.parse(url_list)
for key, value in result.items():
listbox_result.insert(END, key)
if key.startswith("主体url:"):
label_result["text"] = value
# 第三步,将获得的结果放到隐藏标签里
result = json.dumps(result)
label_hidden["text"] = result
# 主窗口
window = Tk()
window.maxsize(1000, 600)
window.minsize(1000, 600)
window.title("带参数url解析器")
# 文本输入框
Label(window, text="请在下方输入框输入url", font=(15,)).place(x=20, y=10)
text_input = Text(window, width=50, height=10, borderwidth=5, relief=SUNKEN, font=(15,))
text_input.place(x=20, y=40)
# url列表框
Label(window, text="已输入的url列表", font=(15,)).place(x=570, y=10)
label_number = Label(window, text="url个数:0", font=(15,))
label_number.place(x=890, y=10)
# # 框架
frame_listbox_show = Frame(window)
frame_listbox_show.place(x=570, y=40)
# # 滚动条
show_scx = Scrollbar(frame_listbox_show, orient=HORIZONTAL)
show_scx.pack(side=BOTTOM, fill=X)
show_scy = Scrollbar(frame_listbox_show)
show_scy.pack(side=RIGHT, fill=Y)
# # url列表框
listbox_show = Listbox(frame_listbox_show, width=48, height=28, borderwidth=5, relief=SUNKEN, font=(15,),
xscrollcommand=show_scx.set, yscrollcommand=show_scy.set)
listbox_show.pack(side=LEFT, fill=BOTH)
show_scx.config(command=listbox_show.xview)
show_scy.config(command=listbox_show.yview)
# 结果列表框
Label(window, text="url解析结果如下", font=(15,)).place(x=20, y=215)
# # 框架
frame_listbox_result = Frame(window)
frame_listbox_result.place(x=20, y=242)
# # 滚动条
result_scx = Scrollbar(frame_listbox_result, orient=HORIZONTAL)
result_scx.pack(side=BOTTOM, fill=X)
result_scy = Scrollbar(frame_listbox_result)
result_scy.pack(side=RIGHT, fill=Y)
# # 结果列表框
listbox_result = Listbox(frame_listbox_result, width=28, height=17, relief=SUNKEN, font=(15,), borderwidth=5,
xscrollcommand=result_scx.set, yscrollcommand=result_scy.set)
listbox_result.pack(side=LEFT)
result_scx.config(command=listbox_result.xview)
result_scy.config(command=listbox_result.yview)
label_hidden = Label(window, width=10, height=10, text="这是隐藏标签")
label_hidden.place(x=300, y=250)
label_result = Label(window, font=(15,), borderwidth=5, relief=SUNKEN, width=30, height=19)
label_result.place(x=295, y=242)
# 按钮
# # 加入
button_join = Button(window, text="加 入", width=10, height=1, font=(15,), borderwidth=5, relief=RAISED)
button_join.place(x=450, y=50)
# # 删除
button_clear = Button(window, text="删 除", width=10, height=1, font=(15,), borderwidth=5, relief=RAISED)
button_clear.place(x=450, y=108)
# # 解析
button_parse = Button(window, text="解 析", width=10, height=1, font=(15,), borderwidth=5, relief=RAISED)
button_parse.place(x=450, y=166)
# 底部栏
button_reboot = Button(window, text="重 置", width=10, height=1, borderwidth=5, relief=RAISED, font=(15,))
button_reboot.place(x=882, y=562)
now = "现在时间 >>> "
now += time.strftime("%Y - %m - %d %H : %M : %S")
label_time = Label(window, text=now, font=(15,))
label_time.place(x=20, y=570)
# 绑定事件
# # 加入按钮左键点击事件
button_join.bind("<ButtonRelease-1>", Button_joinClick)
# # 删除按钮左键点击事件
button_clear.bind("<1>", Button_clearClick)
# # 解析按钮左键点击事件
button_parse.bind("<1>", Button_parseClick)
# # 重置按钮左键点击事件
button_reboot.bind("<ButtonRelease-1>", Button_rebootClick)
# # 列表框点击事件
listbox_result.bind("<1>", ListboxClick)
# 设置定时器
timer = Timer(1, timmer)
timer.start()
# 主窗口运行
window.mainloop()
暂时还没有封装成类,界面也一般,不过这次加了定时器,可以定时刷新内容,牛刀小试,每秒刷新一次时间好了
界面看着其实还不赖
两个结果窗显示的原理大概就是将加入的url送到后台,解析后得到的结果是一个字典
左边的列表框显示的是字典的键,右边的标签显示的是单一某键对应的键值,一般就是某个参数的结果罗列
通过点击右侧的列表框的具体内容决定右侧标签显示何种内容
在显示结果的标签框 label_result 背后由一个专门存放全部数据的隐藏标签,即是代码中的 label_hidden
需要切换内容的时候即从 label_hidden 中提取出来数据以调用
后端url处理部分
通过前端得到的一个列表
首先分析一下url是否为有?存在的带参url,如果不是,则返回带有错误提示信息的字典
然后遍历分析url主体是否一致(为了避免有时手残输错别的url),确定一致了才仅需进行参数解析,但需要注意的是,即便是同一个网站,也会有出现http或https各种开头的情况,为了避免这种状况,url主体只取到https://后面到?前面的部分来进行对比
接下来就是参数分析,其实也简单,以&分割参数,获得参数键值对列表,再对参数列表进行遍历,以=分割键与值,将拥有相同键名的键值存放到另一字典中相同键名下的列表里
最后将存放参数的字典进行遍历,
第一步分析是否为可缺省参数,键值中的参数列表的长度小于输入url列表的长度即为存在缺省,意味着该参数可缺省,如果是可缺省,continue继续下一次循环
第二步分析是否为不变参数,计算键值中的参数列表的集合长度,如果为1,即为不变参数
否则则是或改变参数
最后将分析结果做成字典,输出到前端
具体代码如下
import re
class UrlParser(object):
def parse(self, url_list):
'''
:param url_list: 一个至少包含3个url的列表
:return:
'''
key_list = []
result = {}
for index, url in enumerate(url_list):
# 第一步,分离url主体,若存在不相同,返回提示
if "?" not in url:
return {str(index + 1): "第%d个url不属于带参数型url" % (index + 1)}
all_part = url.split("?")
url_reg = re.compile(r"^(https?|ftp|file)://([-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|])$")
uurl = url_reg.findall(all_part[0])[0][1]
if index > 0:
if uurl != main_url:
return {str(index + 1): "第%d个url的主体url与其前面的url主体不相同" % (index + 1)}
else:
main_url = uurl
all_params = all_part[1]
# 第二步,分离参数
param = all_params.split("&")
# 第三步,分离键值对
for p in param:
k_v = p.split("=")
key = k_v[0]
value = k_v[1]
if key not in key_list:
result[key] = []
key_list.append(key)
result[key].append(value)
# 解析参数
num = len(url_list)
output = {"主体url:" + main_url: "双击左侧参\n数查看详情"}
for key, value in result.items():
# 判断是否为可缺省参数
if len(value) < num:
output["参数可缺省: " + key] = key + " : \n" + "\n".join(value) + "\nNone" * (num - len(value))
continue
# 判断是否为不变参数
if len(set(value)) == 1:
output["参数不变: " + key] = key + " : \n" + "\n".join(value)
else:
output["参数或改变: " + key] = key + ": \n" + "\n".join(value)
return output
结果展示
取了百度贴吧三个搜索结果下的url,分别是python,matlab,c
http://tieba.baidu.com/f?ie=utf-8&kw=python&fr=search
http://tieba.baidu.com/f?ie=utf-8&kw=matlab&fr=search
http://tieba.baidu.com/f?ie=utf-8&kw=c&fr=search
加入到列表框之后,点击""解析""