python编写工具08_用py写一个较为完整的脚本(多线程的目录扫描)

一、思路:

1、	命令行工具参数获取

2、	字典读取

3、	多线程访问

4、	状态码获得判断输出结果

二、工具初始化

2.1 定义banner函数

作用:用于介绍工具版本与名称

在这里插入图片描述

def banner():
    print("*"*51)
    print("*"*2+" "*17+"DirScan  v1.0"+" "*17+"*"*2)
    print("*"*51)
    print()
banner()

2.2 定义usage函数

作用:用于介绍使用方法(url,thread,dictionary)

在这里插入图片描述

def usage():
    print("This is the tool's usage")
    print("python DirScan.py -u url -t thread -d dictionary")
    print()
    print("*"*51 )


usage()

三、从命令行中获取参数

3.1 用到的库:

sys、getopt

3.2 用法示例:

3.2.1 打印出获取到的参数及其类型

在这里插入图片描述

import sys
import getopt

opts,args = getopt.getopt(sys.argv[1:],"u:t:d:")
print(type(opts))
print((opts))
print(type(args))
print(args)
3.2.2 将获取的数据依次输出

在这里插入图片描述

opts,args = getopt.getopt(sys.argv[1:],"u:t:d:")
#打印接收到的值
for k,v in opts:
    print(k)
    print(v)

3.2.3 将获取后的参数,赋值后输出

在这里插入图片描述

import sys
import getopt

def start():
    if len(sys.argv)  == 7:
        opts,args = getopt.getopt(sys.argv[1:],"u:t:d:")
        for k,v in opts:
            #print(k,v)
            if k == '-u':               #这个  “ - ”不要忘了
                url = v
            elif k == '-t':
                threads = v
            elif k == '-d':
                dic = v
        print("url: "+ url)
        print("threads: "+ threads)
        print("dic: "+dic)
    else:
        print("你传输的参数有误")
        sys.exit()              #结束当前程序

start()

四、字典文件的读取与分配

4.1 回顾with…as…结构

在这里插入图片描述

with open("dir.txt","r") as f:
    line_list = f.readlines()
    print(len(line_list))
    print(type(line_list))
    for line in line_list:
        print(line.strip())     #去掉换行

4.2 为多线程分配字典

思路是,一个线程读取固定数目的字典文件内容,

如5个线程,15个字典内容的话。一个线程读取3个内容。

这样将一个字典得内容分为5份就行了。



但是假如有5个线程,16个字典内容的话,改如何解决呢?

那就退而求其次,让每个线程读取4个内容,最后一个线程不用读。

这样字典也分配4份。




假如有5个线程,17个字典内容的话,改如何解决呢?

继续退而求其次,让前面四个线程读取4个内容,最后一个线程读1个内容。

这样字典继续分配为5份。

在这里插入图片描述

import math

def multi_scan(threads):
    result_list = []  # 定义一个存放最终字典的空列表

    with open("dir.txt","r") as f:
        dic_list = f.readlines()

        #确定一个线程读取几行字典内容
        thread_read_line_num = math.ceil(len(dic_list) / int(threads))        #对线程数向上取整,即16/5=3.2 --> 4

        i=0
        temp_list = []              #新建一个临时列表
        for line in dic_list:       #依次从加载的字典中取数据
            i = i + 1
            if i % thread_read_line_num == 0:           #如果够一个线程取得数量了
                temp_list.append(line.strip())
                result_list.append(temp_list)           #将当前线程创建的临时列表  存放到最终空列表中
                temp_list = []
            else:
                temp_list.append(line.strip())          #放一个数据到临时列表

    print(result_list)               #打印输出最终列表

multi_scan(5)

4.3 优化(上边的程序有一定的问题)

在这里插入图片描述

import math

def multi_scan(threads):
    result_list = []  # 定义一个存放最终字典的空列表

    with open("dir.txt","r") as f:
        dic_list = f.readlines()
        lenth = len(dic_list)

        #确定一个线程读取几行字典内容
        thread_read_line_num = math.ceil(len(dic_list) / int(threads))        #对线程数向上取整,即16/5=3.2 --> 4

        i=0
        temp_list = []              #新建一个临时列表
        for line in dic_list:       #依次从加载的字典中取数据
            i = i + 1
            if i % thread_read_line_num == 0:           #如果够一个线程取得数量了
                temp_list.append(line.strip())
                result_list.append(temp_list)           #将当前线程创建的临时列表  存放到最终空列表中
                temp_list = []
            elif i == lenth:                            #防止不够整除,少了最后一个数组。
                temp_list.append(line.strip())          #可以将这三行注释掉传入5个线程,17个数据试试就明白了。
                result_list.append(temp_list)
            else:
                temp_list.append(line.strip())          #放一个数据到临时列表

    print(result_list)               #打印输出最终列表

multi_scan(5)

五、多线程访问

5.1 使用函数

Python的多线程是一个模块“ threading ”,使用记得导入。

5.2 函数用法

threading.Thread(target=A函数,args=(k,v))

#A函数需要提前定义,

#这个元组的key与value都是A函数的参数,V可以没有。

#但是k后边一定要跟“ 逗号 ”,不跟逗号K就成了字符串,格式错误。(无V的情况下)

5.3 原理理解

从A地送100件东西到B地,且一次仅仅可以送出一个。

传统单线程就是一个快递员,送100次,效率非常低,且占用发货资源。

因为在100个货物未送完之前,发货站的人得一直等着快递员回来,然后发下一次。

这样别的物品发货也得等这100个货物送完。

多线程即,一个发货站配备N个快递员(线程),这样就可以让N个快递员同时送货。

一个发货人员同时供应多个快递员,极高得提升速度。

5.4 最终代码(重要)

在这里插入图片描述

import math
import threading
import sys
import getopt
import requests

#工具初始化之版本号与名称
def banner():
    print("*"*51)
    print("*"*2+" "*17+"DirScan  v1.0"+" "*17+"*"*2)
    print("*"*51)
    print()

#工具初始化之用法
def usage():
    print("This is the tool's usage")
    print("python DirScan.py -u url -t thread -d dictionary")
    print()
    print("*"*51 )

#定义一个多线程执行函数
def multi_scan(url,threads,dic):
    result_list = []  # 定义一个存放最终字典的空列表

    with open(dic,"r") as f:
        dic_list = f.readlines()
        lenth = len(dic_list)

        #确定一个线程读取几行字典内容
        thread_read_line_num = math.ceil(len(dic_list) / int(threads))        #对线程数向上取整,即16/5=3.2 --> 4

        i=0
        temp_list = []              #新建一个临时列表
        for line in dic_list:       #依次从加载的字典中取数据
            i = i + 1
            if i % thread_read_line_num == 0:           #如果够一个线程取得数量了
                temp_list.append(line.strip())
                result_list.append(temp_list)           #将当前线程创建的临时列表  存放到最终空列表中
                temp_list = []
            elif i == lenth:                            #防止不够整除,少了最后一个数组。
                temp_list.append(line.strip())          #可以将这三行注释掉传入5个线程,17个数据试试就明白了。
                result_list.append(temp_list)
            else:
                temp_list.append(line.strip())          #放一个数据到临时列表

    #print(result_list)               #打印输出最终列表


    threads_list = []                 #定义一个空的多线程列表
    #制作一个多线程列表
    for i in result_list:
        threads_list.append(threading.Thread(target=scan,args=(url,i)))     #url由命令行传入
    #启动多线程
    for t in threads_list:
        t.start()

#定义一个目录扫描功能的函数
def scan(url,dic):
    headers = {
    
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0"}

    for line in dic:
        r = requests.get(url+'/'+line,headers=headers)
        if r.status_code == 200:
            print(r.url+ " : "+ str(r.status_code))


#定义获取命令行参数的函数,也是程数开始的地方
def start():
    banner()
    if len(sys.argv)  == 7:
        opts,args = getopt.getopt(sys.argv[1:],"u:t:d:")        #从命令行获取参数
        for k,v in opts:
            #print(k,v)
            if k == '-u':               #这个  “ - ”不要忘了
                url = v
            elif k == '-t':
                threads = v
            elif k == '-d':
                dic = v
            else:
                print("你传输的参数有误")
                usage()
                sys.exit()  # 结束当前程序

        multi_scan(url,threads,dic)     #将获取到的参数传入多线程函数,并执行。
    else:
        print("你传输的参数有误")
        usage()
        sys.exit()              #结束当前程序

if __name__ =="__main__":
    start()

六、总结写一个工具的步骤(多线程思路)

6.1 工具的初始化

介绍工具版本、名字和使用方法

6.2 从命令行中获取到指定的参数,并使用这些参数。

6.3 字典的分配

读取字典,按照线程数(X)将字典分配为X个小列表

将X个小列表放置到一个大列表中。

6.4 多线程使用

定义一个访问的函数A,

传入字典、函数A生成一个多线程列表,

启动多线程列表。

6.5 将上述几个函数综合调用

记得优化一些细节

猜你喜欢

转载自blog.csdn.net/weixin_43970718/article/details/114902544