├── .idea
├── PyScript.iml
├── misc.xml
└── modules.xml
├── 111.py
├── Docker
└── docker_pull_speed.py
├── K8s监测工具
└── Get_PodStatus.py
├── Linux资源监测
└── Get_Linux_Info.py
├── README.md
├── load.py
├── wechat.py
├── 创建目录.py
├── 天气预报推送.py
├── 密码生成器-1.py
├── 文件字符串统计.py
├── 文件拷贝.py
├── 登入脚本.py
├── 站点测试
├── web_load_tester.py
└── 使用说明.md
├── 简易菜单.py
└── 网站资源下载
└── download_images.py
/.idea/PyScript.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/111.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | print("hello")
--------------------------------------------------------------------------------
/Docker/docker_pull_speed.py:
--------------------------------------------------------------------------------
1 | import docker
2 | import sys
3 | import re
4 | import time
5 | from collections import defaultdict
6 | import requests
7 | from datetime import datetime
8 | from colorama import init, Fore, Style
9 | from rich.console import Console
10 | from rich.table import Table
11 |
12 | # 需要安装的模块:pip install docker requests colorama rich
13 |
14 |
15 | # 初始化 colorama
16 | init(autoreset=True)
17 |
18 | def format_size(bytes):
19 | """
20 | 格式化字节数为可读的单位
21 | """
22 | for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
23 | if bytes < 1024:
24 | formatted = f"{bytes:.2f}{unit}"
25 | return formatted
26 | bytes /= 1024
27 | formatted = f"{bytes:.2f}PB"
28 | return formatted
29 |
30 | def parse_size(size_str):
31 | """
32 | 解析大小字符串,将其转换为字节数。
33 | 例如:'500kB' -> 500 * 1024
34 | """
35 | size_str = size_str.strip()
36 | match = re.match(r'([\d\.]+)([KMGTP]?B)', size_str, re.IGNORECASE)
37 | if not match:
38 | return 0
39 | number, unit = match.groups()
40 | number = float(number)
41 | unit_multipliers = {
42 | 'B': 1,
43 | 'KB': 1024,
44 | 'MB': 1024**2,
45 | 'GB': 1024**3,
46 | 'TB': 1024**4,
47 | 'PB': 1024**5,
48 | }
49 | return number * unit_multipliers.get(unit.upper(), 1)
50 |
51 | def get_public_ip_info():
52 | """获取本机的公网IP地址、地理区域和运营商"""
53 | try:
54 | # 获取公网IP地址
55 | ip_response = requests.get('http://members.3322.org/dyndns/getip', timeout=5)
56 | if ip_response.status_code == 200:
57 | ip = ip_response.text.strip()
58 | # 验证IP格式
59 | if re.match(r'\d+\.\d+\.\d+\.\d+', ip):
60 | # 获取地理位置信息,使用 ip-api.com
61 | geo_response = requests.get(f'http://ip-api.com/json/{ip}?lang=zh-CN', timeout=5)
62 | if geo_response.status_code == 200:
63 | geo_data = geo_response.json()
64 | if geo_data['status'] == 'success':
65 | region = f"{geo_data.get('regionName', '')} {geo_data.get('city', '')}"
66 | isp = geo_data.get('isp', '未知运营商')
67 | return ip, region.strip(), isp
68 | else:
69 | return ip, '无法获取区域信息', '无法获取运营商信息'
70 | else:
71 | return ip, '无法获取区域信息', '无法获取运营商信息'
72 | else:
73 | return '未知', '无法解析公网IP', '无法获取运营商信息'
74 | else:
75 | return '未知', '无法获取公网IP', '无法获取运营商信息'
76 | except Exception as e:
77 | return '未知', f"无法获取公网IP及区域信息: {e}", '无法获取运营商信息'
78 |
79 | def docker_pull_with_speed(image):
80 | try:
81 | client = docker.from_env()
82 | except docker.errors.DockerException as e:
83 | print(f"{Fore.RED}无法连接到Docker守护进程。请确保Docker已安装并正在运行。")
84 | sys.exit(1)
85 |
86 | # 检查镜像是否已存在
87 | try:
88 | existing_image = client.images.get(image)
89 | print(f"{Fore.GREEN}镜像 {Fore.YELLOW}{image} {Fore.GREEN}已存在,无需拉取。")
90 | return
91 | except docker.errors.ImageNotFound:
92 | pass # 镜像不存在,继续拉取
93 | except docker.errors.APIError as e:
94 | print(f"{Fore.RED}无法检查镜像是否存在:{e.explanation}")
95 | sys.exit(1)
96 |
97 | # 如果用户没有指定标签,默认使用 'latest'
98 | if ':' not in image:
99 | image += ':latest'
100 | print(f"{Fore.YELLOW}未指定标签,默认使用 'latest' 标签。")
101 |
102 | # 使用低级 API 以便获取详细的拉取信息
103 | low_level_client = docker.APIClient(base_url='unix://var/run/docker.sock')
104 |
105 | print(f"{Fore.CYAN}开始拉取镜像: {Fore.YELLOW}{image}")
106 |
107 | # 获取并显示公网IP地址、区域和运营商
108 | ip_address, region, isp = get_public_ip_info()
109 |
110 | # 使用 rich 来显示美化的表格
111 | console = Console()
112 | table = Table(show_header=True, header_style="bold cyan")
113 | table.add_column("IP地址", style="yellow", justify="center")
114 | table.add_column("IP区域", style="yellow", justify="center")
115 | table.add_column("运营商", style="yellow", justify="center")
116 |
117 | table.add_row(f"[bold yellow]{ip_address}[/]", f"[bold yellow]{region}[/]", f"[bold yellow]{isp}[/]")
118 |
119 | console.print(table)
120 |
121 | # 打印开始时间
122 | start_time = time.time()
123 | start_datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
124 | print(f"{Fore.GREEN}开始时间: {start_datetime}")
125 |
126 | # 初始化变量
127 | total_downloaded = 0
128 | layer_downloaded = defaultdict(float) # 存储每个层已下载的字节数
129 | layer_totals = defaultdict(float) # 存储每个层的总字节数
130 |
131 | try:
132 | for line in low_level_client.pull(image, stream=True, decode=True):
133 | if 'status' in line:
134 | status = line['status']
135 | id = line.get('id', '')
136 | progress_detail = line.get('progressDetail', {})
137 | current = progress_detail.get('current', 0)
138 | total = progress_detail.get('total', 0)
139 |
140 | if 'Downloading' in status or 'Extracting' in status:
141 | if id:
142 | if current > layer_downloaded[id]: # 更新递增的下载量
143 | layer_downloaded[id] = current
144 | layer_totals[id] = total
145 |
146 | # 计算总已下载字节数
147 | total_downloaded = sum(layer_downloaded.values())
148 |
149 | # 计算下载速度
150 | current_time = time.time()
151 | elapsed_time = current_time - start_time
152 | if elapsed_time > 0:
153 | speed = total_downloaded / elapsed_time
154 | else:
155 | speed = 0
156 |
157 | # 显示进度和速度
158 | total_formatted = format_size(total_downloaded)
159 | speed_formatted = format_size(speed)
160 |
161 | # 构建输出字符串,并添加 '\033[K' 清除行尾
162 | output_str = (f"\r{Fore.MAGENTA}已下载: {Fore.YELLOW}{total_formatted} | "
163 | f"{Fore.CYAN}速度: {Fore.YELLOW}{speed_formatted}/s\033[K")
164 | # 使用 sys.stdout.write 输出并刷新
165 | sys.stdout.write(output_str)
166 | sys.stdout.flush()
167 |
168 | print(f"\n{Fore.GREEN}镜像拉取完成。")
169 |
170 | # 计算并显示结束时间和总耗时
171 | end_time = time.time()
172 | end_datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
173 | total_time = end_time - start_time
174 | print(f"{Fore.GREEN}结束时间: {end_datetime}")
175 | print(f"{Fore.GREEN}总耗时: {Fore.YELLOW}{total_time:.2f} 秒")
176 |
177 | except docker.errors.APIError as e:
178 | print(f"\n{Fore.RED}发生错误: {e.explanation}")
179 | except KeyboardInterrupt:
180 | print(f"\n{Fore.RED}用户中断操作。")
181 | finally:
182 | client.close()
183 |
184 | def main():
185 | print(f"{Fore.BLUE}欢迎使用 Docker 镜像拉取速度监控脚本!")
186 | image_input = input(f"{Fore.BLUE}请输入要拉取的 Docker 镜像名称和标签(例如:ubuntu:latest):{Style.RESET_ALL}").strip()
187 | if not image_input:
188 | print(f"{Fore.RED}镜像名称不能为空。")
189 | sys.exit(1)
190 |
191 | # 如果用户没有指定标签,默认使用 'latest'
192 | if ':' not in image_input:
193 | image_input += ':latest'
194 | print(f"{Fore.YELLOW}未指定标签,默认使用 'latest' 标签。")
195 |
196 | docker_pull_with_speed(image_input)
197 |
198 | if __name__ == "__main__":
199 | main()
200 |
--------------------------------------------------------------------------------
/K8s监测工具/Get_PodStatus.py:
--------------------------------------------------------------------------------
1 | import smtplib
2 | from email.mime.text import MIMEText
3 | from kubernetes import client, config
4 | import time
5 |
6 | # 配置 K8s API 客户端
7 | config.load_kube_config()
8 | v1 = client.CoreV1Api()
9 |
10 | # 邮件通知配置
11 | smtp_server = 'smtp.example.com'
12 | smtp_port = 587
13 | smtp_user = 'user@example.com'
14 | smtp_password = 'password'
15 | mail_from = 'user@example.com'
16 | mail_to = ['user1@example.com', 'user2@example.com']
17 | mail_subject = 'K8s Pod 监控告警'
18 |
19 | # 监控循环
20 | while True:
21 | # 获取所有运行中的 Pod
22 | pods = v1.list_pod_for_all_namespaces(watch=False)
23 | # 统计运行中和失败的 Pod 数量
24 | running_pods = 0
25 | failed_pods = 0
26 | for pod in pods.items:
27 | if pod.status.phase == 'Running':
28 | running_pods += 1
29 | elif pod.status.phase == 'Failed':
30 | failed_pods += 1
31 |
32 | # 发送邮件通知
33 | if failed_pods > 0:
34 | mail_body = f"当前共有 {running_pods+failed_pods} 个 Pod,其中 {failed_pods} 个 Pod 处于失败状态。"
35 | msg = MIMEText(mail_body)
36 | msg['From'] = mail_from
37 | msg['To'] = ', '.join(mail_to)
38 | msg['Subject'] = mail_subject
39 | smtp = smtplib.SMTP(smtp_server, smtp_port)
40 | smtp.starttls()
41 | smtp.login(smtp_user, smtp_password)
42 | smtp.sendmail(mail_from, mail_to, msg.as_string())
43 | smtp.quit()
44 |
45 | # 等待 5 分钟后再次检查
46 | time.sleep(300)
47 |
--------------------------------------------------------------------------------
/Linux资源监测/Get_Linux_Info.py:
--------------------------------------------------------------------------------
1 | import psutil
2 | import smtplib
3 | from email.mime.text import MIMEText
4 | from email.header import Header
5 |
6 | # 定义邮件发送信息
7 | mail_host = 'smtp.example.com' # 发件人邮箱SMTP服务器地址
8 | mail_user = 'your_email@example.com' # 发件人邮箱账号
9 | mail_pass = 'your_password' # 发件人邮箱密码
10 | receivers = ['recipient1@example.com', 'recipient2@example.com'] # 收件人邮箱账号
11 |
12 | # 获取系统资源使用情况
13 | cpu_percent = psutil.cpu_percent(interval=1) # CPU占用率
14 | memory = psutil.virtual_memory() # 内存使用情况
15 | memory_percent = memory.percent # 内存使用率
16 | memory_used = round(memory.used / 1024 / 1024 / 1024, 2) # 内存使用量(GB)
17 | memory_total = round(memory.total / 1024 / 1024 / 1024, 2) # 内存总量(GB)
18 | disk = psutil.disk_usage('/') # 磁盘使用情况
19 | disk_percent = disk.percent # 磁盘使用率
20 | disk_used = round(disk.used / 1024 / 1024 / 1024, 2) # 磁盘使用量(GB)
21 | disk_total = round(disk.total / 1024 / 1024 / 1024, 2) # 磁盘总量(GB)
22 |
23 | # 构造邮件内容
24 | mail_content = f"""
25 |
系统资源使用情况
26 | CPU占用率:{cpu_percent}%
27 | 内存使用率:{memory_percent}%
28 | 内存使用量:{memory_used}GB
29 | 内存总量:{memory_total}GB
30 | 磁盘使用率:{disk_percent}%
31 | 磁盘使用量:{disk_used}GB
32 | 磁盘总量:{disk_total}GB
33 | """
34 |
35 | # 构造邮件
36 | message = MIMEText(mail_content, 'html', 'utf-8')
37 | message['From'] = Header(mail_user)
38 | message['To'] = Header(','.join(receivers))
39 | subject = 'Linux系统资源使用情况'
40 | message['Subject'] = Header(subject)
41 |
42 | try:
43 | # 发送邮件
44 | smtpObj = smtplib.SMTP()
45 | smtpObj.connect(mail_host, 25)
46 | smtpObj.login(mail_user, mail_pass)
47 | smtpObj.sendmail(mail_user, receivers, message.as_string())
48 | smtpObj.quit()
49 | print("邮件发送成功")
50 | except smtplib.SMTPException as e:
51 | print("邮件发送失败:", e)
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python代码
2 |
--------------------------------------------------------------------------------
/load.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding:utf-8 -*- -
3 | import os, time
4 |
5 | last_worktime=0
6 | last_idletime=0
7 |
8 | def get_cpu():
9 | global last_worktime, last_idletime
10 | f=open("/proc/stat","r")
11 | line=""
12 | while not "cpu " in line: line=f.readline()
13 | f.close()
14 | spl=line.split(" ")
15 | worktime=int(spl[2])+int(spl[3])+int(spl[4])
16 | idletime=int(spl[5])
17 | dworktime=(worktime-last_worktime)
18 | didletime=(idletime-last_idletime)
19 | rate=float(dworktime)/(didletime+dworktime)
20 | last_worktime=worktime
21 | last_idletime=idletime
22 | if(last_worktime==0): return 0
23 | return rate
24 |
25 | def get_mem_usage_percent():
26 | try:
27 | f = open('/proc/meminfo', 'r')
28 | for line in f:
29 | if line.startswith('MemTotal:'):
30 | mem_total = int(line.split()[1])
31 | elif line.startswith('MemFree:'):
32 | mem_free = int(line.split()[1])
33 | elif line.startswith('Buffers:'):
34 | mem_buffer = int(line.split()[1])
35 | elif line.startswith('Cached:'):
36 | mem_cache = int(line.split()[1])
37 | elif line.startswith('SwapTotal:'):
38 | vmem_total = int(line.split()[1])
39 | elif line.startswith('SwapFree:'):
40 | vmem_free = int(line.split()[1])
41 | else:
42 | continue
43 | f.close()
44 | except:
45 | return None
46 | physical_percent = usage_percent(mem_total - (mem_free + mem_buffer + mem_cache), mem_total)
47 | virtual_percent = 0
48 | if vmem_total > 0:
49 | virtual_percent = usage_percent((vmem_total - vmem_free), vmem_total)
50 | return physical_percent, virtual_percent
51 |
52 | def usage_percent(use, total):
53 | try:
54 | ret = (float(use) / total) * 100
55 | except ZeroDivisionError:
56 | raise Exception("ERROR - zero division error")
57 | return ret
58 |
59 | statvfs = os.statvfs('/')
60 |
61 | total_disk_space = statvfs.f_frsize * statvfs.f_blocks
62 | free_disk_space = statvfs.f_frsize * statvfs.f_bfree
63 | disk_usage = (total_disk_space - free_disk_space) * 100.0 / total_disk_space
64 | disk_usage = int(disk_usage)
65 | disk_tip = "硬盘空间使用率(最大100%):"+str(disk_usage)+"%"
66 | print(disk_tip)
67 |
68 | mem_usage = get_mem_usage_percent()
69 | mem_usage = int(mem_usage[0])
70 | mem_tip = "物理内存使用率(最大100%):"+str(mem_usage)+"%"
71 | print(mem_tip)
72 |
73 | cpu_usage = int(get_cpu()*100)
74 | cpu_tip = "CPU使用率(最大100%):"+str(cpu_usage)+"%"
75 | print(cpu_tip)
76 |
77 | load_average = os.getloadavg()
78 | load_tip = "系统负载(三个数值中有一个超过3就是高):"+str(load_average)
79 | print(load_tip)
80 |
--------------------------------------------------------------------------------
/wechat.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | import requests
4 | import json
5 | import sys
6 | import os
7 |
8 | headers = {'Content-Type': 'application/json;charset=utf-8'}
9 | api_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=c4f1290a-xxx"
10 |
11 | def msg(text):
12 | json_text= {
13 | "msgtype": "text",
14 | "text": {
15 | "content": text
16 | },
17 | }
18 | print requests.post(api_url,json.dumps(json_text),headers=headers).content
19 |
20 | if __name__ == '__main__':
21 | text = sys.argv[1]
22 | msg(text)
23 |
--------------------------------------------------------------------------------
/创建目录.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | import os
5 | aa = input("输入路径:")
6 | os.makedirs(aa)
7 |
--------------------------------------------------------------------------------
/天气预报推送.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import datetime
4 |
5 | # 获取当前日期
6 | today = datetime.date.today().strftime("%Y-%m-%d")
7 |
8 | # 输入城市名称(拼音)
9 | city = input("请输入城市名称(拼音):")
10 |
11 | # 从API获取天气信息
12 | response = requests.get(f"https://tianqiapi.com/free/day?appid=你的API密钥&appsecret=你的API密钥&city={city}&date={today}")
13 |
14 | # 转换JSON格式
15 | weather_info = json.loads(response.text)
16 |
17 | # 提取需要的信息
18 | date = weather_info["date"]
19 | week = weather_info["week"]
20 | wea = weather_info["wea"]
21 | tem = weather_info["tem"]
22 | win = weather_info["win"]
23 | air = weather_info["air"]
24 | humidity = weather_info["humidity"]
25 |
26 | # 构建消息体
27 | message = f"今天是{date} {week},{city}天气为{wea},温度为{tem}℃,风向是{win},空气质量为{air},湿度为{humidity}%。"
28 |
29 | # 发送消息到企业微信机器人
30 | webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的Webhook Key"
31 | data = {
32 | "msgtype": "text",
33 | "text": {
34 | "content": message
35 | }
36 | }
37 | response = requests.post(url=webhook_url, data=json.dumps(data))
38 | print(response.text)
39 |
--------------------------------------------------------------------------------
/密码生成器-1.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | import string
5 | import random
6 | pwd = ''
7 | all_choise = string.ascii_letters + string.digits
8 |
9 | for i in range(8):
10 | pwd += random.choice(all_choise)
11 |
12 | print(pwd)
--------------------------------------------------------------------------------
/文件字符串统计.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | file = input("请输入要统计的文件路径:")
5 | def filezs(s):
6 | chare = len(s) #统计有多少个字符
7 | words = len(s.split()) #以空格做分隔,统计单词数
8 | lines = s.count('\n') #/n表示回车,统计出多少行
9 | print(lines,words,chare)
10 | if __name__ == '__main__':
11 | s = open(file).read() #open打开文件,read读取文件
12 |
13 | filezs(s)
14 |
--------------------------------------------------------------------------------
/文件拷贝.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | #让用户输入的备份的路径和存放的路径
5 | yuan = input("请输入备份的路径:")
6 | mubiao = input("请输入目标路径:")
7 |
8 | #定义个函数
9 | def bf(x,y):
10 | s = open(yuan,'r')
11 | d = open(mubiao,'w')
12 | for i in s:
13 | d.write(i)
14 | d.flush()
15 | s.close()
16 | d.close()
17 |
18 | #调用函数
19 | bf(x=yuan,y=mubiao)
20 |
--------------------------------------------------------------------------------
/登入脚本.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | #引用函数getpass 实现密码输入的隐藏
5 | import getpass
6 | name = input("输入用户名:")
7 | password = input("输入密码:")
8 | no = 0
9 | while True:
10 | if name == 'tom' and password =='123':
11 | print("登入成功")
12 | break
13 | else:
14 | no += 1
15 | print("登入失败%s次" %no)
16 | name = input("用户输入错误,重新输入:")
17 | password = input("密码输入错误,重新输入:")
18 |
19 | if no == 2:
20 | print("登入失败")
21 | break
--------------------------------------------------------------------------------
/站点测试/web_load_tester.py:
--------------------------------------------------------------------------------
1 | """
2 | Async Web Load Tester (AWLT)
3 | ----------------------------
4 | 一个异步的网站负载测试工具,用于评估网站性能和承载能力。
5 |
6 | 特性:
7 | - 支持高并发异步请求
8 | - 详细的性能指标统计
9 | - 实时进度显示
10 | - 完整的错误追踪
11 | - 可配置的测试参数
12 |
13 | 作者: [Ding Qinzheng]
14 | 版本: 1.0.0
15 | 日期: [2024-10-30]
16 | 许可: MIT
17 | """
18 |
19 | import asyncio
20 | import aiohttp
21 | import time
22 | import argparse
23 | from datetime import datetime
24 | from collections import defaultdict
25 | import statistics
26 |
27 | class LoadTester:
28 | def __init__(self, url, total_requests, concurrent_requests, timeout=30):
29 | self.url = url
30 | self.total_requests = total_requests
31 | self.concurrent_requests = concurrent_requests
32 | self.timeout = timeout
33 | self.results = []
34 | self.errors = defaultdict(int)
35 | self.start_time = None
36 | self.end_time = None
37 |
38 | async def make_request(self, session, request_id):
39 | start_time = time.time()
40 | try:
41 | async with session.get(self.url) as response:
42 | response_time = time.time() - start_time
43 | status = response.status
44 | if status != 200:
45 | self.errors[status] += 1
46 | return {
47 | 'request_id': request_id,
48 | 'status': status,
49 | 'response_time': response_time
50 | }
51 | except Exception as e:
52 | self.errors[str(e)] += 1
53 | return {
54 | 'request_id': request_id,
55 | 'status': 'error',
56 | 'response_time': time.time() - start_time,
57 | 'error': str(e)
58 | }
59 |
60 | async def run_batch(self, start_id):
61 | connector = aiohttp.TCPConnector(limit=None, ssl=False)
62 | timeout = aiohttp.ClientTimeout(total=self.timeout)
63 | async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
64 | tasks = []
65 | for i in range(self.concurrent_requests):
66 | request_id = start_id + i
67 | if request_id < self.total_requests:
68 | tasks.append(self.make_request(session, request_id))
69 | return await asyncio.gather(*tasks)
70 |
71 | async def run_test(self):
72 | print(f"\n开始测试 URL: {self.url}")
73 | print(f"总请求数: {self.total_requests}")
74 | print(f"并发数: {self.concurrent_requests}")
75 | print("测试进行中...\n")
76 |
77 | self.start_time = datetime.now()
78 |
79 | for i in range(0, self.total_requests, self.concurrent_requests):
80 | batch_results = await self.run_batch(i)
81 | self.results.extend(batch_results)
82 |
83 | # 显示进度
84 | completed = min(i + self.concurrent_requests, self.total_requests)
85 | progress = (completed / self.total_requests) * 100
86 | print(f"\r进度: {progress:.1f}% ({completed}/{self.total_requests})", end="")
87 |
88 | self.end_time = datetime.now()
89 | print("\n\n测试完成!")
90 | self.print_results()
91 |
92 | def print_results(self):
93 | # 计算统计数据
94 | response_times = [r['response_time'] for r in self.results if r['status'] == 200]
95 | if not response_times:
96 | print("没有成功的请求!")
97 | return
98 |
99 | successful_requests = len(response_times)
100 | failed_requests = len(self.results) - successful_requests
101 | total_time = (self.end_time - self.start_time).total_seconds()
102 |
103 | print("\n=== 测试结果摘要 ===")
104 | print(f"测试持续时间: {total_time:.2f} 秒")
105 | print(f"成功请求数: {successful_requests}")
106 | print(f"失败请求数: {failed_requests}")
107 | print(f"实际RPS (Requests Per Second): {len(self.results) / total_time:.2f}")
108 |
109 | if response_times:
110 | print(f"\n响应时间统计 (秒):")
111 | print(f"最小: {min(response_times):.3f}")
112 | print(f"最大: {max(response_times):.3f}")
113 | print(f"平均: {statistics.mean(response_times):.3f}")
114 | print(f"中位数: {statistics.median(response_times):.3f}")
115 |
116 | # 计算百分位数
117 | percentiles = [50, 75, 90, 95, 99]
118 | sorted_times = sorted(response_times)
119 | for p in percentiles:
120 | index = int(len(sorted_times) * (p / 100))
121 | print(f"P{p}: {sorted_times[index]:.3f}")
122 |
123 | if self.errors:
124 | print("\n错误统计:")
125 | for error, count in self.errors.items():
126 | print(f"{error}: {count} 次")
127 |
128 | def main():
129 | parser = argparse.ArgumentParser(description='Website Load Testing Tool')
130 | parser.add_argument('url', help='要测试的网站URL')
131 | parser.add_argument('-n', '--requests', type=int, default=100, help='总请求数 (默认: 100)')
132 | parser.add_argument('-c', '--concurrent', type=int, default=10, help='并发请求数 (默认: 10)')
133 | parser.add_argument('-t', '--timeout', type=int, default=30, help='请求超时时间(秒) (默认: 30)')
134 |
135 | args = parser.parse_args()
136 |
137 | # 安全提示
138 | print("\n=== 安全提示 ===")
139 | print("1. 请确保您有权限对目标网站进行负载测试")
140 | print("2. 建议在测试环境中使用此工具")
141 | print("3. 过度的负载测试可能会影响服务器性能")
142 | print("4. 请负责任地使用此工具\n")
143 |
144 | confirm = input("您确认要继续测试吗? (yes/no): ")
145 | if confirm.lower() != 'yes':
146 | print("测试已取消")
147 | return
148 |
149 | tester = LoadTester(args.url, args.requests, args.concurrent, args.timeout)
150 | asyncio.run(tester.run_test())
151 |
152 | if __name__ == '__main__':
153 | main()
154 |
--------------------------------------------------------------------------------
/站点测试/使用说明.md:
--------------------------------------------------------------------------------
1 | ## 使用示例:
2 |
3 | ### 基本使用:
4 |
5 | ```bash
6 | python web_load_tester.py https://example.com -n 1000 -c 100
7 | ```
8 |
9 | ### 使用 POST 方法并添加自定义头部:
10 | ```bash
11 | python web_load_tester.py https://example.com/api -m POST -H "Content-Type: application/json" -H "Authorization: Bearer " -n 500 -c 50
12 | ```
13 |
14 | ### 导出结果为 CSV 文件:
15 | ```bash
16 | python web_load_tester.py https://example.com -n 1000 -c 100 -o results.csv
17 | ```
18 |
19 | ### 禁用 SSL 证书验证:
20 |
21 | ```bash
22 | python web_load_tester.py https://example.com -n 1000 -c 100 --no-ssl-verify
23 | ```
24 |
25 | ### 启用逐步增加负载:
26 | ```bash
27 | python web_load_tester.py https://example.com -n 1000 -c 100 --ramp-up 60
28 | ```
29 |
30 | ### 设置失败请求的最大重试次数:
31 | ```bash
32 | python web_load_tester.py https://example.com -n 1000 -c 100 --retries 3
33 | ```
34 |
35 | ### 使用配置文件:
36 | ```bash
37 | python web_load_tester.py --config config.yaml
38 | ```
39 |
--------------------------------------------------------------------------------
/简易菜单.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # _*_ coding:utf-8 _*_
3 | __author__ = "dqz"
4 | x = ""
5 | cd = """1、矿泉水
6 | 2、可口可乐
7 | """
8 | while not x:
9 | print("请选择以下菜单内容:")
10 | x = input(cd)
11 | if x == "1":
12 | print("矿泉水:3.5元")
13 | elif x == "2":
14 | print("可口可乐:5元")
15 |
--------------------------------------------------------------------------------
/网站资源下载/download_images.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import os
3 | import time
4 | import re
5 | from requests.adapters import HTTPAdapter
6 | from requests.packages.urllib3.util.retry import Retry
7 |
8 | def create_session():
9 | """
10 | 创建一个带有重试机制的会话
11 | """
12 | session = requests.Session()
13 |
14 | retry_strategy = Retry(
15 | total=3,
16 | backoff_factor=1,
17 | status_forcelist=[500, 502, 503, 504]
18 | )
19 |
20 | adapter = HTTPAdapter(max_retries=retry_strategy)
21 | session.mount("http://", adapter)
22 | session.mount("https://", adapter)
23 |
24 | session.headers.update({
25 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
26 | 'Accept': 'image/webp,image/apng,image/*,*/*;q=0.8',
27 | 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'
28 | })
29 |
30 | return session
31 |
32 | def extract_pattern(url):
33 | """
34 | 从示例URL中提取模式
35 | """
36 | # 查找包含数字的部分
37 | pattern = re.search(r'(_\d{3}_)', url)
38 | if not pattern:
39 | raise ValueError("无法从URL中识别出编号模式!请确保URL中包含类似'_001_'的数字编号。")
40 |
41 | # 替换数字部分为占位符
42 | pattern_str = url.replace(pattern.group(), '_{:03d}_')
43 | return pattern_str
44 |
45 | def download_image(session, url_pattern, number):
46 | """
47 | 下载指定编号的图片
48 |
49 | Args:
50 | session: 请求会话
51 | url_pattern: URL模式字符串
52 | number (int): 图片编号
53 | """
54 | # 使用提供的模式生成URL
55 | url = url_pattern.format(number)
56 |
57 | try:
58 | print(f"正在下载: {url}")
59 | response = session.get(url, timeout=15)
60 |
61 | if response.status_code == 200:
62 | if 'image' in response.headers.get('Content-Type', ''):
63 | if not os.path.exists('downloaded_images'):
64 | os.makedirs('downloaded_images')
65 |
66 | # 从URL中提取文件名
67 | filename = url.split('/')[-1]
68 | save_path = os.path.join('downloaded_images', filename)
69 |
70 | with open(save_path, 'wb') as f:
71 | f.write(response.content)
72 |
73 | print(f"✓ 成功下载图片: {filename}")
74 | return True
75 | else:
76 | print(f"✗ 错误: URL返回的不是图片内容")
77 | else:
78 | print(f"✗ 错误: 状态码 {response.status_code}")
79 |
80 | except requests.exceptions.RequestException as e:
81 | print(f"✗ 下载失败: {e}")
82 |
83 | return False
84 |
85 | def get_number_range():
86 | """
87 | 获取用户输入的数字范围
88 | """
89 | while True:
90 | try:
91 | range_input = input("请输入下载范围(格式:起始编号-结束编号,例如1-6): ")
92 | start, end = map(int, range_input.split('-'))
93 | if start > end:
94 | print("起始编号不能大于结束编号!")
95 | continue
96 | if start < 1:
97 | print("起始编号不能小于1!")
98 | continue
99 | if end > 999:
100 | print("结束编号不能大于999!")
101 | continue
102 | return start, end
103 | except ValueError:
104 | print("格式错误!请使用正确的格式,例如:1-6")
105 |
106 | def main():
107 | """
108 | 主函数:处理用户输入并下载图片
109 | """
110 | try:
111 | # 获取示例URL
112 | example_url = input("请输入示例URL(包含编号,例如: https://example.com/image_001.png): ")
113 |
114 | # 获取下载范围
115 | start_num, end_num = get_number_range()
116 |
117 | # 提取URL模式
118 | url_pattern = extract_pattern(example_url)
119 | print(f"\n识别到的URL模式: {url_pattern}")
120 | print(f"将下载范围: {start_num} 到 {end_num}\n")
121 |
122 | # 确认
123 | confirm = input("是否确认开始下载?(y/n): ")
124 | if confirm.lower() != 'y':
125 | print("已取消下载")
126 | return
127 |
128 | print("\n=== 开始下载图片 ===")
129 | session = create_session()
130 | success_count = 0
131 | total_count = end_num - start_num + 1
132 |
133 | for i in range(start_num, end_num + 1):
134 | retry_count = 3
135 | while retry_count > 0:
136 | if download_image(session, url_pattern, i):
137 | success_count += 1
138 | break
139 | retry_count -= 1
140 | if retry_count > 0:
141 | print(f"将在2秒后重试... (剩余重试次数: {retry_count})")
142 | time.sleep(2)
143 |
144 | # 每张图片下载之间暂停1秒
145 | if i < end_num:
146 | time.sleep(1)
147 |
148 | print("\n=== 下载任务完成 ===")
149 | print(f"成功下载: {success_count}/{total_count} 张图片")
150 | print(f"图片保存在 'downloaded_images' 文件夹中")
151 |
152 | except KeyboardInterrupt:
153 | print("\n\n下载已被用户中断")
154 | except Exception as e:
155 | print(f"\n发生错误: {e}")
156 |
157 | if __name__ == "__main__":
158 | main()
159 |
--------------------------------------------------------------------------------