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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /网站资源下载/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 | -------------------------------------------------------------------------------- /站点测试/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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------