news 2026/7/3 8:13:55

基于Nginx日志分析构建自动化恶意采集防护体系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Nginx日志分析构建自动化恶意采集防护体系

1. 项目概述:从被动防御到主动出击

作为网站运维或后端开发者,我们每天都会和Nginx打交道。它稳定、高效,是我们线上服务的基石。但你是否遇到过这种情况:服务器监控告警CPU或带宽突然飙升,一查日志,发现某个IP在短时间内疯狂请求同一个API接口,或者像“蝗虫过境”一样爬取你网站的所有页面?这就是典型的恶意采集行为。它不像DDoS攻击那样猛烈,但像慢性病一样,持续消耗你的服务器资源,拖慢正常用户的访问速度,甚至可能导致关键数据被批量抓取。

传统的安全策略,比如配置防火墙规则,往往是对已知威胁的事后补救,或者针对大规模攻击的防御。对于这种“精准而持续”的采集行为,我们需要更精细化的手段。Nginx日志,这个我们每天生成却可能很少深入分析的宝库,恰恰是解决这个问题的关键。它忠实记录了每一个访问者的“足迹”——谁(IP地址)、什么时候(时间戳)、做了什么(请求路径)、结果如何(状态码)。通过分析这些足迹,我们就能像侦探一样,从海量正常访问中精准定位出那些行为异常的“不速之客”。

本指南的核心,就是带你完成从“日志记录者”到“安全策略制定者”的转变。我们将不依赖任何第三方商业防护产品,仅通过Shell命令、AWK、Python等开源工具,深入Nginx日志腹地,建立一套从分析、识别到自动屏蔽的完整闭环。你会发现,防护网站采集行为,并非高深莫测的安全工程,而是一系列可落地、可复现的数据处理实践。无论你是管理个人博客,还是维护企业级应用,这套方法都能让你对网站流量的掌控力提升一个维度。

2. 核心思路与方案设计:构建三层防御体系

面对恶意采集,单点防御是脆弱的。一个成熟的防护方案应该像洋葱一样,层层递进。我设计的这套体系包含三层:监控分析层、策略判定层和动态执行层。三层协同工作,形成一个能够自我学习和调整的有机整体。

2.1 监控分析层:从原始日志到结构化数据

这是所有工作的基础。Nginx的默认日志格式(combined)虽然信息全面,但只是一行行文本,不利于程序化分析。我们的首要任务是将它们转化为结构化的数据。这里有两个关键点:

第一是日志格式的标准化。我强烈建议你在Nginx配置中自定义一个更丰富的日志格式,包含对分析采集行为至关重要的字段,比如$request_time(请求处理时间)、$http_user_agent(用户代理)和$http_referer(来源页)。一个增强的日志格式定义如下:

log_format security '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$request_time" "$upstream_response_time"'; access_log /var/log/nginx/access.log security;

增加了请求时间和上游响应时间,能帮助我们判断是否是消耗资源的复杂请求。

第二是分析周期的选择。采集行为通常具有持续性,因此按小时或按天进行滚动分析是合适的。我们将使用Linux的logrotate工具或简单的crontab定时任务,将日志按日期切割(如access.log-20231015),然后对切割后的历史日志文件进行分析。这样做的好处是避免分析正在写入的当前日志文件,保证数据一致性,也减轻单次分析的数据量。

2.2 策略判定层:定义什么是“恶意”行为

并非所有高频访问都是恶意的。搜索引擎爬虫(如Googlebot、Baiduspider)频率也很高。因此,我们需要一套多维度的策略来精准画像。单一指标容易误伤,我通常采用组合策略,只有同时触发多条规则,才判定为恶意IP。

  1. 请求频率阈值:这是最直接的指标。例如,单个IP在1分钟内对同一URL路径(如/api/v1/products)请求超过120次(即每秒2次),这远超正常人类或友好爬虫的行为模式。
  2. 访问目录集中度:恶意采集往往专注于特定目录,如文章详情页(/post/*)、商品列表(/product/list*)。统计一个IP的请求中,对某个目录(或URL模式)的请求占比是否异常高(例如超过80%)。
  3. 用户代理(UA)识别与异常:检查UA是否为空、是否为常见爬虫工具库(如python-requests,curl,Go-http-client)或明显伪造的浏览器UA。可以将已知的友好爬虫UA(如各大搜索引擎)加入白名单先行过滤。
  4. 请求规律性:人工访问或正常爬虫请求间隔会有随机性,而程序化采集的请求间隔往往极其规律,比如精确每100毫秒一次。可以通过计算请求时间间隔的标准差来判断,过小的标准差是程序行为的强信号。
  5. 关键页面扫描:频繁访问登录页(/login)、注册页(/register)或管理后台路径(如/admin),即使频率不高,也需高度警惕。

实操心得:策略阈值没有绝对标准。建议你先从宽松的规则开始(例如每分钟300次),运行一段时间,观察捕获的IP列表,结合其UA和访问路径人工复核。逐步收紧阈值,形成一个适合你自身站点流量模式的策略。初期宁可漏判,避免误杀正常用户。

2.3 动态执行层:自动化屏蔽与名单管理

判定出恶意IP后,需要将其加入Nginx的拒绝名单。最直接的方式是修改Nginx配置文件,在httpserverlocation块中使用deny指令。但直接修改主配置并重载Nginx服务有一定风险,且不利于动态更新。

更优雅的方案是使用Nginx的ngx_http_geo_module模块。它允许你将IP地址列表定义在一个独立的文件中,并在Nginx配置中通过变量引用。当需要更新屏蔽名单时,只需更新这个独立文件,然后优雅地重载Nginx配置即可,无需重启服务。

具体设计是:编写一个脚本(如Python脚本),该脚本定期(如每5分钟)执行,完成“分析日志 -> 应用策略 -> 生成恶意IP列表”的工作,然后将这个列表写入一个指定的文件,如/etc/nginx/conf.d/blocked_ips.conf。这个文件内容格式如下:

geo $blocked_ip { default 0; 123.123.123.123 1; 234.234.234.0/24 1; # ... 其他恶意IP }

然后在Nginx的server配置中判断:

server { ... if ($blocked_ip) { return 403; # 或者 444 (直接关闭连接) } ... }

这种方式的性能开销极小,因为geo指令在Nginx启动时就将IP列表加载到内存中,每次请求只是进行一次快速的内存查找。

3. 日志分析实战:从命令行到脚本化

理论说完,我们进入实战环节。假设我们已有按日切割的Nginx日志文件access.log-20231015。我们将一步步从中提炼出可疑IP。

3.1 基础分析:使用AWK进行快速洞察

AWK是日志分析的瑞士军刀。首先,我们统计每个IP的请求总数,这是最基础的频次分析:

awk '{print $1}' access.log-20231015 | sort | uniq -c | sort -nr | head -20

这条命令管道做了以下事情:1)awk ‘{print $1}’提取每行日志的第一个字段(假设是$remote_addr,即IP地址)。2)sort对IP进行排序,为下一步去重准备。3)uniq -c统计每个唯一IP出现的次数。4)sort -nr按统计次数倒序排列。5)head -20显示前20个最活跃的IP。

接下来,我们结合状态码分析。例如,找出请求量巨大且404状态码比例异常的IP,这可能是扫描器在探测不存在的路径:

awk '$9 == 404 {print $1}' access.log-20231015 | sort | uniq -c | sort -nr | head -10

3.2 进阶策略:识别针对性的采集行为

基础频次分析可能会误伤CDN节点或代理池IP。我们需要更精细的策略。例如,识别在短时间内对特定API接口进行高频请求的IP。以下脚本找出在1小时窗口内,对/api/v1/article接口请求超过500次的IP:

# 使用awk结合关联数组进行时间窗口内的计数(这里简化处理,按小时切割的日志) grep '/api/v1/article' access.log-20231015 | awk -v limit=500 '{ ip = $1; count[ip]++; } END { for (ip in count) { if (count[ip] > limit) { print count[ip], ip; } } }' | sort -nr

对于更复杂的时间窗口分析(如滑动窗口),AWK会显得力不从心,这时就需要用到Python或Go这类更强大的编程语言。

3.3 脚本化实现:一个完整的Python分析示例

下面是一个Python脚本示例,它实现了组合策略:统计IP频率、检查UA、并关联特定路径。我们将分析结果输出到一个文件中,供后续屏蔽使用。

#!/usr/bin/env python3 import re from collections import defaultdict, Counter from datetime import datetime import sys # 策略阈值配置 REQUEST_LIMIT = 1000 # 单个IP总请求数上限 PATH_PATTERN = r'^/product/\d+$' # 监控的商品详情页路径模式 PATH_REQUEST_LIMIT = 200 # 对监控路径的请求上限 SUSPICIOUS_UAS = ['python-requests', 'scrapy', 'curl', 'Go-http-client'] def parse_log_line(line): """解析单行Nginx日志(combined格式)""" # 这是一个简化的解析器,实际生产环境建议使用更健壮的库或正则 pattern = r'(\d+\.\d+\.\d+\.\d+) - - \[(.*?)\] "(.*?)" (\d+) (\d+) "(.*?)" "(.*?)"' match = re.match(pattern, line) if match: ip, time_str, request, status, size, referer, ua = match.groups() return { 'ip': ip, 'time': datetime.strptime(time_str.split()[0], '%d/%b/%Y:%H:%M:%S'), 'method': request.split()[0] if request else '', 'path': request.split()[1] if len(request.split()) > 1 else '', 'status': int(status), 'ua': ua.lower() } return None def analyze_log_file(file_path): ip_total_reqs = defaultdict(int) ip_path_reqs = defaultdict(lambda: defaultdict(int)) ip_ua_list = defaultdict(set) with open(file_path, 'r') as f: for line in f: data = parse_log_line(line) if not data: continue ip = data['ip'] path = data['path'] ua = data['ua'] # 1. 统计总请求数 ip_total_reqs[ip] += 1 # 2. 统计对特定路径模式的请求数 if re.match(PATH_PATTERN, path): ip_path_reqs[ip][path] += 1 # 3. 记录该IP使用的UA ip_ua_list[ip].add(ua) # 应用策略,筛选恶意IP malicious_ips = set() for ip, total in ip_total_reqs.items(): path_count = sum(ip_path_reqs[ip].values()) uas = ip_ua_list[ip] # 策略1: 总请求数异常高 condition1 = total > REQUEST_LIMIT # 策略2: 对特定路径请求异常集中 condition2 = path_count > PATH_REQUEST_LIMIT # 策略3: UA为可疑的采集工具 condition3 = any(sus_ua in ua for ua in uas for sus_ua in SUSPICIOUS_UAS) # 满足任意两条策略,则判定为恶意IP(可根据情况调整逻辑,如 condition1 and condition2) if (condition1 and condition2) or condition3: malicious_ips.add(ip) print(f"[检测到恶意IP] IP: {ip}, 总请求: {total}, 特定路径请求: {path_count}, UA样本: {list(uas)[:2]}") return malicious_ips if __name__ == '__main__': if len(sys.argv) < 2: print("用法: python3 analyze_nginx.py <日志文件路径>") sys.exit(1) log_file = sys.argv[1] bad_ips = analyze_log_file(log_file) # 将恶意IP写入文件,格式为Nginx geo模块所需 with open('/etc/nginx/conf.d/blocked_ips.conf', 'w') as f: f.write("geo $blocked_ip {\n") f.write(" default 0;\n") for ip in bad_ips: f.write(f" {ip} 1;\n") f.write("}\n") print(f"已生成屏蔽列表,共 {len(bad_ips)} 个IP。")

这个脚本展示了从日志解析、多维度统计到策略判定的完整流程。你可以通过crontab设置定时任务,让它每天凌晨分析前一天的日志,并自动更新屏蔽列表。

4. Nginx配置与屏蔽策略优化

分析出的恶意IP,最终要通过Nginx生效。如何配置才能既高效又安全?

4.1 使用Geo模块进行高效屏蔽

如前所述,ngx_http_geo_module是首选。确保你的Nginx编译时包含了此模块(默认通常包含)。配置步骤如下:

  1. 在主配置文件nginx.confhttp块中,引入我们脚本生成的独立IP列表文件:
    http { include /etc/nginx/conf.d/blocked_ips.conf; ... }
  2. 在具体的serverlocation块中应用规则:
    server { listen 80; server_name yourdomain.com; # 在location块外判断,避免重复计算 if ($blocked_ip) { # 返回403禁止访问,并记录到日志 access_log /var/log/nginx/blocked_access.log combined; return 403; # 或者使用444,直接关闭连接,不发送任何响应头,更节省资源 # return 444; } location / { root /usr/share/nginx/html; index index.html; } }
    这里我单独为被屏蔽的访问开了一个日志blocked_access.log,方便后续审计和验证屏蔽效果。

4.2 屏蔽策略的精细化与误伤处理

直接denyreturn 403有时过于粗暴。我们可以设计更精细化的策略:

  • 速率限制(Rate Limiting):对于疑似恶意但不确定的IP,或者为了缓解而非阻断,可以使用ngx_http_limit_req_module模块进行限速。例如,将某些IP的请求速率限制在正常用户水平。
    http { limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s; ... server { location /api/ { # 对/api/路径应用限速,突发请求不超过5个 limit_req zone=perip burst=5 nodelay; proxy_pass http://backend; } } }
  • 挑战响应:对于高级爬虫,可以引入简单的JS挑战或验证码。例如,对于判定为恶意的IP,将其请求重定向到一个静态页面,该页面包含一段计算题,只有通过计算并提交正确结果的请求才被放行。这可以有效拦截无头浏览器(Headless Browser)之外的简单爬虫。
  • 白名单机制这是防止误伤的关键!务必建立并维护一个白名单文件。将你的办公室IP、公司VPN IP、重要的第三方服务IP(如支付回调、监控平台)、已知的友好爬虫IP段(如各大搜索引擎官方公布的IP段)加入其中。在geo块中,白名单IP应设置为一个特殊值(如0),并在判断逻辑中优先放行。
    geo $blocked_ip { default 0; include /etc/nginx/conf.d/whitelist.conf; # 白名单IP设为0 include /etc/nginx/conf.d/blacklist.conf; # 黑名单IP设为1 } geo $whitelist_ip { default 0; include /etc/nginx/conf.d/whitelist.conf; # 白名单IP设为1 } server { if ($whitelist_ip) { break; # 白名单直接放行,不进行后续判断 } if ($blocked_ip) { return 403; } ... }

4.3 配置生效与验证

修改配置后,使用nginx -t命令测试配置文件语法是否正确。确认无误后,执行nginx -s reload平滑重载配置。重载不会中断正在处理的连接,是线上服务推荐的配置更新方式。

验证屏蔽是否生效有多种方法:

  1. 从被屏蔽IP的机器访问:最直接,应看到403错误页面。
  2. 查看Nginx错误日志:被return 403的请求会在错误日志(error.log)中留下记录。
  3. 查看我们单独设立的屏蔽访问日志blocked_access.log):所有被拦截的请求详情都会记录在这里,便于复查。
  4. 使用curl命令模拟curl -I http://yourdomain.com从服务器本地或另一台机器测试,观察返回的HTTP状态码。

5. 高级技巧与自动化运维

将上述步骤脚本化、自动化,是提升运维效率的关键。这里分享几个进阶的实践技巧。

5.1 构建自动化防护流水线

我们可以用Shell脚本或Python脚本将整个流程串联起来,形成一个定时执行的防护流水线。以下是一个简单的Shell脚本框架:

#!/bin/bash # auto_block.sh LOG_DIR="/var/log/nginx" YESTERDAY=$(date -d "yesterday" +"%Y%m%d") ANALYSIS_SCRIPT="/opt/scripts/analyze_nginx.py" BLACKLIST_FILE="/etc/nginx/conf.d/blacklist.conf" WHITELIST_FILE="/etc/nginx/conf.d/whitelist.conf" # 步骤1: 分析昨天的日志文件 echo "开始分析日志: access.log-$YESTERDAY" python3 $ANALYSIS_SCRIPT $LOG_DIR/access.log-$YESTERDAY > /tmp/new_blacklist.txt # 步骤2: 合并新旧黑名单,并去重(避免重复添加) # 注意:这里假设分析脚本输出的是纯IP列表,每行一个 cat $BLACKLIST_FILE /tmp/new_blacklist.txt 2>/dev/null | sort | uniq > /tmp/merged_blacklist.txt # 步骤3: 生成最终的Nginx geo配置块 { echo "geo \$blocked_ip {" echo " default 0;" # 先加入白名单(设为0,确保不被屏蔽) if [ -f "$WHITELIST_FILE" ]; then awk '{print " " $1 " 0;"}' $WHITELIST_FILE fi # 再加入黑名单(设为1) awk '{print " " $1 " 1;"}' /tmp/merged_blacklist.txt echo "}" } > /etc/nginx/conf.d/blocked_ips.conf # 步骤4: 重载Nginx配置 if nginx -t; then nginx -s reload echo "Nginx配置已重载,黑名单更新完成。" # 可选:将本次新增的IP记录到另一个日志,用于后续审计 comm -13 <(sort $BLACKLIST_FILE 2>/dev/null) <(sort /tmp/new_blacklist.txt) > /var/log/nginx/blocked_new_$YESTERDAY.log # 更新黑名单文件(仅IP列表) cp /tmp/merged_blacklist.txt $BLACKLIST_FILE else echo "Nginx配置测试失败,请检查生成的blocked_ips.conf文件。" exit 1 fi

然后通过crontab -e添加定时任务,每天凌晨2点执行:

0 2 * * * /bin/bash /opt/scripts/auto_block.sh >> /var/log/nginx/block_cron.log 2>&1

5.2 处理动态IP与代理池

高级的采集者会使用代理IP池,这使得单一IP频率策略可能失效。应对方法需要升级:

  • 行为指纹识别:除了IP,可以结合其他指纹,如User-Agent的特定头部组合、TCP窗口大小、TLS指纹等。但这需要更底层的流量分析工具(如modsecurity等WAF)。
  • 集群协同防御:如果你管理多台服务器,可以共享恶意IP列表。例如,将所有服务器的屏蔽日志汇总到一个中心节点(如Redis),进行全局频率统计。一个IP在集群内任何一台机器上行为异常,都会被整个集群屏蔽。
  • 基于会话(Session)或令牌(Token)的限速:对于API接口,可以对未认证的请求实施更严格的全局速率限制,而对已登录用户则放宽。这迫使采集者必须处理登录逻辑,增加了其成本。

5.3 监控与审计

防护系统本身也需要被监控。

  • 监控屏蔽日志的增长情况:如果blocked_access.log体积在短时间内剧增,可能意味着你正在遭受大规模扫描或策略过于严格。
  • 定期审查黑名单:建议每周或每月,人工抽样检查一下被屏蔽的IP的原始访问日志,确认屏蔽是否合理。有时可能会误封一些来自公共网络(如机场、咖啡馆WiFi)的正常用户。
  • 设置告警:当单日屏蔽IP数超过历史平均值的N倍时,发送告警通知(如邮件、钉钉、Slack),提示可能存在新的攻击模式或策略需要调整。

6. 常见问题与排查实录

在实际部署和运行这套防护体系时,你肯定会遇到各种问题。下面是我踩过的一些坑和对应的解决方案。

6.1 误封了重要IP或搜索引擎

这是最令人头疼的问题。症状:某个地区用户无法访问,或者网站在搜索引擎中的收录突然下降。

排查与解决

  1. 立即检查屏蔽日志grep ‘可疑IP’ /var/log/nginx/blocked_access.log,查看该IP被屏蔽时的具体请求详情(路径、UA)。
  2. 核对白名单:第一时间将被误封的IP加入白名单文件(whitelist.conf),然后重载Nginx。
  3. 分析误封原因:查看该IP在原始访问日志中的行为。是因为请求频率触发了阈值吗?它的UA是什么?可能是一个企业出口IP,背后有大量员工同时访问,导致总请求量偏高。这时需要调整策略,例如,对于具有合法浏览器UA的IP,可以适当提高频率阈值,或者将其从基于IP的统计改为基于“IP+UA”的组合统计。
  4. 搜索引擎爬虫:务必使用搜索引擎官方提供的验证方法(如nslookup验证Googlebot的IP)来确认其真实性,并将官方IP段加入白名单。不要仅仅依靠UA字符串来判断。

6.2 Nginx配置重载失败或服务异常

症状:执行nginx -s reload后报错,或者重载后部分功能异常。

排查步骤

  1. 首要命令nginx -t。它会精确指出配置文件的哪一行有语法错误。最常见的错误是geo块中IP地址格式不对,或者缺少分号、括号。
  2. 检查生成的文件:重点检查自动化脚本生成的/etc/nginx/conf.d/blocked_ips.conf文件。确保其格式严格符合geo块语法,特别是每条规则末尾的分号。检查是否有空白行或特殊字符被意外引入。
  3. 文件权限:确保Nginx工作进程(通常是www-datanginx用户)有权限读取blocked_ips.conf文件及其所在目录。
  4. 内存考虑:如果你的黑名单IP数量极其庞大(例如数十万),geo指令可能会占用较多内存。虽然它很高效,但也需留意。可以考虑按/24/16网段进行封禁,以减少条目。

6.3 屏蔽后攻击者更换IP继续采集

症状:屏蔽了一批IP后,采集行为暂停片刻,随后又从一批新的IP开始。

应对策略

  1. 升级行为识别:这说明对方使用了IP池。此时,单纯基于IP的防御效果有限。需要将重点转向行为模式识别。例如,分析其访问路径序列是否具有规律性(如顺序爬取ID),是否忽略robots.txt,是否在非正常时段(如凌晨)保持极高频率访问。
  2. 动态挑战:对疑似IP(如来自某些数据中心ASN的IP)的访问,插入一个轻量级的JS挑战。真正的浏览器能轻松执行,而简单的脚本爬虫则会失败。
  3. 放缓屏蔽节奏:不要一检测到就立刻永久屏蔽。可以设置一个“观察期”或“惩罚等级”。例如,第一次触发规则,将其加入一个“限速列表”,限制其请求频率为正常用户的1/10。再次触发,则升级为“临时屏蔽列表”,屏蔽1小时。屡次触发,才加入“永久黑名单”。这增加了攻击者的成本,也减少了误封的影响。

6.4 日志分析脚本性能瓶颈

症状:分析单日日志文件(几个GB大小)耗时过长,超过定时任务窗口。

优化方案

  1. 使用更高效的工具:对于简单的频率统计,awksort可能比Python脚本更快。可以先用awk进行初步过滤和聚合,再将结果交给Python进行复杂策略判断。
  2. 并行处理:如果日志文件巨大,可以使用split命令将其分割成多个小文件,然后用GNU Parallel工具并行运行分析脚本,最后合并结果。
  3. 增量分析:不要每次都分析全量日志。可以记录上次分析到的日志文件行号或时间戳,下次只分析新增的部分。这需要你的日志切割和脚本设计配合。
  4. 使用专业日志处理平台:当规模进一步扩大,可以考虑引入ELK Stack(Elasticsearch, Logstash, Kibana)或Grafana Loki等日志聚合分析系统,它们提供了强大的实时查询和可视化能力,可以非常灵活地定义和检测异常行为模式。

防护是一个持续对抗的过程。没有一劳永逸的方案。这套基于Nginx日志的分析与屏蔽体系,为你提供了一个成本低廉、自主可控的起点。它让你对自己的流量有了更深的洞察,能够快速响应大多数自动化、低复杂度的采集行为。随着你对攻击模式越来越了解,你的策略也会越来越精准和有效。记住,核心在于持续观察、分析和迭代你的规则。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/3 8:03:10

暗黑破坏神2存档编辑器:零基础快速修改角色与物品的终极指南

暗黑破坏神2存档编辑器&#xff1a;零基础快速修改角色与物品的终极指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 想要轻松修改暗黑破坏神2的存档文件吗&#xff1f;d2s-editor是一款专为暗黑破坏神2玩家设计的强大存档编…

作者头像 李华
网站建设 2026/7/3 7:59:07

成年人必看!治愈一生的经典名著《小王子》

成年人必读的治愈经典&#xff0c;《小王子》从来不止是儿童童话&#xff0c;更是成年人的人生教科书。长大后才读懂&#xff0c;这本经典治愈书籍藏着我们所有的迷茫、遗憾与成长&#xff0c;也是当之无愧的人生必读名著。很多人年少读《小王子》&#xff0c;只记住了温柔的童…

作者头像 李华
网站建设 2026/7/3 7:56:35

D2DX:3大核心功能彻底解决暗黑2卡顿与画面问题的终极方案

D2DX&#xff1a;3大核心功能彻底解决暗黑2卡顿与画面问题的终极方案 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 还在为…

作者头像 李华
网站建设 2026/7/3 7:54:32

python基础08文件操作

一、文件操作核心概念先明确几个概念概念含义文件路径文件在系统中的位置&#xff0c;绝对路径&#xff0c;相对路径文件模式打开文件的方式&#xff0c;读&#xff0c;写&#xff0c;追加等文件对象打开文件后返回的对象&#xff0c;用于后续读写操作,通过open()函数获取编码格…

作者头像 李华