效果展示


项目目录,与命令行版扫描器同:

前言

这篇文章与前一篇原理相同,都是对生成的可能链接进行试错验证,所以我们不再讨论原理部分,主要内容放在语言的继承和窗口的可视化上。

图形化界面我采用了tkinter标准库,没有什么特殊原因,只是不需要另外安装。

首先,先明确一件事情,tkinter不属于Python语言本身。tkinter是一个开放源码的图形接口开发工具,最初是用TCL编写的GUI函数库,它提供许多图形接口,Python将其移植到自己的内建模块里。所以说,tkinter就是tkinter它自己,Python只是借用,并不属于自己的一部分。

其中每个部件我们有个统一的名称叫“控件”,英文为widget。

你可以选择任意你习惯的第三方库,能达成效果就好。

设计实现

可视化

因为核心部分在命令行版就已经做了分析与设计,所以我们从GUI开始。


简单将其分成五部分来进行说明。(在实际的设计中,应当是预先想好设计图纸,然后再根据特性去实现。我们现在反过来了,看着已经实现的东西,来编写代码。)

接收根目录的Widget(1)

这里很好找到适合的控件,只是个简单的接收输入功能嘛。用Entry就好:

window = tk.Tk()
window.title('Web Scanner    by 刑者')
window.geometry('600x400')
window.config(background='#CCE8CF')entry = tk.Entry(window)
entry.place(x=100, y=10)

接收进程数与超时时长的widget(2)

第二部分的两个使用了同一widget——Combobox,它属于tkinter里ttk的内容。

Combobox可以当成Entry和下拉菜单的组合,文章开头的截图里没有进行数值选择的演示,大家可以自行操作。

from tkinter import ttkthread_num = tk.StringVar()
comboxlist = ttk.Combobox(window, textvariable=thread_num)
comboxlist["values"] = ('1', '3', '5')
comboxlist.current(0)
comboxlist.place(x=100, y=50)timeout = tk.StringVar()
comboxlist1 = ttk.Combobox(window, textvariable=timeout)
comboxlist1["values"] = ('1', '0.5', '0.1')
comboxlist1.current(0)
comboxlist1.place(x=100, y=90)

二者分别规定了可选范围(values),其中的current方法是设置默认数值,比如两个combobox都是使用current(0)作为默认值,在运行是它就会分别取values中下标为0的值,作为显示值。

到这大家可能看到了,我所有的widget都是使用place方法进行的配置。我必须要承认,这不是一个好的配置方式。在大部分情况下,应当优先选择pack方法,pack使用相对位置的概念处理控件配置,是三个配置器中,灵活性最高,延展性最好的一个。(另一个是grid,一般在设计表格型布局的时候使用,比如我们这里的第三部分——复选框。)

上面所说的三个方法呢,用来包装和定位各组件在容器或者窗口内的位置,我们也叫做窗口控件配置管理器(Widget Layout Manager,有的书上翻译成了配置管理员,我觉得不好听)。

而我这里使用place绝对位置来处理,直接固定住控件的位置的原因,只是单纯的因为懒。(使用pack会多一些参数,这个人懒得调参~)

选择目录字典(3)

在图中的第三部分,我们给了一组复选框,让用户根据网站开发情况,有针对性的选择合适的字典进行扫描。

复选框,使用Checkbutton。

你会怎样写这6个Checkbutton呢?可以这样:

status_asp = tk.BooleanVar()
status_aspx = tk.BooleanVar()
status_dir = tk.BooleanVar()
status_jsp = tk.BooleanVar()
status_mdb = tk.BooleanVar()
status_php = tk.BooleanVar()cb_asp = tk.Checkbutton(window, text='ASP', variable=status_asp).place(x=400, y=10)
cb_aspx = tk.Checkbutton(window, text='ASPX', variable=status_aspx).place(x=400, y=50)
cb_dir = tk.Checkbutton(window, text="DIR", variable=status_dir).place(x=400, y=90)
cb_jsp = tk.Checkbutton(window, text="JSP", variable=status_jsp).place(x=500, y=10)
cb_mdb = tk.Checkbutton(window, text="MDB", variable=status_mdb).place(x=500, y=50)
cb_php = tk.Checkbutton(window, text="PHP", variable=status_php).place(x=500, y=90)

读取字典的时候这样写:

def read_dict():''' load the dict '''combin = []global status_asp, status_aspx, status_dir, status_jsp, status_mdb, status_phpif status_asp.get():with open('ASP.txt') as f:combin.extend(f.read().split())if status_aspx.get():with open('ASPX.txt') as f:combin.extend(f.read().split())if status_dir.get():with open('DIR.txt') as f:combin.extend(f.read().split())if status_jsp.get():with open('JSP.txt') as f:combin.extend(f.read().split())if status_mdb.get():with open('MDB.txt') as f:combin.extend(f.read().split())if status_php.get():with open('PHP.txt') as f:combin.extend(f.read().split())return combin

当然了,这并不优雅。如果你是用pack来进行配置的话,修改起来可能会更加的简单,place的灵活性太差了。不过我们还是可以尝试把它写的优雅一些,如:

dicts = ["ASP", "ASPX", "DIR", "JSP", "MDB", "PHP"]
checkboxes = []
for i in range(3):checkboxes.append(tk.BooleanVar())tk.Checkbutton(window, text=dicts[i], variable=checkboxes[i]).place(x=400, y=10+40*i)
for i in range(3,6):checkboxes.append(tk.BooleanVar())tk.Checkbutton(window, text=dicts[i], variable=checkboxes[i]).place(x=500, y=10+40*(i-3))

是不是少了很多代码?看着就舒服。还是那个问题,因为place太死板了,我们这里需要两个循环,你可以尝试使用pack来配置,一个循环解决问题哈。

那读取字典的操作,也就可以简单化了:

def read_dict():''' load the dict '''global dicts, checkboxescombin = []for i in range(len(checkboxes)):if checkboxes[i].get():with open(dicts[i]+".txt", "r") as f:combin.extend(f.read().split())return combin

不多说了,优不优雅自己体会。(在命令行版中的读取字典的操作,也向这里一样相当的冗余,你尝试着将它修改的优雅简洁些吧~)

运行按钮(4)

第四部分,就一个按钮,不用想,用Button。

当点击按钮时,启动扫描器。

def run():WST = WebScannerTkl()WST.run()def scan():threading.Thread(target=run).start()button = tk.Button(window, text="Let's go", command=scan)
button.place(x=280, y=150)

这里没有过多要说的,在run函数里创建扫描器对象,并调用对象的run方法进行扫描(两个run不要搞混啊)。这个类的设计大部分功能与上篇文章里的命令行版相同,我们只需要继承过来,重写一些方法即可。(放在后面说)

那,点击按钮的时候,为什么不让它直接执行run,而是通过scan创建个线程,让线程去执行呢?

还记得第一篇文章(端口扫描器),我们最后讨论的GIL吗?窗口的显示是个不断的循环输出,如果让进程去执行函数功能,在这段执行时间段里,没人来循环界面,界面就会出现“卡死”的情况。忘记的小伙伴去翻下吧。传送门

输出框(5)

第五部分,实时输出扫描结果。它不需要什么其他的功能,用Text就好。

t = tk.Text(window, height=10)
t.place(x=10, y=220)

(再次认错,代码是很久之前写的,里面变量起的名字让人抓狂,你在编写的时候记得改正哈。)

五大部分完成了,其实还有一部分,就是在窗口的右下角有个进度标签,可以回到开头动态图片里查看。

它的设计呢,我是使用的Label标签,然后实时的修改变量的值。除了此处的标签,还有输入框前面的"HTTP URL",“线程数”,“超时”都是使用的标签。

var_progress = tk.StringVar()tk.Label(window, text='HTTP URL:').place(x=20, y=10)
tk.Label(window, text='进程数:').place(x=20, y=50)
tk.Label(window, text='请求超时:').place(x=20, y=90)
progress = tk.Label(window, textvariable=var_progress).place(x=500, y=370)

至此,可视化完成。

类的设计

我们前面说了,进行扫描的核心代码与命令行版本近乎相同,我们先把命令行版的贴出来:

class WebScanner(object):_running_time = 0_number_of_threads_completed = 0def __init__(self, host, thread_num, paths):"""initialization object"""self.host = host if host[-1] != '/' else host[:-1]self.thread_num = thread_numself.paths = pathsdef animation(self):"""opening animation"""return r'''__      __      ___.     _________
/  \    /  \ ____\_ |__  /   _____/ ____ _____    ____   ____   ___________
\   \/\/   // __ \| __ \ \_____  \_/ ___\\__  \  /    \ /    \_/ __ \_  __ \\        /\  ___/| \_\ \/        \  \___ / __ \|   |  \   |  \  ___/|  | \/\__/\  /  \___  >___  /_______  /\___  >____  /___|  /___|  /\___  >__|   \/       \/    \/        \/     \/     \/     \/     \/     \/       '''def run(self):"""start scanner"""WebScanner._running_time = time.time()for i in range(self.thread_num):threading.Thread(target=self._subthread).start()def _subthread(self):"get url from dictionary and try to connect"while self.paths:sub_url = self.paths.pop()headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/51.0.2704.63 Safari/537.36'}url = self.host + sub_urlreq = urllib.request.Request(url=url, headers=headers)try:##Discard requests longer than two secondsrequest = urllib.request.urlopen(req, timeout=1)result = request.geturl(), request.getcode(), len(request.read())print(result)except:passWebScanner._number_of_threads_completed += 1if WebScanner._number_of_threads_completed == self.thread_num:print("Cost time {} seconds.".format(time.time() - WebScanner._running_time))

试图分析,我们需要修改哪些部分。

animation我们不需要,不管他。run函数不需要动,没有问题。进程函数呢~,它就需要改变了。

在命令行版本中,对扫描结果我们直接进行print输出,而在GUI版中,我们需要输出到Text里,这是需要改变的地方。还需要做别的事吗?需要,还有个进度条呢?每次执行扫描,都要把右下角的Label内容加一,这样才是实时的情况。这里的Text和Label绑定的变量,都将其作为对象初始化的一个属性。那加上超时属性,总共三个新属性需要添加。分析完毕。

综上,只需修改_subthread和__init__函数即可:

class WebScannerTkl(WebScanner):def __init__(self, host, thread_num, paths, timeout, print_, progress):super().__init__(host, thread_num, paths)self.print = print_self.progress = progressself.timeout = timeoutdef _subthread(self):"get url from dictionary and try to connect"length = len(self.paths)progress = 0while self.paths:sub_url = self.paths.pop()headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/51.0.2704.63 Safari/537.36'}url = self.host + sub_urlreq = urllib.request.Request(url=url, headers=headers)try:##Discard requests longer than two secondsrequest = urllib.request.urlopen(req, timeout=self.timeout)result = request.geturl(), request.getcode(), len(request.read())self.print.insert("insert", str(result)+"\n")except:passfinally:progress += 1self.progress.set("进度:" + str(progress) + r'/' + str(length))WebScanner._number_of_threads_completed += 1if WebScanner._number_of_threads_completed == self.thread_num:self.print.insert("insert","Cost time {} seconds.".format(time.time() - WebScanner._running_time))

现在是不是体会到继承的强大了,少写了多少代码呀~。

现在,按钮的执行函数也就可以确认了:

def run():WST = WebScannerTkl(entry.get(), int(thread_num.get()), \read_dict(), float(timeout.get()), \t, var_progress)WST.run()

分别传入,根目录,线程数,字典列表,超时时间,输出框(Text),进度标签变量进行初始化。(还是那个问题,变量名没有起好,理解了就行哈。)

节目清单

完整代码:

import tkinter as tk
from tkinter import ttk
from web import WebScanner
import threading
import urllib.request
import timeclass WebScannerTkl(WebScanner):def __init__(self, host, thread_num, paths, timeout, print_, progress):super().__init__(host, thread_num, paths)self.print = print_self.progress = progressself.timeout = timeoutdef _subthread(self):"get url from dictionary and try to connect"length = len(self.paths)progress = 0while self.paths:sub_url = self.paths.pop()headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/51.0.2704.63 Safari/537.36'}url = self.host + sub_urlreq = urllib.request.Request(url=url, headers=headers)try:##Discard requests longer than two secondsrequest = urllib.request.urlopen(req, timeout=self.timeout)result = request.geturl(), request.getcode(), len(request.read())self.print.insert("insert", str(result)+"\n")except:passfinally:progress += 1self.progress.set("进度:" + str(progress) + r'/' + str(length))WebScanner._number_of_threads_completed += 1if WebScanner._number_of_threads_completed == self.thread_num:self.print.insert("insert","Cost time {} seconds.".format(time.time() - WebScanner._running_time))def read_dict():''' load the dict '''global dicts, checkboxescombin = []for i in range(len(checkboxes)):if checkboxes[i].get():with open(dicts[i]+".txt", "r") as f:combin.extend(f.read().split())return combindef run():WST = WebScannerTkl(entry.get(), int(thread_num.get()), \read_dict(), float(timeout.get()), \t, var_progress)WST.run()window = tk.Tk()
window.title('Web Scanner    by 刑者')
window.geometry('600x400')
window.config(background='#CCE8CF')entry = tk.Entry(window)
entry.place(x=100, y=10)thread_num = tk.StringVar()
comboxlist = ttk.Combobox(window, textvariable=thread_num)
comboxlist["values"] = ('1', '3', '5')
comboxlist.current(0)
comboxlist.place(x=100, y=50)timeout = tk.StringVar()
comboxlist1 = ttk.Combobox(window, textvariable=timeout)
comboxlist1["values"] = ('1', '0.5', '0.1')
comboxlist1.current(0)
comboxlist1.place(x=100, y=90)dicts = ["ASP", "ASPX", "DIR", "JSP", "MDB", "PHP"]
checkboxes = []
for i in range(3):checkboxes.append(tk.BooleanVar())tk.Checkbutton(window, text=dicts[i], variable=checkboxes[i]).place(x=400, y=10+40*i)
for i in range(3,6):checkboxes.append(tk.BooleanVar())tk.Checkbutton(window, text=dicts[i], variable=checkboxes[i]).place(x=500, y=10+40*(i-3))t = tk.Text(window, height=10)
t.place(x=10, y=220)def scan():threading.Thread(target=run).start()button = tk.Button(window, text="Let's go", command=scan)
button.place(x=280, y=150)var_progress = tk.StringVar()tk.Label(window, text='HTTP URL:').place(x=20, y=10)
tk.Label(window, text='进程数:').place(x=20, y=50)
tk.Label(window, text='请求超时:').place(x=20, y=90)
progress = tk.Label(window, textvariable=var_progress).place(x=500, y=370)window.mainloop()

有些地方没有写注释,不过我们都一步步的分析过,应该在理解上没有什么问题。

发现我结束的有点突兀,但确实没有什么点值得写了,很多问题我们都在前两篇文章里讨论过,无需多谈。如仍旧有疑问,我们评论里见吧。

(下一篇是,PHP一句话连接工具(GUI版),下个月见吧。)

完。

动手实现简易网站目录扫描器(桌面窗口版)——WebScannerTkl相关推荐

  1. 动手实现简易网站目录扫描器——WebScanner

    效果展示 项目目录: 引言 不知是否有小伙伴在学习Web安全相关的知识,如果有的话,那应该对XSS,SQL注入,文件上传,一句话脚本等等基本功应该是再熟悉不过了.最初学习的时候是它,实战最先测试的也是 ...

  2. 动手实现简易端口扫描器——PortScanner

    文章目录 效果展示 前言 系列介绍 举例子&打比方 何为端口 物理端口 虚拟端口 TCP&UDP 文章介绍 设计分析 设计实现 关于GIL 效果展示 本地服务器状态图: 前言 系列介绍 ...

  3. 网站目录爆破的扫描器的思路

    2019独角兽企业重金招聘Python工程师标准>>> 题目起的有点不通顺.. 网站目录 文件 爆破是攻击者的一个常见攻击手法  这个这可以达到 : 1. 通过特定名称的文件 或者 ...

  4. 简易漫画网站搭建-漫画喵Server版

    小喵的唠叨话:寒假的时候写了一个漫画爬虫,爬取了好几个漫画,不过一直没有找到合适的漫画阅读的工具.因此最近就试着自己写一个漫画的网站,放在公网上或者局域网里,这样就能随时随地用手机.Pad看漫画了. ...

  5. 局域网内简易网站的发布

    1.首先我们先做一个简易的网页 打开我们的记事本,在里面输入以下内容: <!DOCTYPE html> <html><head> <title> 简易网 ...

  6. 【OpenGL】七、桌面窗口搭建 ( 导入头文件 | 桌面程序入口函数 | 注册窗口 | 创建窗口 | 显示窗口 )

    文章目录 一.导入头文件 二.桌面程序入口函数 三.注册窗口 四.创建窗口 五.显示窗口 六.完整代码示例 七.相关资源 基于 [OpenGL]一.Visual Studio 2019 创建 Wind ...

  7. 小米范工具系列之二:小米范 web目录扫描器

    最新版本1.1,下载地址:http://pan.baidu.com/s/1c1NDSVe  文件名scandir,请使用java1.8运行 小米范web目录扫描器主要功能是探测web可能存在的目录及文 ...

  8. php 开发桌面应用,使用NW将开发的网站打包成桌面应用

    # 使用NW将我们开发的网站打包成桌面应用 >[info] NW.js 是Node.js 开发的桌面应用打包工具 > 你可以使用node语言开发桌面应用 我这里只是介绍如何将网站包一个本地 ...

  9. VC++ 利用MFC的CWindowDC类实现画线功能 在桌面窗口中画线 绘制彩色线条 CPen nPenStyle nWidth crColor

    目录 利用MFC的CWindowDC类实现画线功能 在桌面窗口中画线 绘制彩色线条 CPen nPenStyle nWidth crColor 接上:VC++ 绘制线条 OnLButtonDown函数 ...

最新文章

  1. SqlServer索引的原理与应用
  2. Objective-C中的Block
  3. P4071-[SDOI2016]排列计数【组合计数,错排】
  4. 官方 STM32F303ZE Nucleo-144开发板 点亮led
  5. Laravel测试驱动开发--功能测试 1
  6. 多少开发人员 饿了么_饿了么CPS新社交电商,2020年的创业新风口
  7. 管理新语:依照员工能力,可以分为飞天型、登山型、平路型
  8. Atitit 图像处理 灰度图片 灰度化的原理与实现
  9. 基于人体姿态识别算法的行人抬手分析
  10. 可视化建站cms_帝国CMS教程 | 01.系统运行环境及简介
  11. Java 编程练习之:101-200之间的素数
  12. 王铎《草书唐人诗九首》
  13. PSD是什么文件格式
  14. 【vue】bable的介绍以及编写vue文件
  15. 单例设计模式(饿汉式VS懒汉式)
  16. 飞腾CPU体系结构(九)
  17. HTML+PHP+MYSQL将数据库中的数据用表格显示
  18. LINUX 一键装机 PXE system-config-kickstart 资源 实现简单操作镜像装机
  19. 【数学】对向量的求导和Jacobian矩阵的几何意义与Hessian矩阵
  20. 【数据结构初阶】单链表补充内容+又双叒叕刷链表题

热门文章

  1. 如何 拍 计算机 屏幕,电脑屏幕还能这么用?拍照太方便了
  2. Python 基础练习题
  3. git--“HEAD detached from”的解决方法
  4. 打死我也不说(深度优先搜索)
  5. 张帅/斯托瑟2:0击败头号种子 晋级澳网女双四强
  6. 安卓系统刷机怎么刷机_安卓系统手机怎么刷机
  7. 多目标跟踪DeepSort
  8. 一个不错的外国Flash游戏
  9. 总裁福布斯约稿:人工智能与差异化的探讨
  10. 高职计算机公共课程改革研究,高职公共计算机课程改革探析论文