{"id":6405,"date":"2025-10-06T15:44:36","date_gmt":"2025-10-06T07:44:36","guid":{"rendered":"http:\/\/cnliutz.ipyingshe.net\/?p=6405"},"modified":"2025-10-06T15:44:37","modified_gmt":"2025-10-06T07:44:37","slug":"apache2%e6%97%a5%e5%bf%97%e5%88%86%e6%9e%90python%e4%bb%a3%e7%a0%81","status":"publish","type":"post","link":"http:\/\/cnliutz.wicp.vip\/?p=6405","title":{"rendered":"apache2\u65e5\u5fd7\u5206\u6790python\u4ee3\u7801"},"content":{"rendered":"\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"802\" height=\"632\" data-id=\"6406\" src=\"http:\/\/cnliutz.ipyingshe.net\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154317.jpg\" alt=\"\" class=\"wp-image-6406\" srcset=\"http:\/\/cnliutz.wicp.vip\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154317.jpg 802w, http:\/\/cnliutz.wicp.vip\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154317-300x236.jpg 300w, http:\/\/cnliutz.wicp.vip\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154317-768x605.jpg 768w\" sizes=\"auto, (max-width: 802px) 100vw, 802px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"802\" height=\"632\" data-id=\"6407\" src=\"http:\/\/cnliutz.ipyingshe.net\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154340.jpg\" alt=\"\" class=\"wp-image-6407\" srcset=\"http:\/\/cnliutz.wicp.vip\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154340.jpg 802w, http:\/\/cnliutz.wicp.vip\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154340-300x236.jpg 300w, http:\/\/cnliutz.wicp.vip\/wp-content\/uploads\/2025\/10\/\u5c4f\u5e55\u622a\u56fe-2025-10-06-154340-768x605.jpg 768w\" sizes=\"auto, (max-width: 802px) 100vw, 802px\" \/><\/figure>\n<\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>import matplotlib\nimport matplotlib.pyplot as plt\nimport re\nimport json\nimport random\nfrom collections import Counter\nfrom datetime import datetime\nimport tkinter as tk\nfrom tkinter import filedialog, messagebox, ttk\n\n# \u4f18\u5316\u5b57\u4f53\u914d\u7f6e\uff0c\u4f7f\u7528 Windows \u7cfb\u7edf\u66f4\u901a\u7528\u7684\u5b57\u4f53\nplt.rcParams&#91;\"font.family\"] = &#91;\"SimHei\", \"Microsoft YaHei\", \"SimSun\", \"Arial\"]\n# \u8bbe\u7f6e\u5b57\u4f53\u67e5\u627e\u7684\u56de\u9000\u673a\u5236\nplt.rcParams&#91;\"axes.unicode_minus\"] = False  # \u89e3\u51b3\u8d1f\u53f7\u663e\u793a\u95ee\u9898\nmatplotlib.use('Agg')  # \u4f7f\u7528\u975e\u4ea4\u4e92\u5f0f\u540e\u7aef\n\nclass ApacheLogAnalyzer:\n    def __init__(self, log_file_path=None):\n        self.log_file_path = log_file_path\n        self.logs = &#91;]\n        self.parsed_logs = &#91;]\n        self.hourly_traffic = None\n        self.ip_counts = None\n        self.status_code_counts = None\n        self.request_method_counts = None\n        self.most_requested_paths = None\n        self.analysis_report = \"\"  # \u5b58\u50a8\u6587\u5b57\u5206\u6790\u62a5\u544a\n    \n    def load_logs(self):\n        try:\n            with open(self.log_file_path, 'r', encoding='utf-8') as file:\n                self.logs = file.readlines()\n            print(f\"\u6210\u529f\u52a0\u8f7d {len(self.logs)} \u6761\u65e5\u5fd7\u8bb0\u5f55\")\n            return True\n        except Exception as e:\n            print(f\"\u52a0\u8f7d\u65e5\u5fd7\u6587\u4ef6\u5931\u8d25: {str(e)}\")\n            # \u52a0\u8f7d\u5931\u8d25\u65f6\u4f7f\u7528\u6a21\u62df\u6570\u636e\n            self._generate_sample_logs()\n            return False\n    \n    def _generate_sample_logs(self):\n        \"\"\"\u5f53\u65e0\u6cd5\u52a0\u8f7d\u5b9e\u9645\u65e5\u5fd7\u65f6\uff0c\u751f\u6210\u6a21\u62df\u65e5\u5fd7\u6570\u636e\"\"\"\n        print(\"\u6b63\u5728\u751f\u6210\u6a21\u62df\u65e5\u5fd7\u6570\u636e...\")\n        sample_logs = &#91;]\n        sample_ips = &#91;\"192.168.1.1\", \"10.0.0.1\", \"172.16.0.1\", \"192.168.0.1\", \"10.10.10.1\"]\n        sample_paths = &#91;\"\/index.html\", \"\/about.html\", \"\/contact.html\", \"\/products.html\", \"\/blog\/post1.html\"]\n        sample_methods = &#91;\"GET\", \"POST\", \"PUT\", \"DELETE\"]\n        sample_status = &#91;200, 404, 500, 301, 403]\n        \n        # \u751f\u621024\u5c0f\u65f6\u7684\u6a21\u62df\u6570\u636e\n        for hour in range(24):\n            # \u6bcf\u4e2a\u5c0f\u65f6\u751f\u6210\u968f\u673a\u6570\u91cf\u7684\u8bf7\u6c42\n            requests_count = random.randint(10, 50)\n            for _ in range(requests_count):\n                ip = random.choice(sample_ips)\n                method = random.choice(sample_methods)\n                path = random.choice(sample_paths)\n                status = random.choice(sample_status)\n                size = random.randint(100, 5000)\n                \n                # \u6784\u5efa\u6a21\u62df\u65e5\u5fd7\u884c\n                log_line = f\"{ip} - - &#91;{hour}:{random.randint(0,59)}:{random.randint(0,59)} +0000] \"\n                log_line += f'\"{method} {path} HTTP\/1.1\" {status} {size}'\n                sample_logs.append(log_line)\n        \n        self.logs = sample_logs\n        print(f\"\u751f\u6210\u4e86 {len(self.logs)} \u6761\u6a21\u62df\u65e5\u5fd7\")\n    \n    def parse_logs(self):\n        # \u4f18\u5316\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u5904\u7406\u5404\u79cd\u53ef\u80fd\u7684\u65e5\u5fd7\u683c\u5f0f\n        log_pattern = re.compile(r'(\\S+) - - \\&#91;(.*?)\\] \"(.*?)\" (\\d+) (\\S+)')\n        \n        self.parsed_logs = &#91;]\n        \n        for log in self.logs:\n            match = log_pattern.match(log)\n            if match:\n                ip, timestamp_str, request, status_code, response_size = match.groups()\n                \n                # \u89e3\u6790\u8bf7\u6c42\u65b9\u6cd5\u548c\u8def\u5f84\n                request_parts = request.split()\n                if len(request_parts) >= 2:\n                    method = request_parts&#91;0]\n                    path = request_parts&#91;1]\n                else:\n                    method = \"UNKNOWN\"\n                    path = request\n                \n                # \u89e3\u6790\u65f6\u95f4\u6233\n                try:\n                    # \u5904\u7406\u5e38\u89c1\u7684Apache\u65e5\u5fd7\u65f6\u95f4\u683c\u5f0f\n                    timestamp = datetime.strptime(timestamp_str.split()&#91;0], '%d\/%b\/%Y:%H:%M:%S')\n                    hour = f\"{timestamp.hour:02d}:00\"\n                except:\n                    hour = \"unknown\"\n                \n                # \u5904\u7406\u54cd\u5e94\u5927\u5c0f\n                try:\n                    response_size = int(response_size) if response_size != '-' else 0\n                except:\n                    response_size = 0\n                \n                self.parsed_logs.append({\n                    'ip': ip,\n                    'timestamp': timestamp_str,\n                    'hour': hour,\n                    'request': request,\n                    'method': method,\n                    'path': path,\n                    'status_code': int(status_code),\n                    'response_size': response_size\n                })\n        \n        print(f\"\u6210\u529f\u89e3\u6790 {len(self.parsed_logs)} \u6761\u65e5\u5fd7\")\n        return len(self.parsed_logs) > 0\n    \n    def analyze_traffic_by_hour(self):\n        hourly_traffic = Counter()\n        \n        # \u786e\u4fdd\u67090-23\u65f6\u7684\u6240\u6709\u6570\u636e\u70b9\uff0c\u5373\u4f7f\u6ca1\u6709\u8bbf\u95ee\n        for hour in range(24):\n            hourly_traffic&#91;f\"{hour:02d}:00\"] = 0\n        \n        for log in self.parsed_logs:\n            if log&#91;'hour'] != \"unknown\":\n                hourly_traffic&#91;log&#91;'hour']] += 1\n        \n        self.hourly_traffic = hourly_traffic\n        return hourly_traffic\n    \n    def analyze_ip_addresses(self, top_n=10):\n        ip_counter = Counter(log&#91;'ip'] for log in self.parsed_logs)\n        self.ip_counts = ip_counter.most_common(top_n)\n        return self.ip_counts\n    \n    def analyze_status_codes(self):\n        status_counter = Counter(log&#91;'status_code'] for log in self.parsed_logs)\n        self.status_code_counts = status_counter\n        return status_counter\n    \n    def analyze_request_methods(self):\n        method_counter = Counter(log&#91;'method'] for log in self.parsed_logs)\n        self.request_method_counts = method_counter\n        return method_counter\n    \n    def analyze_requested_paths(self, top_n=10):\n        path_counter = Counter(log&#91;'path'] for log in self.parsed_logs)\n        self.most_requested_paths = path_counter.most_common(top_n)\n        return self.most_requested_paths\n    \n    def generate_hourly_traffic_chart(self, hourly_traffic=None):\n        # \u5982\u679c\u6ca1\u6709\u63d0\u4f9bhourly_traffic\uff0c\u4f7f\u7528\u7c7b\u5b9e\u4f8b\u7684\u5c5e\u6027\u6216\u751f\u6210\u793a\u4f8b\u6570\u636e\n        if hourly_traffic is None:\n            if self.hourly_traffic:\n                hourly_traffic = self.hourly_traffic\n            else:\n                print(\"\u8b66\u544a: \u6ca1\u6709\u627e\u5230\u5c0f\u65f6\u6d41\u91cf\u6570\u636e\uff0c\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u751f\u6210\u56fe\u8868\")\n                # \u751f\u621024\u5c0f\u65f6\u7684\u793a\u4f8b\u6570\u636e\n                hours = &#91;f'{h:02d}:00' for h in range(24)]\n                hourly_traffic = {hour: random.randint(10, 100) for hour in hours}\n        \n        # \u786e\u4fdd\u6570\u636e\u662f\u6309\u5c0f\u65f6\u987a\u5e8f\u6392\u5e8f\u7684\n        sorted_hours = sorted(hourly_traffic.keys())\n        traffic_values = &#91;hourly_traffic&#91;hour] for hour in sorted_hours]\n        \n        plt.figure(figsize=(12, 6))\n        plt.bar(sorted_hours, traffic_values, color='skyblue')\n        plt.title('\u6bcf\u5c0f\u65f6\u8bbf\u95ee\u91cf\u8d8b\u52bf', fontsize=16)\n        plt.xlabel('\u5c0f\u65f6', fontsize=12)\n        plt.ylabel('\u8bbf\u95ee\u6b21\u6570', fontsize=12)\n        plt.xticks(rotation=45)\n        plt.grid(axis='y', linestyle='--', alpha=0.7)\n        plt.tight_layout()\n        plt.savefig('hourly_traffic.png', dpi=300, bbox_inches='tight')\n        print(\"\u5df2\u751f\u6210\u6bcf\u5c0f\u65f6\u8bbf\u95ee\u91cf\u8d8b\u52bf\u56fe: hourly_traffic.png\")\n    \n    def generate_ip_address_chart(self):\n        if not self.ip_counts:\n            print(\"\u8b66\u544a: \u6ca1\u6709IP\u5730\u5740\u5206\u6790\u6570\u636e\uff0c\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u751f\u6210\u56fe\u8868\")\n            # \u751f\u6210\u793a\u4f8bIP\u6570\u636e\n            self.ip_counts = &#91;(f\"192.168.1.{i}\", random.randint(50, 200)) for i in range(1, 11)]\n        \n        ips, counts = zip(*self.ip_counts)\n        plt.figure(figsize=(12, 6))\n        plt.barh(ips, counts, color='lightgreen')\n        plt.title('\u8bbf\u95ee\u91cf\u6700\u591a\u7684IP\u5730\u5740', fontsize=16)\n        plt.xlabel('\u8bbf\u95ee\u6b21\u6570', fontsize=12)\n        plt.ylabel('IP\u5730\u5740', fontsize=12)\n        plt.tight_layout()\n        plt.savefig('top_ip_addresses.png', dpi=300, bbox_inches='tight')\n        print(\"\u5df2\u751f\u6210IP\u5730\u5740\u5206\u5e03\u56fe: top_ip_addresses.png\")\n    \n    def generate_status_code_chart(self):\n        if not self.status_code_counts:\n            print(\"\u8b66\u544a: \u6ca1\u6709\u72b6\u6001\u7801\u5206\u6790\u6570\u636e\uff0c\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u751f\u6210\u56fe\u8868\")\n            # \u751f\u6210\u793a\u4f8b\u72b6\u6001\u7801\u6570\u636e\n            self.status_code_counts = {200: random.randint(1000, 5000),\n                                     404: random.randint(100, 500),\n                                     500: random.randint(10, 100),\n                                     301: random.randint(50, 200),\n                                     403: random.randint(20, 80)}\n        \n        status_codes = list(self.status_code_counts.keys())\n        counts = list(self.status_code_counts.values())\n        plt.figure(figsize=(10, 6))\n        plt.pie(counts, labels=status_codes, autopct='%1.1f%%', startangle=90)\n        plt.title('HTTP\u72b6\u6001\u7801\u5206\u5e03', fontsize=16)\n        plt.axis('equal')\n        plt.tight_layout()\n        plt.savefig('status_code_distribution.png', dpi=300, bbox_inches='tight')\n        print(\"\u5df2\u751f\u6210\u72b6\u6001\u7801\u5206\u5e03\u56fe: status_code_distribution.png\")\n    \n    def generate_request_method_chart(self):\n        if not self.request_method_counts:\n            print(\"\u8b66\u544a: \u6ca1\u6709\u8bf7\u6c42\u65b9\u6cd5\u5206\u6790\u6570\u636e\uff0c\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u751f\u6210\u56fe\u8868\")\n            # \u751f\u6210\u793a\u4f8b\u8bf7\u6c42\u65b9\u6cd5\u6570\u636e\n            self.request_method_counts = {\"GET\": random.randint(1000, 5000),\n                                        \"POST\": random.randint(500, 2000),\n                                        \"PUT\": random.randint(100, 500),\n                                        \"DELETE\": random.randint(50, 200)}\n        \n        methods = list(self.request_method_counts.keys())\n        counts = list(self.request_method_counts.values())\n        plt.figure(figsize=(10, 6))\n        plt.bar(methods, counts, color='lightcoral')\n        plt.title('HTTP\u8bf7\u6c42\u65b9\u6cd5\u5206\u5e03', fontsize=16)\n        plt.xlabel('\u8bf7\u6c42\u65b9\u6cd5', fontsize=12)\n        plt.ylabel('\u8bf7\u6c42\u6b21\u6570', fontsize=12)\n        plt.tight_layout()\n        plt.savefig('request_method_distribution.png', dpi=300, bbox_inches='tight')\n        print(\"\u5df2\u751f\u6210\u8bf7\u6c42\u65b9\u6cd5\u5206\u5e03\u56fe: request_method_distribution.png\")\n    \n    def generate_requested_paths_chart(self):\n        if not self.most_requested_paths:\n            print(\"\u8b66\u544a: \u6ca1\u6709\u8bf7\u6c42\u8def\u5f84\u5206\u6790\u6570\u636e\uff0c\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u751f\u6210\u56fe\u8868\")\n            # \u751f\u6210\u793a\u4f8b\u8bf7\u6c42\u8def\u5f84\u6570\u636e\n            paths = &#91;\"\/index.html\", \"\/about.html\", \"\/contact.html\", \"\/products.html\", \"\/blog\/\"]\n            self.most_requested_paths = &#91;(path, random.randint(100, 1000)) for path in paths]\n        \n        paths, counts = zip(*self.most_requested_paths)\n        # \u622a\u65ad\u8fc7\u957f\u7684\u8def\u5f84\u4ee5\u4fbf\u663e\u793a\n        truncated_paths = &#91;path&#91;:30] + '...' if len(path) > 30 else path for path in paths]\n        \n        plt.figure(figsize=(12, 6))\n        plt.barh(truncated_paths, counts, color='lightblue')\n        plt.title('\u8bbf\u95ee\u91cf\u6700\u591a\u7684\u9875\u9762\u8def\u5f84', fontsize=16)\n        plt.xlabel('\u8bbf\u95ee\u6b21\u6570', fontsize=12)\n        plt.ylabel('\u9875\u9762\u8def\u5f84', fontsize=12)\n        plt.tight_layout()\n        plt.savefig('most_requested_paths.png', dpi=300, bbox_inches='tight')\n        print(\"\u5df2\u751f\u6210\u9875\u9762\u8bbf\u95ee\u5206\u5e03\u56fe: most_requested_paths.png\")\n    \n    def save_analysis_results(self):\n        results = {\n            'total_logs': len(self.logs),\n            'parsed_logs': len(self.parsed_logs),\n            'hourly_traffic': dict(self.hourly_traffic) if self.hourly_traffic else {},\n            'top_ip_addresses': dict(self.ip_counts) if self.ip_counts else {},\n            'status_code_distribution': dict(self.status_code_counts) if self.status_code_counts else {},\n            'request_method_distribution': dict(self.request_method_counts) if self.request_method_counts else {},\n            'most_requested_paths': dict(self.most_requested_paths) if self.most_requested_paths else {}\n        }\n        \n        with open('analysis_results.json', 'w', encoding='utf-8') as file:\n            json.dump(results, file, ensure_ascii=False, indent=2)\n        \n        print(\"\u5206\u6790\u7ed3\u679c\u5df2\u4fdd\u5b58\u5230 analysis_results.json\")\n    \n    def generate_text_report(self):\n        \"\"\"\u751f\u6210\u6587\u5b57\u5f62\u5f0f\u7684\u5206\u6790\u62a5\u544a\"\"\"\n        report = &#91;\"====== Apache\u65e5\u5fd7\u5206\u6790\u62a5\u544a ======\"]\n        \n        # \u57fa\u672c\u7edf\u8ba1\n        report.append(f\"\\n1. \u57fa\u672c\u7edf\u8ba1\")\n        report.append(f\"   - \u603b\u65e5\u5fd7\u6761\u6570: {len(self.logs)}\")\n        report.append(f\"   - \u6210\u529f\u89e3\u6790\u6761\u6570: {len(self.parsed_logs)}\")\n        report.append(f\"   - \u89e3\u6790\u7387: {len(self.parsed_logs)\/len(self.logs)*100:.2f}%\" if self.logs else \"   - \u89e3\u6790\u7387: 0%\")\n        \n        # \u6d41\u91cf\u5206\u6790\n        if self.hourly_traffic:\n            total_requests = sum(self.hourly_traffic.values())\n            peak_hour = max(self.hourly_traffic.items(), key=lambda x: x&#91;1])\n            quiet_hour = min(self.hourly_traffic.items(), key=lambda x: x&#91;1])\n            \n            report.append(f\"\\n2. \u6d41\u91cf\u5206\u6790\")\n            report.append(f\"   - \u603b\u8bf7\u6c42\u6570: {total_requests}\")\n            report.append(f\"   - \u5cf0\u503c\u65f6\u6bb5: {peak_hour&#91;0]} ({peak_hour&#91;1]}\u6b21\u8bf7\u6c42)\")\n            report.append(f\"   - \u4f4e\u8c37\u65f6\u6bb5: {quiet_hour&#91;0]} ({quiet_hour&#91;1]}\u6b21\u8bf7\u6c42)\")\n            \n            # \u8ba1\u7b97\u6bcf\u5c0f\u65f6\u5e73\u5747\u8bf7\u6c42\u6570\n            avg_requests_per_hour = total_requests \/ 24 if total_requests else 0\n            report.append(f\"   - \u6bcf\u5c0f\u65f6\u5e73\u5747\u8bf7\u6c42\u6570: {avg_requests_per_hour:.2f}\")\n        \n        # IP\u5730\u5740\u5206\u6790\n        if self.ip_counts:\n            report.append(f\"\\n3. IP\u5730\u5740\u5206\u6790\")\n            report.append(f\"   - \u8bbf\u95ee\u91cf\u6700\u591a\u76845\u4e2aIP\u5730\u5740:\")\n            for ip, count in self.ip_counts&#91;:5]:\n                report.append(f\"     * {ip}: {count}\u6b21\u8bbf\u95ee\")\n            \n            # \u8ba1\u7b97IP\u591a\u6837\u6027 (\u552f\u4e00IP\u6570\u91cf)\n            unique_ips = len(set(log&#91;'ip'] for log in self.parsed_logs)) if self.parsed_logs else 0\n            report.append(f\"   - \u552f\u4e00IP\u5730\u5740\u6570\u91cf: {unique_ips}\")\n        \n        # HTTP\u72b6\u6001\u7801\u5206\u6790\n        if self.status_code_counts:\n            total_codes = sum(self.status_code_counts.values())\n            report.append(f\"\\n4. HTTP\u72b6\u6001\u7801\u5206\u6790\")\n            \n            # \u6309\u72b6\u6001\u7801\u7c7b\u522b\u5206\u7ec4\n            status_categories = {\n                '2xx\u6210\u529f': sum(count for code, count in self.status_code_counts.items() if 200 &lt;= code &lt; 300),\n                '3xx\u91cd\u5b9a\u5411': sum(count for code, count in self.status_code_counts.items() if 300 &lt;= code &lt; 400),\n                '4xx\u5ba2\u6237\u7aef\u9519\u8bef': sum(count for code, count in self.status_code_counts.items() if 400 &lt;= code &lt; 500),\n                '5xx\u670d\u52a1\u5668\u9519\u8bef': sum(count for code, count in self.status_code_counts.items() if 500 &lt;= code &lt; 600)\n            }\n            \n            for category, count in status_categories.items():\n                if count > 0:\n                    percentage = count \/ total_codes * 100\n                    report.append(f\"   - {category}: {count}\u6b21 ({percentage:.2f}%)\")\n            \n            # \u5217\u51fa\u5e38\u89c1\u72b6\u6001\u7801\n            common_codes = &#91;code for code, count in self.status_code_counts.items() if count > 0]\n            if common_codes:\n                report.append(f\"   - \u51fa\u73b0\u7684\u72b6\u6001\u7801: {', '.join(map(str, common_codes))}\")\n        \n        # \u8bf7\u6c42\u65b9\u6cd5\u5206\u6790\n        if self.request_method_counts:\n            total_methods = sum(self.request_method_counts.values())\n            report.append(f\"\\n5. HTTP\u8bf7\u6c42\u65b9\u6cd5\u5206\u6790\")\n            \n            for method, count in sorted(self.request_method_counts.items(), key=lambda x: x&#91;1], reverse=True):\n                percentage = count \/ total_methods * 100\n                report.append(f\"   - {method}: {count}\u6b21 ({percentage:.2f}%)\")\n        \n        # \u8bf7\u6c42\u8def\u5f84\u5206\u6790\n        if self.most_requested_paths:\n            report.append(f\"\\n6. \u9875\u9762\u8bbf\u95ee\u5206\u6790\")\n            report.append(f\"   - \u8bbf\u95ee\u91cf\u6700\u591a\u76845\u4e2a\u9875\u9762:\")\n            for path, count in self.most_requested_paths&#91;:5]:\n                # \u622a\u65ad\u8fc7\u957f\u7684\u8def\u5f84\n                display_path = path&#91;:50] + '...' if len(path) > 50 else path\n                report.append(f\"     * {display_path}: {count}\u6b21\u8bbf\u95ee\")\n        \n        # \u5f02\u5e38\u68c0\u6d4b\n        report.append(\"\\n7. \u5f02\u5e38\u68c0\u6d4b\")\n        \n        # \u68c0\u67e5404\u9519\u8bef\u8fc7\u591a\u7684\u60c5\u51b5\n        if self.status_code_counts and self.status_code_counts.get(404, 0) > len(self.parsed_logs) * 0.1:\n            report.append(f\"   ! \u8b66\u544a: 404\u9519\u8bef\u5360\u6bd4\u8fc7\u9ad8 ({self.status_code_counts&#91;404]\/len(self.parsed_logs)*100:.2f}%)\uff0c\u53ef\u80fd\u5b58\u5728\u5927\u91cf\u65e0\u6548\u94fe\u63a5\")\n        else:\n            report.append(f\"   - 404\u9519\u8bef\u6bd4\u4f8b\u6b63\u5e38\")\n        \n        # \u68c0\u67e55xx\u9519\u8bef\n        if self.status_code_counts:\n            server_errors = sum(count for code, count in self.status_code_counts.items() if 500 &lt;= code &lt; 600)\n            if server_errors > 0:\n                report.append(f\"   ! \u8b66\u544a: \u53d1\u73b0{server_errors}\u6b21\u670d\u52a1\u5668\u9519\u8bef(5xx)\uff0c\u9700\u8981\u68c0\u67e5\u670d\u52a1\u5668\u5065\u5eb7\u72b6\u51b5\")\n            else:\n                report.append(f\"   - \u672a\u53d1\u73b0\u670d\u52a1\u5668\u9519\u8bef(5xx)\")\n        \n        report.append(\"\\n====== \u5206\u6790\u62a5\u544a\u7ed3\u675f ======\")\n        \n        # \u4fdd\u5b58\u62a5\u544a\n        self.analysis_report = \"\\n\".join(report)\n        \n        # \u5199\u5165\u6587\u4ef6\n        with open('analysis_report.txt', 'w', encoding='utf-8') as file:\n            file.write(self.analysis_report)\n        \n        print(\"\u5206\u6790\u62a5\u544a\u5df2\u4fdd\u5b58\u5230 analysis_report.txt\")\n        return self.analysis_report\n    \n    def run_full_analysis(self):\n        print(\"\u5f00\u59cb\u65e5\u5fd7\u5206\u6790...\")\n        \n        # \u52a0\u8f7d\u65e5\u5fd7\n        if not self.load_logs():\n            print(\"\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u7ee7\u7eed\u5206\u6790\")\n        \n        # \u89e3\u6790\u65e5\u5fd7\n        if not self.parse_logs():\n            print(\"\u65e5\u5fd7\u89e3\u6790\u5931\u8d25\uff0c\u4f7f\u7528\u9884\u751f\u6210\u7684\u793a\u4f8b\u6570\u636e\")\n            # \u8bbe\u7f6e\u4e00\u4e9b\u793a\u4f8b\u6570\u636e\u4ee5\u4fbf\u751f\u6210\u56fe\u8868\n            self._setup_sample_analysis_data()\n        \n        # \u6267\u884c\u5404\u9879\u5206\u6790\n        hourly_traffic = self.analyze_traffic_by_hour()\n        self.analyze_ip_addresses()\n        self.analyze_status_codes()\n        self.analyze_request_methods()\n        self.analyze_requested_paths()\n        \n        # \u751f\u6210\u6240\u6709\u56fe\u8868\n        self.generate_hourly_traffic_chart(hourly_traffic)\n        self.generate_ip_address_chart()\n        self.generate_status_code_chart()\n        self.generate_request_method_chart()\n        self.generate_requested_paths_chart()\n        \n        # \u751f\u6210\u6587\u5b57\u5206\u6790\u62a5\u544a\n        self.generate_text_report()\n        \n        # \u4fdd\u5b58\u5206\u6790\u7ed3\u679c\n        self.save_analysis_results()\n        \n        print(\"\u65e5\u5fd7\u5206\u6790\u5b8c\u6210\uff01\")\n    \n    def _setup_sample_analysis_data(self):\n        \"\"\"\u8bbe\u7f6e\u793a\u4f8b\u5206\u6790\u6570\u636e\uff0c\u786e\u4fdd\u56fe\u8868\u80fd\u591f\u751f\u6210\"\"\"\n        # \u793a\u4f8b\u5c0f\u65f6\u6d41\u91cf\u6570\u636e\n        hours = &#91;f'{h:02d}:00' for h in range(24)]\n        self.hourly_traffic = {hour: random.randint(10, 100) for hour in hours}\n        \n        # \u793a\u4f8bIP\u6570\u636e\n        self.ip_counts = &#91;(f\"192.168.1.{i}\", random.randint(50, 200)) for i in range(1, 11)]\n        \n        # \u793a\u4f8b\u72b6\u6001\u7801\u6570\u636e\n        self.status_code_counts = {200: random.randint(1000, 5000),\n                                 404: random.randint(100, 500),\n                                 500: random.randint(10, 100),\n                                 301: random.randint(50, 200),\n                                 403: random.randint(20, 80)}\n        \n        # \u793a\u4f8b\u8bf7\u6c42\u65b9\u6cd5\u6570\u636e\n        self.request_method_counts = {\"GET\": random.randint(1000, 5000),\n                                    \"POST\": random.randint(500, 2000),\n                                    \"PUT\": random.randint(100, 500),\n                                    \"DELETE\": random.randint(50, 200)}\n        \n        # \u793a\u4f8b\u8bf7\u6c42\u8def\u5f84\u6570\u636e\n        paths = &#91;\"\/index.html\", \"\/about.html\", \"\/contact.html\", \"\/products.html\", \"\/blog\/\"]\n        self.most_requested_paths = &#91;(path, random.randint(100, 1000)) for path in paths]\n\nclass LogAnalyzerGUI:\n    def __init__(self, root):\n        self.root = root\n        self.root.title(\"Apache\u65e5\u5fd7\u5206\u6790\u5de5\u5177\")\n        self.root.geometry(\"800x600\")  # \u589e\u5927\u7a97\u53e3\u5c3a\u5bf8\u4ee5\u5bb9\u7eb3\u66f4\u591a\u5185\u5bb9\n        \n        # \u8bbe\u7f6e\u4e2d\u6587\u5b57\u4f53\n        self.style = ttk.Style()\n        self.style.configure(\"TButton\", font=('SimHei', 10))\n        self.style.configure(\"TLabel\", font=('SimHei', 10))\n        self.style.configure(\"TText\", font=('SimHei', 10))\n        \n        self.log_file_path = None\n        self.analyzer = None\n        \n        self.create_widgets()\n    \n    def create_widgets(self):\n        # \u521b\u5efa\u9876\u90e8\u6846\u67b6\u7528\u4e8e\u9009\u62e9\u6587\u4ef6\n        top_frame = ttk.Frame(self.root, padding=\"10\")\n        top_frame.pack(fill=tk.X)\n        \n        self.file_label = ttk.Label(top_frame, text=\"\u672a\u9009\u62e9\u65e5\u5fd7\u6587\u4ef6\")\n        self.file_label.pack(side=tk.LEFT, padx=(0, 10))\n        \n        select_file_btn = ttk.Button(top_frame, text=\"\u9009\u62e9\u65e5\u5fd7\u6587\u4ef6\", command=self.select_log_file)\n        select_file_btn.pack(side=tk.LEFT)\n        \n        # \u521b\u5efa\u4e2d\u95f4\u6846\u67b6\u7528\u4e8e\u5206\u6790\u6309\u94ae\n        middle_frame = ttk.Frame(self.root, padding=\"10\")\n        middle_frame.pack(fill=tk.X)\n        \n        analyze_btn = ttk.Button(middle_frame, text=\"\u5f00\u59cb\u5206\u6790\", command=self.start_analysis)\n        analyze_btn.pack(fill=tk.X)\n        \n        # \u521b\u5efa\u7ed3\u679c\u6807\u7b7e\u9875\n        self.notebook = ttk.Notebook(self.root)\n        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)\n        \n        # \u521b\u5efa\u65e5\u5fd7\u8f93\u51fa\u6807\u7b7e\u9875\n        log_frame = ttk.Frame(self.notebook)\n        self.notebook.add(log_frame, text=\"\u64cd\u4f5c\u65e5\u5fd7\")\n        \n        self.log_text = tk.Text(log_frame, wrap=tk.WORD, height=15)\n        self.log_text.pack(fill=tk.BOTH, expand=True)\n        \n        # \u6dfb\u52a0\u6eda\u52a8\u6761\u5230\u65e5\u5fd7\u6587\u672c\u6846\n        log_scrollbar = ttk.Scrollbar(self.log_text, command=self.log_text.yview)\n        log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)\n        self.log_text.config(yscrollcommand=log_scrollbar.set)\n        \n        # \u521b\u5efa\u5206\u6790\u62a5\u544a\u6807\u7b7e\u9875\n        report_frame = ttk.Frame(self.notebook)\n        self.notebook.add(report_frame, text=\"\u5206\u6790\u62a5\u544a\")\n        \n        self.report_text = tk.Text(report_frame, wrap=tk.WORD, height=15)\n        self.report_text.pack(fill=tk.BOTH, expand=True)\n        \n        # \u6dfb\u52a0\u6eda\u52a8\u6761\u5230\u62a5\u544a\u6587\u672c\u6846\n        report_scrollbar = ttk.Scrollbar(self.report_text, command=self.report_text.yview)\n        report_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)\n        self.report_text.config(yscrollcommand=report_scrollbar.set)\n        \n        # \u91cd\u5b9a\u5411stdout\u5230\u65e5\u5fd7\u6587\u672c\u6846\n        import sys\n        sys.stdout = TextRedirector(self.log_text, \"stdout\")\n    \n    def select_log_file(self):\n        file_path = filedialog.askopenfilename(\n            title=\"\u9009\u62e9Apache\u65e5\u5fd7\u6587\u4ef6\",\n            filetypes=&#91;(\"\u65e5\u5fd7\u6587\u4ef6\", \"*.log\"), (\"\u6240\u6709\u6587\u4ef6\", \"*.*\")]\n        )\n        \n        if file_path:\n            self.log_file_path = file_path\n            self.file_label.config(text=file_path)\n            messagebox.showinfo(\"\u6587\u4ef6\u9009\u62e9\", f\"\u5df2\u9009\u62e9\u6587\u4ef6: {file_path}\")\n    \n    def start_analysis(self):\n        if not self.log_file_path:\n            # \u5982\u679c\u6ca1\u6709\u9009\u62e9\u6587\u4ef6\uff0c\u8be2\u95ee\u662f\u5426\u4f7f\u7528\u793a\u4f8b\u6570\u636e\n            if messagebox.askyesno(\"\u65e0\u6587\u4ef6\u9009\u62e9\", \"\u672a\u9009\u62e9\u65e5\u5fd7\u6587\u4ef6\uff0c\u662f\u5426\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u8fdb\u884c\u5206\u6790\uff1f\"):\n                self.analyzer = ApacheLogAnalyzer()\n                self.log_text.delete(1.0, tk.END)\n                self.report_text.delete(1.0, tk.END)\n                self.analyzer.run_full_analysis()\n                # \u663e\u793a\u5206\u6790\u62a5\u544a\n                self.display_analysis_report()\n                messagebox.showinfo(\"\u5206\u6790\u5b8c\u6210\", \"\u4f7f\u7528\u793a\u4f8b\u6570\u636e\u7684\u65e5\u5fd7\u5206\u6790\u5df2\u5b8c\u6210\uff01\")\n        else:\n            try:\n                self.analyzer = ApacheLogAnalyzer(self.log_file_path)\n                self.log_text.delete(1.0, tk.END)\n                self.report_text.delete(1.0, tk.END)\n                self.analyzer.run_full_analysis()\n                # \u663e\u793a\u5206\u6790\u62a5\u544a\n                self.display_analysis_report()\n                messagebox.showinfo(\"\u5206\u6790\u5b8c\u6210\", \"\u65e5\u5fd7\u5206\u6790\u5df2\u5b8c\u6210\uff01\")\n            except Exception as e:\n                messagebox.showerror(\"\u5206\u6790\u9519\u8bef\", f\"\u5206\u6790\u8fc7\u7a0b\u4e2d\u51fa\u73b0\u9519\u8bef: {str(e)}\")\n    \n    def display_analysis_report(self):\n        \"\"\"\u5728GUI\u4e2d\u663e\u793a\u6587\u5b57\u5206\u6790\u62a5\u544a\"\"\"\n        if self.analyzer and self.analyzer.analysis_report:\n            self.report_text.configure(state=\"normal\")\n            self.report_text.delete(1.0, tk.END)\n            self.report_text.insert(tk.END, self.analyzer.analysis_report)\n            self.report_text.configure(state=\"disabled\")\n        else:\n            self.report_text.configure(state=\"normal\")\n            self.report_text.insert(tk.END, \"\u65e0\u6cd5\u663e\u793a\u5206\u6790\u62a5\u544a: \u6ca1\u6709\u627e\u5230\u62a5\u544a\u6570\u636e\u3002\")\n            self.report_text.configure(state=\"disabled\")\n\nclass TextRedirector:\n    def __init__(self, text_widget, tag=\"stdout\"):\n        self.text_widget = text_widget\n        self.tag = tag\n    \n    def write(self, string):\n        self.text_widget.configure(state=\"normal\")\n        self.text_widget.insert(tk.END, string)\n        self.text_widget.see(tk.END)\n        self.text_widget.configure(state=\"disabled\")\n    \n    def flush(self):\n        pass\n\nif __name__ == \"__main__\":\n    root = tk.Tk()\n    app = LogAnalyzerGUI(root)\n    root.mainloop()<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-6405","post","type-post","status-publish","format-standard","hentry","category-2"],"_links":{"self":[{"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=\/wp\/v2\/posts\/6405","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6405"}],"version-history":[{"count":1,"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=\/wp\/v2\/posts\/6405\/revisions"}],"predecessor-version":[{"id":6408,"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=\/wp\/v2\/posts\/6405\/revisions\/6408"}],"wp:attachment":[{"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6405"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/cnliutz.wicp.vip\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}