标签: 代码

  • 淘宝天猫 PC 端 CSS 隐藏技巧:高效实现元素隐形方案

    淘宝天猫 PC 端 CSS 隐藏技巧:高效实现元素隐形方案

    核心实现思路

    元素隐藏的核心需求是让目标元素在视觉上不可见,且不影响页面其他元素的正常布局。本次方案通过定位偏移、背景设置与可见性控制的组合方式,既避免了display: none可能引发的布局塌陷问题,也解决了单纯visibility: hidden占用页面空间的弊端,适配淘宝天猫 PC 端的渲染环境。

    优化后 CSS 代码

    /* 全品类弹窗容器隐藏样式 */
    .all-cats-popup {
      position: absolute;
      top: -49999px; /* 向上偏移,脱离可视区域 */
      left: 0;
      width: 10000px;
      height: 100000px;
      display: block;
      background: #ffffff; /* 保持背景一致性,避免透明导致的异常显示 */
    }
    
    /* 弹窗内容区域定位优化 */
    .popup-content {
      position: relative;
      width: 100%;
      float: left;
      clear: both;
      left: 99999px; /* 向右偏移,进一步确保不可见 */
      top: 99490px;
      height: 100%;
      background: #ffffff;
      background-image: url(//gdp.alicdn.com/imgextra/i1/752188877/O1CN013sFHB32FRikpKiLy4_!!75218877.gif);
      background-position: top center;
      background-attachment: fixed;
      background-repeat: no-repeat;
    }
    
    /* 强制显示控制(兼容特殊场景) */
    .popup-hidden {
      visibility: visible; /* 覆盖默认隐藏状态,确保元素可正常渲染 */
    }

    代码解析与使用说明

    1. 容器隐藏逻辑

    .all-cats-popup 类通过 position: absolute 脱离文档流,再利用超大负值 top: -49999px 将元素移出页面可视区域。宽高设置为超大值(width: 10000pxheight: 100000px)是为了适配不同页面布局,避免元素部分暴露,背景色设置为白色可与页面背景融合,减少视觉冲突。

    2. 内容区域定位

    .popup-content 作为子容器,通过 float: left 和 clear: both 确保布局不错乱,left 和 top 的超大正值偏移与父容器配合,双重保障元素不可见。背景图相关属性保留了原始需求,适用于需要加载背景资源但不展示元素的场景,background-attachment: fixed 可固定背景位置,提升显示一致性。

    3. 兼容场景控制

    .popup-hidden 类使用 visibility: visible 强制元素可见,该类可根据业务需求动态添加或移除,适用于 “默认隐藏,特定条件下显示” 的交互场景,相比 display 属性切换,visibility 不会破坏元素的布局结构,适配淘宝天猫的组件渲染机制。

    注意事项

    1. 兼容性适配:该方案兼容主流浏览器及淘宝天猫 PC 端的内置渲染引擎,无需额外添加浏览器前缀。
    2. 性能优化:超大宽高设置可能影响页面渲染性能,若无需适配特殊布局,可适当减小宽高值(如 width: 100vwheight: 100vh)。
    3. 背景资源:背景图 URL 为示例地址,实际使用时需替换为自身项目的资源链接,确保资源可正常访问。
    4. 交互配合:若需通过 JS 控制元素显示 / 隐藏,可结合 classList.add()/classList.remove() 操作 .popup-hidden 类,避免直接修改样式属性。

    通过以上优化后的 CSS 代码,可高效实现淘宝天猫 PC 端元素的隐藏需求,同时兼顾布局稳定性和场景兼容性,适用于店铺装修、活动页面开发等多种场景。

  • 数字囤积症救星!LeePoet教你用AI智能整理海量图片

    数字囤积症救星!LeePoet教你用AI智能整理海量图片

    图片太多了怎么办?LeePoet一站式智能整理方案

    💡 LeePoet技术理念:复杂的科技,应该以最简单的方式服务每个普通人。

    你是否也曾在数千张照片中翻找一张重要合影?是否因为图片太多而放弃整理?本文是数字时代每个人的“图片救星”。无论你是拥有上万张照片的摄影爱好者,还是被工作图片淹没的职场人,LeePoet将用AI技术为你提供从简单到专业的全系列解决方案。

    从人物识别到内容分类,Python自动化搞定图片管理,每个人手机里几千张照片的普遍现象,手动整理的痛苦:耗时、低效、容易遗漏,LeePoet的解决方案理念:技术让生活更简单。”隐私保护+内容管理,一键分类敏感图片”,多层级风险评估。

    包含开箱即用的Python脚本、详细配置教程和常见问题解决方案。LeePoet用实际案例证明,技术不应该高高在上,而要真正服务于生活。

    UBUNTU创建虚拟环境操作

    1.创建虚拟环境
    # 进入你的项目文件夹
    cd /path/to/your/project
    
    # 创建虚拟环境(会在当前文件夹创建 venv 目录)
    python3 -m venv myenv
    
    2.激活虚拟环境
    source myenv/bin/activate
    
    3.安装依赖
    python -m pip install opencv-python
    

    如果要使用增强版本,还需要安装:

    python -m pip install torch ultralytics
    
    4.基本完成。

    初级检测:

    创建一个名为 extract_people_images.py的文件完整代码:

    import os
    import shutil
    import cv2
    from pathlib import Path
    
    def detect_people_in_image(image_path, face_cascade=None):
        """
        检测图片中是否包含人物
        """
        if face_cascade is None:
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        
        try:
            img = cv2.imread(image_path)
            if img is None:
                return False
            
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            
            faces = face_cascade.detectMultiScale(
                gray,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30)
            )
            
            return len(faces) > 0
            
        except Exception as e:
            print(f"处理图片 {image_path} 时出错: {e}")
            return False
    
    def extract_images_with_people(source_dir, target_dir):
        """
        从源文件夹提取带人物的图片到目标文件夹
        """
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 加载人脸检测器
        face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        
        print("开始扫描图片...")
        
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            
            # 检查文件格式
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                total_images += 1
                print(f"处理第 {total_images} 张图片: {filename}")
                
                # 检测是否包含人物
                if detect_people_in_image(file_path, face_cascade):
                    images_with_people += 1
                    
                    # 构建目标路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 复制文件
                    shutil.copy2(file_path, target_path)
                    print(f"✓ 检测到人物: {filename}")
                else:
                    print(f"✗ 未检测到人物: {filename}")
        
        print("\n" + "="*50)
        print("处理完成!")
        print(f"总共处理图片: {total_images}张")
        print(f"检测到包含人物的图片: {images_with_people}张")
        print(f"图片已保存到: {target_dir}")
    
    def main():
        # 设置路径
        current_dir = os.getcwd()
        target_dir = os.path.join(current_dir, "images_with_people")
        
        print(f"当前文件夹: {current_dir}")
        print(f"目标文件夹: {target_dir}")
        print("-" * 50)
        
        # 执行提取
        extract_images_with_people(current_dir, target_dir)
    
    if __name__ == "__main__":
        main()
    
    5. 运行脚本
    python extract_people_images.py
    
    6. 退出虚拟环境

    完成后,可以退出虚拟环境:

    其它说明:安装所需库(上面装完了可以不看这)
    # 升级pip(可选)
    python -m pip install --upgrade pip
    
    # 安装OpenCV(基础版本)
    python -m pip install opencv-python
    
    # 或者安装增强版本所需的库
    python -m pip install opencv-python torch ultralytics
    
    创建 requirements.txt 文件(可选)

    你可以创建一个依赖文件,方便以后重新安装:

    # 生成requirements.txt
    python -m pip freeze requirements.txt
    

    requirements.txt 内容示例:

    opencv-python==4.8.1.78
    numpy==1.24.3
    

    以后重新安装依赖:

    python -m pip install -r requirements.txt
    
    完整的项目结构建议
    your_project/
    ├── venv/                    # 虚拟环境(不要提交到版本控制)
    ├── extract_people_images.py # 主程序
    ├── requirements.txt         # 依赖列表
    └── images_with_people/      # 输出文件夹(程序自动创建)
    

    库装不上的其它操作

    python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple –verbose

    中级检测:

    正常激活虚拟环境

    cd myenv  #即虚拟环境目录
    source myenv/bin/activate   # 进入虚拟环境(如果还没激活)
    pip install opencv-python    # 确保已安装所需库
    

    安装依赖的完整步骤

    # 1. 激活虚拟环境
    source myenv/bin/activate
    
    # 2. 安装依赖(如果网络慢可以使用清华镜像)
    python -m pip install torch torchvision ultralytics opencv-python
    
    # 或者使用国内镜像加速安装
    python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python
    
    # 直接使用python命令运行,不需要执行权限
    python extract_people_images.py
    
    # 给脚本执行权限:
    chmod +x extract_people_images.py
    

    ##

    一、增强检测人物图片:

    使用YOLOv8模型进行更准确的人物检测,增强版人物图片检测

    模型说明

    • yolov8n.pt:最小最快,适合快速检测
    • yolov8s.pt:平衡速度和精度
    • yolov8m.pt:中等精度
    • yolov8l.pt:高精度
    • yolov8x.pt:最高精度,最慢

    特性

    1. 更准确的人物检测:YOLO可以检测各种姿势、大小的人物
    2. 可调置信度:根据需求调整检测敏感度
    3. 检测预览:可选保存带检测框的图片
    4. 详细统计:显示检测数量、置信度、处理时间等
    5. 错误处理:完善的异常处理,不会因为单张图片失败而停止
    6. 进度显示:实时显示处理进度

    这个增强版本比基础版本准确得多,特别是对于侧面、远处、遮挡的人物检测效果更好!

    完整的Python代码

    #!/usr/bin/env python3
    """
    增强版人物图片检测程序
    使用YOLOv8模型进行更准确的人物检测
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            print("\n如果安装缓慢,可以使用清华镜像:")
            print("pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python")
            return None, None
    
    def extract_images_with_people_enhanced(source_dir, target_dir, confidence_threshold=0.3, 
                                          model_size='yolov8n.pt', device='cpu', 
                                          save_detection_preview=False):
        """
        使用YOLO模型检测并提取包含人物的图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值(0.0-1.0),值越小检测越敏感
        model_size: 模型大小 ('yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt')
        device: 运行设备 ('cpu' 或 'cuda')
        save_detection_preview: 是否保存带检测框的预览图
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.JPG', '.JPEG', '.PNG']
        
        print("=" * 60)
        print("增强版人物图片检测程序")
        print("=" * 60)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print(f"设备: {device}")
        print(f"保存检测预览: {save_detection_preview}")
        print("-" * 60)
        
        try:
            # 加载YOLO模型(会自动下载如果不存在)
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            print("请检查网络连接或手动下载模型")
            return
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 处理: {filename}")
            total_images += 1
            
            try:
                # 记录开始时间
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检查是否检测到人物(YOLO中person类的ID是0)
                has_people = False
                people_count = 0
                max_confidence = 0.0
                
                for result in results:
                    if result.boxes is not None and len(result.boxes) > 0:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            confidence = float(box.conf)
                            
                            # class_id 0 对应 'person'
                            if class_id == 0:
                                has_people = True
                                people_count += 1
                                max_confidence = max(max_confidence, confidence)
                
                if has_people:
                    images_with_people += 1
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    base_target_path = target_path
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 复制原图到目标文件夹
                    shutil.copy2(file_path, target_path)
                    
                    # 如果启用预览,保存带检测框的图片
                    if save_detection_preview and has_people:
                        try:
                            # 绘制检测结果
                            plotted_image = results[0].plot()
                            preview_filename = f"preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    print(f"  ✓ 检测到 {people_count} 个人物 (最高置信度: {max_confidence:.3f})")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已复制到: {os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'people_count': people_count,
                        'max_confidence': max_confidence,
                        'detection_time': detection_time
                    })
                    
                else:
                    print(f"  ✗ 未检测到人物 (检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 60)
        print("处理完成!")
        print("=" * 60)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到包含人物的图片: {images_with_people}张")
            print(f"检测率: {(images_with_people/total_images*100):.1f}%")
            
            if detection_times:
                avg_detection_time = sum(detection_times) / len(detection_times)
                print(f"平均检测时间: {avg_detection_time:.2f}秒/张")
                print(f"总检测时间: {sum(detection_times):.2f}秒")
            
            if images_with_people > 0:
                print(f"\n包含人物的图片已保存到: {target_dir}")
                if save_detection_preview:
                    print(f"检测预览图已保存到: {preview_dir}")
                
                # 显示检测到最多人物的前几张图片
                if processed_files:
                    processed_files.sort(key=lambda x: x['people_count'], reverse=True)
                    print(f"\n检测结果最好的图片:")
                    for i, file_info in enumerate(processed_files[:3]):
                        print(f"  {i+1}. {file_info['filename']} - {file_info['people_count']}人 "
                              f"(置信度: {file_info['max_confidence']:.3f})")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='增强版人物图片检测程序')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='images_with_people',
                           help='目标文件夹路径 (默认: images_with_people)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        
        args = parser.parse_args()
        
        # 检查源文件夹是否存在
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        # 运行检测程序
        extract_images_with_people_enhanced(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview
        )
    
    # 简化版本函数(不需要命令行参数)
    def simple_extract():
        """简化版本,使用默认参数"""
        source_dir = os.getcwd()  # 当前文件夹
        target_dir = os.path.join(source_dir, "images_with_people")
        
        print("使用简化模式运行...")
        extract_images_with_people_enhanced(source_dir, target_dir)
    
    if __name__ == "__main__":
        # 如果没有命令行参数,使用简化版本
        import sys
        if len(sys.argv) == 1:
            simple_extract()
        else:
            main()
    

    步骤1:保存文件

    在nano编辑器中:

    • Ctrl+X退出
    • Y确认保存
    • Enter确认文件名

    步骤2:运行程序

    python extract_people_images_enhanced_copy.py
    

    方法2:使用命令行参数

    # 基本使用
    python extract_people_images_enhanced_copy.py --source /path/to/images --target ./output
    
    # 调整检测敏感度(值越小越敏感)
    python extract_people_images_enhanced_copy.py --confidence 0.2
    
    # 使用更大的模型(更准确但更慢)
    python extract_people_images_enhanced_copy.py --model yolov8s.pt
    
    # 保存检测预览图
    python extract_people_images_enhanced_copy.py --preview
    
    # 使用GPU加速(如果有NVIDIA显卡)
    python extract_people_images_enhanced_copy.py --device cuda
    
    # 查看所有选项
    python extract_people_images_enhanced_copy.py --help
    

    如果还是有问题,使用这个简单版本:

    # 先删除所有有问题的文件
    rm -f *.py
    
    # 创建简单版本
    cat > simple_detection.py << 'EOF'
    import os
    import shutil
    import cv2
    from pathlib import Path
    
    def detect_people():
        print("开始检测人物图片...")
        
        # 检查OpenCV
        try:
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        except:
            print("请先安装OpenCV: pip install opencv-python")
            return
        
        # 创建目标文件夹
        target_dir = "images_with_people"
        Path(target_dir).mkdir(exist_ok=True)
        
        # 支持的图片格式
        formats = ['.jpg', '.jpeg', '.png']
        count = 0
        
        for filename in os.listdir('.'):
            if any(filename.lower().endswith(fmt) for fmt in formats):
                print(f"处理: {filename}")
                img = cv2.imread(filename)
                if img is not None:
                    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    faces = face_cascade.detectMultiScale(gray, 1.1, 5)
                    if len(faces) > 0:
                        shutil.copy2(filename, os.path.join(target_dir, filename))
                        print(f"✓ 检测到人物")
                        count += 1
                    else:
                        print(f"✗ 未检测到人物")
        
        print(f"\n完成! 找到 {count} 张包含人物的图片")
    
    if __name__ == "__main__":
        detect_people()
    EOF
    
    # 运行简单版本
    python simple_detection.py
    

    请按照步骤1-4操作,应该能解决问题!

    二、增强检测人物图片(自定义文件夹):

    这个版本实现了把检测到的图片直接移动到新的文件夹而不是复制,也可以通过后面的加参数定义移动或者复制。

    主要修改 shutil.copy2()shutil.move()

    #!/usr/bin/env python3
    """
    增强版人物图片检测程序(移动版本)
    使用YOLOv8模型进行更准确的人物检测,并将图片移动到新文件夹
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            print("\n如果安装缓慢,可以使用清华镜像:")
            print("pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python")
            return None, None
    
    def extract_images_with_people_enhanced(source_dir, target_dir, confidence_threshold=0.3, 
                                          model_size='yolov8n.pt', device='cpu', 
                                          save_detection_preview=False, move_instead_of_copy=True):
        """
        使用YOLO模型检测并移动包含人物的图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值(0.0-1.0),值越小检测越敏感
        model_size: 模型大小 ('yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt')
        device: 运行设备 ('cpu' 或 'cuda')
        save_detection_preview: 是否保存带检测框的预览图
        move_instead_of_copy: 是否移动而不是复制图片
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.JPG', '.JPEG', '.PNG']
        
        print("=" * 60)
        print("增强版人物图片检测程序(移动版本)")
        print("=" * 60)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"操作模式: {'移动' if move_instead_of_copy else '复制'}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print(f"设备: {device}")
        print(f"保存检测预览: {save_detection_preview}")
        print("-" * 60)
        
        # 警告信息
        if move_instead_of_copy:
            print("⚠️  警告: 此操作将移动图片文件,原文件夹中的图片将被删除!")
            response = input("是否继续?(y/N): ")
            if response.lower() != 'y':
                print("操作已取消")
                return
        
        try:
            # 加载YOLO模型(会自动下载如果不存在)
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            print("请检查网络连接或手动下载模型")
            return
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 处理: {filename}")
            total_images += 1
            
            try:
                # 记录开始时间
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检查是否检测到人物(YOLO中person类的ID是0)
                has_people = False
                people_count = 0
                max_confidence = 0.0
                
                for result in results:
                    if result.boxes is not None and len(result.boxes) > 0:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            confidence = float(box.conf)
                            
                            # class_id 0 对应 'person'
                            if class_id == 0:
                                has_people = True
                                people_count += 1
                                max_confidence = max(max_confidence, confidence)
                
                if has_people:
                    images_with_people += 1
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    base_target_path = target_path
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 移动或复制文件到目标文件夹
                    if move_instead_of_copy:
                        shutil.move(file_path, target_path)
                        operation_text = "移动"
                    else:
                        shutil.copy2(file_path, target_path)
                        operation_text = "复制"
                    
                    # 如果启用预览,保存带检测框的图片
                    if save_detection_preview and has_people:
                        try:
                            # 重新读取图片用于预览(如果是移动操作,需要重新加载)
                            if move_instead_of_copy:
                                preview_source_path = target_path
                            else:
                                preview_source_path = file_path
                                
                            preview_results = model(preview_source_path, conf=confidence_threshold, device=device, verbose=False)
                            plotted_image = preview_results[0].plot()
                            preview_filename = f"preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    print(f"  ✓ 检测到 {people_count} 个人物 (最高置信度: {max_confidence:.3f})")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已{operation_text}到: {os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'people_count': people_count,
                        'max_confidence': max_confidence,
                        'detection_time': detection_time,
                        'operation': operation_text
                    })
                    
                else:
                    print(f"  ✗ 未检测到人物 (检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 60)
        print("处理完成!")
        print("=" * 60)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到包含人物的图片: {images_with_people}张")
            print(f"检测率: {(images_with_people/total_images*100):.1f}%")
            
            if detection_times:
                avg_detection_time = sum(detection_times) / len(detection_times)
                print(f"平均检测时间: {avg_detection_time:.2f}秒/张")
                print(f"总检测时间: {sum(detection_times):.2f}秒")
            
            if images_with_people > 0:
                operation_mode = "移动" if move_instead_of_copy else "复制"
                print(f"\n包含人物的图片已{operation_mode}到: {target_dir}")
                if save_detection_preview:
                    print(f"检测预览图已保存到: {preview_dir}")
                
                # 显示检测到最多人物的前几张图片
                if processed_files:
                    processed_files.sort(key=lambda x: x['people_count'], reverse=True)
                    print(f"\n检测结果最好的图片:")
                    for i, file_info in enumerate(processed_files[:3]):
                        print(f"  {i+1}. {file_info['filename']} - {file_info['people_count']}人 "
                              f"(置信度: {file_info['max_confidence']:.3f})")
                    
                # 安全提示
                if move_instead_of_copy:
                    remaining_files = len([f for f in os.listdir(source_dir) 
                                         if any(f.lower().endswith(fmt) for fmt in supported_formats)])
                    print(f"\n⚠️  原文件夹剩余图片: {remaining_files}张")
                    print("⚠️  检测到的图片已被移动到目标文件夹,原文件已删除")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='增强版人物图片检测程序(移动版本)')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='images_with_people',
                           help='目标文件夹路径 (默认: images_with_people)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        parser.add_argument('--copy', action='store_true',
                           help='使用复制模式而不是移动模式')
        
        args = parser.parse_args()
        
        # 检查源文件夹是否存在
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        # 运行检测程序
        extract_images_with_people_enhanced(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview,
            move_instead_of_copy=not args.copy  # 如果指定--copy则使用复制模式
        )
    
    # 简化版本函数(不需要命令行参数)
    def simple_extract():
        """简化版本,使用默认参数(移动模式)"""
        source_dir = os.getcwd()  # 当前文件夹
        target_dir = os.path.join(source_dir, "images_with_people")
        
        print("使用简化模式运行(移动模式)...")
        print("此操作将把检测到人物的图片移动到新文件夹!")
        
        response = input("是否继续?(y/N): ")
        if response.lower() != 'y':
            print("操作已取消")
            return
        
        extract_images_with_people_enhanced(source_dir, target_dir, move_instead_of_copy=True)
    
    if __name__ == "__main__":
        # 如果没有命令行参数,使用简化版本
        import sys
        if len(sys.argv) == 1:
            simple_extract()
        else:
            main()
    

    主要修改内容:

    1. shutil.copy2()改为 shutil.move()
    2. 添加了移动模式的安全确认,避免误操作
    3. 增加了 move_instead_of_copy参数,可以控制是移动还是复制
    4. 添加了 --copy命令行参数,如果需要复制模式可以加上这个参数
    5. 改进了预览图生成逻辑,适应移动操作
    6. 增加了操作完成后的统计信息,显示剩余文件数量

    使用方法:

    移动模式(默认):

    # 简单使用(移动图片)
    python extract_people_images_enhanced_move.py
    
    # 带参数使用
    python extract_people_images_enhanced_move.py --source ./图片文件夹 --target ./人物图片
    

    复制模式(如果需要保留原文件):

    # 使用复制模式
    python extract_people_images_enhanced_move.py --copy
    
    # 带预览的复制模式
    python extract_people_images_enhanced_move.py --copy --preview
    

    其他参数:

    # 调整检测敏感度
    python extract_people_images_enhanced_move.py --confidence 0.2
    
    # 使用更大的模型
    python extract_people_images_enhanced_move.py --model yolov8s.pt
    
    # 保存检测预览图
    python extract_people_images_enhanced_move.py --preview
    

    安全特性:

    1. 运行前确认:移动模式会要求用户确认
    2. 进度显示:实时显示处理进度
    3. 结果统计:完成后显示移动/复制的文件数量
    4. 剩余文件提示:显示原文件夹剩余图片数量

    这样修改后,检测到人物的图片会被直接移动到目标文件夹,原文件会被删除,节省磁盘空间。如果你需要保留原文件,使用 --copy参数即可。

    高级检测:

    方案1:基于YOLO的人体部位检测

    专门检测女性人体暴露或色情内容。这里有几个不同级别的实现方案:

    #!/usr/bin/env python3
    """
    女性人体暴露/色情图片检测程序
    使用YOLO模型检测暴露的身体部位
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            return None, None
    
    class NudityDetector:
        """暴露内容检测器"""
        
        def __init__(self, confidence_threshold=0.3):
            self.confidence_threshold = confidence_threshold
            # 定义敏感部位类别(基于COCO数据集)
            self.sensitive_parts = {
                'person': 0,      # 人物
                'face': 1,        # 脸部(某些数据集有)
            }
            
            # 定义暴露风险等级的关键词(用于文件名和路径分析)
            self.risky_keywords = [
                'nude', 'naked', 'bikini', 'swimsuit', 'lingerie', 'sexy', 'hot',
                '暴露', '性感', '内衣', '比基尼', '泳装', '裸体', '色情'
            ]
        
        def detect_exposure_level(self, results, filename=""):
            """
            检测图片的暴露等级
            返回: (暴露等级, 置信度, 检测到的部位)
            """
            exposure_level = 0  # 0: 安全, 1: 轻度, 2: 中度, 3: 高度暴露
            max_confidence = 0
            detected_parts = []
            
            for result in results:
                if result.boxes is not None and len(result.boxes) > 0:
                    for box in result.boxes:
                        class_id = int(box.cls)
                        confidence = float(box.conf)
                        
                        # 检测人物
                        if class_id == 0:  # person
                            detected_parts.append('person')
                            max_confidence = max(max_confidence, confidence)
                            
                            # 如果有高置信度的人物检测,基础暴露等级为1
                            if confidence > 0.5:
                                exposure_level = max(exposure_level, 1)
            
            # 基于文件名分析
            filename_risk = self.analyze_filename_risk(filename.lower())
            exposure_level = max(exposure_level, filename_risk)
            
            return exposure_level, max_confidence, detected_parts
        
        def analyze_filename_risk(self, filename):
            """分析文件名的风险等级"""
            risk_level = 0
            for keyword in self.risky_keywords:
                if keyword in filename:
                    if keyword in ['nude', 'naked', '裸体', '色情']:
                        risk_level = max(risk_level, 3)
                    elif keyword in ['bikini', 'swimsuit', 'lingerie', '比基尼', '泳装', '内衣']:
                        risk_level = max(risk_level, 2)
                    else:
                        risk_level = max(risk_level, 1)
            return risk_level
        
        def analyze_skin_ratio(self, image_path):
            """简单的肤色比例分析(基础版本)"""
            try:
                import cv2
                import numpy as np
                
                # 读取图片
                img = cv2.imread(image_path)
                if img is None:
                    return 0
                    
                # 转换到HSV颜色空间进行肤色检测
                hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
                
                # 定义肤色范围(需要根据实际情况调整)
                lower_skin = np.array([0, 20, 70], dtype=np.uint8)
                upper_skin = np.array([20, 255, 255], dtype=np.uint8)
                
                # 创建肤色掩码
                mask = cv2.inRange(hsv, lower_skin, upper_skin)
                
                # 计算肤色像素比例
                skin_ratio = np.sum(mask > 0) / (img.shape[0] * img.shape[1])
                
                return skin_ratio
                
            except Exception as e:
                print(f"肤色分析错误: {e}")
                return 0
    
    def extract_sensitive_images(source_dir, target_dir, confidence_threshold=0.3, 
                               model_size='yolov8n.pt', device='cpu', 
                               save_detection_preview=False, move_instead_of_copy=True,
                               min_exposure_level=1):
        """
        检测并提取敏感图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值
        model_size: 模型大小
        device: 运行设备
        save_detection_preview: 是否保存检测预览
        move_instead_of_copy: 是否移动文件
        min_exposure_level: 最小暴露等级 (1-3)
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 按暴露等级创建子文件夹
        level_folders = {
            1: os.path.join(target_dir, "level1_mild"),
            2: os.path.join(target_dir, "level2_moderate"),
            3: os.path.join(target_dir, "level3_high")
        }
        
        for folder in level_folders.values():
            Path(folder).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        print("=" * 70)
        print("女性人体暴露/色情图片检测程序")
        print("=" * 70)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"操作模式: {'移动' if move_instead_of_copy else '复制'}")
        print(f"最小暴露等级: {min_exposure_level}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print("-" * 70)
        
        # 警告信息
        if move_instead_of_copy:
            print("⚠️  警告: 此操作将移动图片文件!")
            response = input("是否继续?(y/N): ")
            if response.lower() != 'y':
                print("操作已取消")
                return
        
        # 初始化检测器
        detector = NudityDetector(confidence_threshold)
        
        try:
            # 加载YOLO模型
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            return
        
        # 统计信息
        total_images = 0
        detected_images = 0
        level_stats = {1: 0, 2: 0, 3: 0}
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 分析: {filename}")
            total_images += 1
            
            try:
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检测暴露等级
                exposure_level, max_confidence, detected_parts = detector.detect_exposure_level(results, filename)
                
                # 简单的肤色比例分析
                skin_ratio = detector.analyze_skin_ratio(file_path)
                if skin_ratio > 0.3:  # 如果肤色比例较高,提高暴露等级
                    exposure_level = max(exposure_level, 2)
                
                if exposure_level >= min_exposure_level:
                    detected_images += 1
                    level_stats[exposure_level] = level_stats.get(exposure_level, 0) + 1
                    
                    # 确定目标文件夹
                    target_level_folder = level_folders.get(exposure_level, target_dir)
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_level_folder, filename)
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_level_folder, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 移动或复制文件
                    if move_instead_of_copy:
                        shutil.move(file_path, target_path)
                        operation_text = "移动"
                    else:
                        shutil.copy2(file_path, target_path)
                        operation_text = "复制"
                    
                    # 保存检测预览
                    if save_detection_preview:
                        try:
                            preview_results = model(target_path if move_instead_of_copy else file_path, 
                                                  conf=confidence_threshold, device=device, verbose=False)
                            plotted_image = preview_results[0].plot()
                            preview_filename = f"L{exposure_level}_preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    # 暴露等级描述
                    level_descriptions = {
                        1: "轻度暴露",
                        2: "中度暴露", 
                        3: "高度暴露"
                    }
                    
                    print(f"  ✓ 检测结果: {level_descriptions.get(exposure_level, '未知')} (等级{exposure_level})")
                    print(f"  ✓ 肤色比例: {skin_ratio:.3f}")
                    print(f"  ✓ 检测部位: {', '.join(detected_parts) if detected_parts else '无'}")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已{operation_text}到: level{exposure_level}/{os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'exposure_level': exposure_level,
                        'skin_ratio': skin_ratio,
                        'detected_parts': detected_parts,
                        'detection_time': detection_time,
                        'operation': operation_text
                    })
                    
                else:
                    print(f"  ✗ 安全图片 (暴露等级: {exposure_level}, 检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 70)
        print("检测完成!")
        print("=" * 70)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到敏感图片: {detected_images}张")
            print(f"检测率: {(detected_images/total_images*100):.1f}%")
            
            print(f"\n暴露等级分布:")
            for level, count in level_stats.items():
                if count > 0:
                    level_desc = {1: "轻度暴露", 2: "中度暴露", 3: "高度暴露"}.get(level, "未知")
                    print(f"  等级{level} ({level_desc}): {count}张")
            
            if detected_images > 0:
                operation_mode = "移动" if move_instead_of_copy else "复制"
                print(f"\n敏感图片已{operation_mode}到对应等级的文件夹")
                
                # 显示检测结果
                if processed_files:
                    processed_files.sort(key=lambda x: x['exposure_level'], reverse=True)
                    print(f"\n风险最高的图片:")
                    for i, file_info in enumerate(processed_files[:5]):
                        print(f"  {i+1}. {file_info['filename']} - 等级{file_info['exposure_level']} "
                              f"(肤色比例: {file_info['skin_ratio']:.3f})")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='女性人体暴露/色情图片检测程序')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='sensitive_images',
                           help='目标文件夹路径 (默认: sensitive_images)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        parser.add_argument('--copy', action='store_true',
                           help='使用复制模式而不是移动模式')
        parser.add_argument('--level', type=int, default=1, choices=[1, 2, 3],
                           help='最小暴露等级 (1:轻度, 2:中度, 3:高度, 默认: 1)')
        
        args = parser.parse_args()
        
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        extract_sensitive_images(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview,
            move_instead_of_copy=not args.copy,
            min_exposure_level=args.level
        )
    
    if __name__ == "__main__":
        import sys
        if len(sys.argv) == 1:
            # 简化模式运行
            source_dir = os.getcwd()
            target_dir = os.path.join(source_dir, "sensitive_images")
            
            print("女性人体暴露图片检测程序")
            print("此操作将检测并分类暴露程度的图片!")
            
            response = input("是否继续?(y/N): ")
            if response.lower() == 'y':
                extract_sensitive_images(source_dir, target_dir, move_instead_of_copy=True)
            else:
                print("操作已取消")
        else:
            main()
    

    方案2:使用专门的NSFW检测模型

    如果需要更准确的结果,可以使用专门的NSFW检测模型:

    # 需要额外安装的库
    # pip install tensorflow keras
    
    def setup_nsfw_detector():
        """设置专门的NSFW检测器"""
        try:
            # 这里可以使用预训练的NSFW检测模型
            # 例如: https://github.com/rockyzhengwu/nsfw
            print("正在加载NSFW检测模型...")
            # 实际实现需要下载预训练模型
            return None
        except ImportError:
            print("请安装TensorFlow: pip install tensorflow")
            return None
    

    使用方法:

    # 基本使用(移动模式,检测所有暴露等级)
    python sensitive_detector.py
    
    # 只检测高度暴露的图片
    python sensitive_detector.py --level 3
    
    # 复制模式(保留原文件)
    python sensitive_detector.py --copy
    
    # 指定源文件夹和目标文件夹
    python sensitive_detector.py --source ./图片库 --target ./敏感图片
    
    # 保存检测预览
    python sensitive_detector.py --preview
    
    # 使用更准确的模型
    python sensitive_detector.py --model yolov8s.pt
    

    暴露等级说明:

    • 等级1(轻度): 检测到人物,可能有轻微暴露
    • 等级2(中度): 检测到较多肤色区域或敏感关键词
    • 等级3(高度): 高度暴露内容,包含大量肤色区域或明确敏感内容

    注意事项:

    1. 准确率限制: 这种检测方法有一定误判率
    2. 隐私保护: 请确保合法使用,尊重他人隐私
    3. 法律合规: 在不同地区使用此类工具可能受到法律限制
    4. 人工审核: 建议最终结果由人工审核确认

    这个程序会按暴露程度将图片分类到不同的文件夹,方便你进一步处理。

    正确的运行方法:

    方法1:直接运行Python脚本

    # 进入脚本所在目录
    cd /home/leepoet/Documents/env/myenv/甜心
    
    # 直接运行Python脚本
    python 女性人体暴露.py
    

    方法2:给脚本添加执行权限后直接运行

    # 进入脚本所在目录
    cd /home/leepoet/Documents/env/myenv/甜心
    
    # 给脚本添加执行权限
    chmod +x 女性人体暴露.py
    
    # 直接运行脚本
    ./女性人体暴露.py
    

    设置自定义检测路径

    你可以通过命令行参数灵活指定源文件夹和目标文件夹:

    # 检测指定文件夹,结果保存到自定义目录
    python your_script.py --source /path/to/your/images --target /path/to/output

    # 完整参数示例
    python your_script.py --source /home/user/photos --target /home/user/sorted_photos --confidence 0.5 --model yolov8s.pt --preview --copy

    4. 关键参数说明

    • --source: 指定需要检测的图片文件夹路径
    • --target: 指定结果输出文件夹路径
    • --confidence: 调整检测灵敏度(0.1-1.0)
    • --model: 选择不同的YOLO模型(影响精度和速度)
    • --preview: 保存带检测框的预览图
    • --copy: 使用复制模式(默认是移动文件)
  • Pintree:重新定义你的书签体验,开启高效导航新方式!

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    在日常浏览网页时,你是否常常为书签管理而头疼?面对成百上千个收藏链接,每次查找都像大海捞针。那些曾经精心保存的技术文档、实用工具,是不是早已在书签栏里“沉睡”多年?随着收藏内容不断增多,书签变得杂乱无章、难以查找,跨设备使用也极为不便。

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    今天,我们要介绍一款开源工具——Pintree,它能够将繁琐的浏览器书签一键转变为美观实用的导航网站,轻松解决书签管理的所有痛点。无论你是技术开发者、运维人员,还是普通用户,Pintree 都能让你的书签变得井井有条,易于查找和分享。

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    Pintree 的核心功能十分强大:

    • •快速转换:只需几分钟,无需编程基础,即可将书签导出并转换为结构清晰的导航页面。
    • •美观实用:支持多种主题风格、图标布局和背景自定义,让你的导航页既好看又好用。
    • •多平台分享:一键部署,轻松将你的导航网站发布到线上,方便个人使用或团队共享。
    • •收益可能:通过广告变现,让你的收藏也能产生价值。

    Pintree 基于 Next.js 构建,可部署于 Vercel,并使用 PostgreSQL 存储数据,稳定高效。操作流程非常简单:

    一、使用 Pintree 浏览器插件导出书签为 JSON 文件;

    首先,我们需要将收藏夹的链接导出为 JSON 文件。安装 Pintree Bookmarks Exporter 浏览器插件,点击 Export Bookmarks,选择书签栏里的文件夹,点击 continue 后便可以下载导出的 JSON 文件。

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    二、将文件上传至你 Fork 的 Pintree 项目仓库;

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    三、在 GitHub Pages 中启用页面部署,即可拥有专属导航网站。

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    最后,我们启用 GitHub 页面功能。在你的 pintree 仓库页面中,点击“Settings”(设置)。找到“Pages”选项。在“Source”下拉菜单中,选择“gh-pages”分支,然后点击“Save”(保存)。几分钟后,你的静态网站将会在 https://yourusername.github.io/pintree 上可用,当然要替换“yourusername”。

    Pintree:重新定义你的书签体验,开启高效导航新方式!

    你还可以根据自己的喜好调整页面样式,打造独一无二的导航体验。无论是用于个人知识管理,还是希望分享优质资源,Pintree 都是一个值得尝试的工具。点击下方链接,立即体验 Pintree 带来的便捷与高效!

    项目地址:https://github.com/Pintree-io/pintree

    官网:https://pintree.io/

  • 从开源到顶流:Animate.css12年打磨的动画库如何吸引8万+开发者追随

    从开源到顶流:Animate.css12年打磨的动画库如何吸引8万+开发者追随

    在如今网页设计快速迭代的时代,如何让页面更生动、更吸引用户?

    一款开源的 CSS 动画库 —— Animate.css,用简单的方式解决了添加动画效果的复杂性。无论是增强用户体验,还是打造更具冲击力的界面设计,Animate.css 都能轻松实现,成为你的助力工具。

    Animate.css是什么

    从开源到顶流:Animate.css12年打磨的动画库如何吸引8万+开发者追随

    Animate.css 是一个轻量级、开箱即用的开源 CSS 动画库,内置了几十种常见的交互动画。从淡入淡出到弹跳翻转,它把原本需要手写关键帧的繁琐操作,简化成类名引用。对前端开发者来说,这意味着几行 HTML 就能让元素动起来,而且兼容主流浏览器,基本不用操心降级问题。

    开源成就

    • Star数
      在 GitHub 上已收获 超过 82k 星标,长期位居 CSS 类库热门榜单前列,是许多团队搭建原型或落地页时的首选工具。
    • 主开发语言
      项目以 CSS 为主(67.8%),配合 HTML 示例和少量 JavaScript 控制逻辑,结构清晰,维护成本低。

    核心功能

    从开源到顶流:Animate.css12年打磨的动画库如何吸引8万+开发者追随
    • 丰富的动画效果
      提供上百种预设动画,涵盖进入、退出、强调等多种场景。比如想做个按钮抖动提醒,直接加个 animate__shake 就行,省去了查文档写 @keyframes 的时间。
    • 跨平台兼容性
      经过多年迭代,它对 Chrome、Firefox、Safari 等主流浏览器支持良好,移动端也能稳定运行,基本不会出现“本地正常、线上抽风”的情况。

    • 无障碍支持
      很少有动画库认真对待这一点,但 Animate.css 主动适配了系统的 prefers-reduced-motion 设置——当用户开启“减少动画”偏好时,动画会自动关闭,这对敏感人群非常友好。
    • 轻松定制
      如果只用到几个动画,可以通过 Sass 源码按需引入,打包后体积可以控制在几KB以内,避免加载一整个库却只用一两个效果的浪费。 Hello, Animate.css!  
    • 快速集成
      不依赖框架,原生 HTML/CSS 项目也能用。只要引入文件,再给元素加上对应的类名,动画立马生效,适合快速验证交互想法。

    安装指南

    使用 npm 或 yarn 直接安装 Animate.css:

    # 使用 npm 安装
    npm install animate.css --save

    # 使用 yarn 安装
    yarn add animate.css

    在 HTML 文件中引入:

    <link rel="stylesheet" href="animate.min.css">

    为元素添加动画效果:

    <div class="animate__animated animate__bounce">
      这是一个带动画效果的元素
    div>

    注意:所有动画都需要先加上 animate__animated 基础类,再叠加具体效果类(如 animate__bounce),这是它的命名约定。

    如果需要更复杂的控制,比如延迟、重复次数或回调函数,可以结合 JavaScript 使用,官网提供了详细示例:https://animate.style/

    Animate.css 并不是什么黑科技,但它解决了一个很实际的问题:怎么低成本地给页面加点“动静”。对于新手,它是学习 CSS 动画的友好入口;对于老手,它是个可靠的“动画零件库”,能在赶工期时救一把。如果你还在手动写 keyframes 实现 hover 效果,或许真该试试这个用了就知道香的工具。

    开源地址https://github.com/animate-css/animate.css

  • 如何将文章统计数据模块完美嵌入WordPress主题

    如何将文章统计数据模块完美嵌入WordPress主题

    想要在WordPress网站上清晰展示各分类的文章数量吗?本文分享一个强大的短代码解决方案,不仅能显示全站文章总数,还能自动列出每个分类下的文章数量,让内容结构一目了然。

    该代码实现了以下功能:

    1. 使用wp_count_posts()获取已发布文章总数
    2. 通过get_categories()获取所有分类信息
    3. 遍历分类并显示每个分类下的文章数量
    4. 返回包含HTML结构的统计结果

    使用方法:

    function enhanced_post_count() {
        // 获取总文章数
        $total_posts = wp_count_posts('post')->publish;
        $output = '<div class="post-stats">';
        $output .= '<p>总文章数: <strong>' . $total_posts . '</strong></p>';
        
        // 获取所有分类
        $categories = get_categories(array(
            'orderby' => 'name',
            'hide_empty' => false
        ));
        
        $output .= '<ul class="category-stats">';
        foreach ($categories as $category) {
            // 获取每个分类的文章数
            $cat_count = $category->count;
            $output .= sprintf(
                '<li>%s: %d篇</li>',
                $category->name,
                $cat_count
            );
        }
        $output .= '</ul></div>';
        
        return $output;
    }
    add_shortcode('enhanced_post_count', 'enhanced_post_count');
    • 将代码添加到主题的functions.php文件中
    • 在文章或页面中使用短代码:
    [enhanced_post_count]
    • 可通过CSS美化输出样式

    下面是记录是调用上面的代码记录本站文章的展示:[enhanced_post_count]

    如需进一步定制,可以:

    • 添加参数控制是否显示空分类
    • 按文章数量排序分类
    • 添加分类链接
    • 使用缓存提高性能

  • 🔒 掌控内容可见性:纯代码WordPress文章隐藏与会员内容保护完全指南

    🔒 掌控内容可见性:纯代码WordPress文章隐藏与会员内容保护完全指南

    在信息过载的数字时代,​​精准控制内容的可见性​​已成为WordPress网站主的核心需求。无论是为了保护独家资源、提升会员价值,还是为了优化用户体验和实现更精准的引流,掌握如何隐藏文章内容都是一项至关重要的技能。

    数据显示,​​超过90%的WordPress用户​​可能忽略了通过内容隐藏来提升网站价值与安全性的巨大潜力。默认情况下,WordPress会显示所有文章内容,这在很多场景下并非最优选择。例如,若您希望​​引导访客关注微信公众号​​以查看隐藏内容,或仅向​​已登录的会员、订阅用户​​展示专属信息,亦或是单纯地让网站首页和列表页显得更加简洁,您都需要对内容的可见性进行有效管理。

    本指南将为您系统梳理在WordPress中隐藏文章内容的多种方法,从无需编程的插件方案到高度自定义的代码实现,助您找到最适合自身技术水平和业务需求的解决方案。

    在WordPress中隐藏文章内容是一个常见需求,可能是为了提供会员专属内容、引导用户注册,或者只是想让首页和列表页更简洁。下面我为你介绍几种主流方法。

    下面这个表格汇总了各方法的特点,方便快速了解:

    方法易用性灵活度技术要求推荐场景隐藏效果
    ​插件法​⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐大部分用户,尤其是不熟悉代码或需要复杂功能​完全隐藏​​,源代码中也不可见(部分插件)
    ​简码法​⭐⭐⭐⭐⭐⭐⭐⭐需要为登录用户和访客显示不同内容​选择性显示​​,内容仍在源代码中
    ​主题代码修改法​⭐⭐⭐⭐⭐⭐⭐⭐熟悉代码的用户,需要永久性修改或高度自定义​完全移除​​,源代码中也不可见
    ​区块可见性控制​⭐⭐⭐⭐⭐⭐⭐⭐使用古腾堡编辑器,需要根据条件(如用户角色、设备)隐藏内容​条件性显示​​,内容仍在源代码中

    🧩 ​​一、使用插件隐藏内容(推荐给大多数用户)​

    插件是最简单灵活的方式,尤其适合不熟悉代码的用户。

    1. ​内容访问控制插件​​:例如 ​​Content Control​​ 插件,允许你根据用户角色或登录状态来显示或隐藏内容。
    2. ​密码保护插件​​:像 ​​Passster​​ 这样的插件,可以密码保护文章的任何部分。你只需用短代码(如 
     [passster]你的隐藏内容 [/passster]

    )包裹内容,并设置密码

    3.​​登录后可见插件​​:有些插件支持使用短代码(例如 

     [loginview]隐藏内容 [/loginview]

    )来标记仅限登录用户查看的内容。用户登录后才会显示这些内容。

    4.​​微信公众号引流插件​​:有些插件可以隐藏内容,并要求用户关注指定的微信公众号并回复关键词后才能查看。这类插件通常使用类似 

    [hide]隐藏内容 [/hide]

    的简码。

    💡 ​​选择提示​​:在选择插件时,务必在WordPress官方插件库或可信来源查看其评价、更新日期和兼容性。

    🧑‍💻 ​​二、使用短代码(需添加代码)​

    如果你习惯用代码,可以在主题的 functions.php文件中添加代码来创建自定义短代码,控制内容的显示。

    例如,创建一个名为 members_only的短代码,使内容仅对登录用户可见:

    // 添加只允许登录后查看的短代码
    add_shortcode( 'members_only', 'members_only_shortcode' );
    function members_only_shortcode( $atts, $content = null ) {
        if ( is_user_logged_in() && !empty( $content ) && !is_feed() ) {
            return $content; // 已登录用户看到内容
        }
        // 未登录用户看到提示信息
        return '<div style="text-align:center; border:1px dashed #FF9A9A; padding:8px; margin:10px auto; color:green;">要查看更多文章内容,请您先<a href="' . wp_login_url() . '" target="_blank">登录/注册</a></div>';
    }

    添加后,在文章中使用 

    [members_only]这里是仅限会员的内容 [/members_only]

    ,未登录用户将看到提示登录的样式框。

    拿我这个博客来讲,我做的只是一个记录自己知识储备的博客,不需要用户注册,只有我自己一个人用,那么,我可以把<a href=”‘ . wp_login_url() . ‘” target=”_blank”>变成<a href=”” target=”_blank”>就可以了。或者把return这段都去掉都行

    🔒 掌控内容可见性:纯代码WordPress文章隐藏与会员内容保护完全指南

    这是改完后的效果

    🔒 掌控内容可见性:纯代码WordPress文章隐藏与会员内容保护完全指南

    ⚙️ ​​三、修改主题模板文件(永久性隐藏)​

    此方法直接修改主题文件,效果是永久性的。​​强烈建议操作前备份,并使用子主题​​,防止主题更新丢失修改。

    若希望首页、分类页等存档页面只显示文章标题或摘要,而不显示全文,你需要修改主题模板文件,如 index.phparchive.php。找到循环(Loop)中调用文章内容的函数(如 the_content()),注释掉或删除它。

    🔧 ​​四、使用古腾堡区块的可见性条件​

    如果你使用WordPress的古腾堡编辑器,一些插件(如 ​​Block Visibility​​)可以为区块编辑器添加显示条件控制。你可以根据用户角色、登录状态、设备类型、日期时间等条件来设置特定区块的显示或隐藏。

    🤔 ​​如何选择方法?​

    • •​​追求简单快捷​​:从​​插件法​​开始,它能满足大多数需求且风险低。
    • •​​需要高度定制化​​:如果你懂代码,​​简码法​​和​​修改主题文件​​能提供更灵活的控制。
    • •​​临时或条件性隐藏​​:​​区块可见性控制​​插件很适合。
    • •​​为特定用户群提供内容​​:结合​​用户角色控制插件​​和​​会员插件​​。

    💎 ​​记住​​:没有唯一“正确”的方法,最佳选择取决于你的具体需求和技术舒适度。对于大多数用户,从一款合适的插件开始尝试通常是最稳妥的起点。

  • 如何高效批量重命名:告别杂乱文件,一键生成数字序列

    如何高效批量重命名:告别杂乱文件,一键生成数字序列

    犯有仓鼠症的玩家都知道,我们电脑里的学习资料多如牛毛,尤其是图片文件,命名杂乱无章,整理起来异常头疼。利用 Windows 自带的 CMD 和批处理脚本进行批量重命名,可以极大提升效率。下面我将为你提供一个从创建脚本到执行的完整方案。

    如何高效批量重命名:告别杂乱文件,一键生成数字序列

    📌 操作方法:使用批处理脚本

    通过创建一个批处理文件(.bat),你可以快速将指定目录下的所有 JPG 文件按数字序列重命名(例如 1.jpg, 2.jpg, 3.jpg …)。

    步骤 1:创建批处理文件

    1. 1.在需要批量重命名的图片文件夹中,​​右键​​ > ​​新建​​ > ​​文本文档​​。
    2. 2.打开新建的文本文件,将以下代码复制粘贴进去:
    @echo off
    setlocal enabledelayedexpansion
    
    set count=0
    for %%i in (*.jpg) do (
        set /a count+=1
        ren "%%i" "!count!.jpg"
    )
    
    echo 重命名完成!共重命名了 !count! 个文件。
    pause
    1. 点击​​文件​​ > ​​另存为​​。在保存对话框中:
      • •​​保存类型​​ 选择 ​​“所有文件”​​。
      • •​​文件名​​ 输入任意名称,但​​后缀必须为 .bat​(例如 批量重命名.bat)。
      • •​​编码​​ 建议选择 ​​ANSI​​ 以避免中文乱码。
    2. 点击​​保存​​。

    步骤 2:运行脚本

    双击运行刚刚保存的 .bat文件。脚本会自动将当前文件夹内所有 .jpg文件按顺序重命名为 1.jpg2.jpg3.jpg……命令行窗口会显示完成提示

    ⚠️ 重要注意事项

    1. ​备份文件​​:在执行批量重命名操作前,​​务必对原始文件进行备份​​。重命名操作通常是不可逆的,一旦执行难以恢复。
    2. 文件顺序​​:通过此方法重命名文件的​​顺序可能与你在资源管理器中所见的顺序不同​​,因为它依赖于 dir命令读取文件的顺序,这通常与文件创建时间等相关。如果需要严格按照特定顺序(如按修改时间、文件名排序),建议先对文件进行排序,或使用更强大的脚本工具(如 PowerShell 或 Python)。
    3. ​文件名冲突​​:确保目标文件夹中​​没有现成的 1.jpg2.jpg等文件​​,否则重命名时会因文件名冲突而失败。
    4. ​特殊字符与长路径​​:如果文件名中包含​​空格或特殊字符​​(如括号),在批处理命令中需要用​​双引号​​将文件名括起来。上述脚本已对此进行处理。极长的路径也可能导致命令失败。
    5. ​仅处理当前目录​​:此脚本默认只重命名​​批处理文件所在目录​​下的 JPG 文件,不会处理子文件夹中的文件。

    💡 扩展应用与技巧

    • •​​修改文件扩展名​​:如果你想批量修改其他类型的文件扩展名(如将所有 .png.crdownload改为 .png),只需修改脚本中的文件扩展名即可,或使用命令 ren *.crdownload *.png
    • •​​自定义命名格式​​:
      • •若想在数字前加​​前缀​​(如 photo_1.jpg),可将 ren "%%i" "!count!.jpg"改为 ren "%%i" "photo_!count!.jpg"
      • •若想保持数字编号的​​统一位数​​(如 0001.jpg0002.jpg),可修改脚本如下:
    @echo off
    setlocal enabledelayedexpansion
    set count=10000 # 从10000开始,利用字符串截取后4位
    for %%i in (*.jpg) do (
        set /a count+=1
        set newname=!count:~-4! # 提取后四位数字
        ren "%%i" "!newname!.jpg"
    )
    pause
    • •​使用 Excel 辅助复杂重命名​​:对于非常复杂、无规律的重命名需求(例如每个文件的新名都不同),可以先用 dir /b *.jpg > filenames.txt命令导出原文件名列表到文本文件,然后在 Excel 中加工,生成所有 ren命令,最后复制回批处理文件执行。

    🔄 替代方案:文件资源管理器快速重命名

    如果需求很简单,只是需要快速加上序列号,Windows 文件资源管理器本身就提供了一个快捷方法

    在文件夹中​​全选​​(Ctrl + A)所有要重命名的 JPG 文件。

    1. 按下 ​​F2​​ 键,或右键点击第一个文件选择​​重命名​​。
    2. 输入一个基础名称(如 学习资料),然后按回车键。
    3. 系统会自动将所有文件命名为 学习资料 (1).jpg学习资料 (2).jpg学习资料 (3).jpg……。

  • 红帽子(Red Hat)系列操作系统

    红帽子(Red Hat)系列操作系统

    红帽子(Red Hat)是创立于1993年的美国开源软件公司,专注于基于Linux内核的操作系统及相关技术服务。其早期产品Red Hat Linux因图形界面友好、稳定性强,曾成为最受欢迎的Linux商业发行版之一。2003年起停止更新Red Hat Linux,转向维护社区驱动的Fedora项目,并推出企业级产品Red Hat Enterprise Linux(RHEL),通过订阅模式提供技术支持与系统更新服务 

    红帽子(Red Hat)系列操作系统

    该公司于2000年进入中国市场,2004年在北京设立办事处拓展本地业务。RHEL系列针对企业服务器与数据中心设计,整合了YUM包管理器、SELinux安全机制等技术,支持多平台部署与混合云环境。其开源模式允许用户自由修改和分发代码,同时通过订阅认证限制官方软件源访问,形成“开源+商业服务”的商业模式。红帽子还参与制定开源许可规范,推动GPL协议合规性解决方案,促进技术生态协作。

    由于 Red Hat Enterprise Linux (RHEL) 是企业级收费系统,获取其镜像通常需要订阅账户。不过,也有一些免费的替代方案和开发者资源可供选择。

    主要的 Red Hat 相关下载渠道和资源:

    来源类型提供方/渠道名称网址主要特点/说明
    ​🌐 官方渠道​Red Hat 官方开发者门户https://developers.redhat.com/products/rhel/download提供免费的 ​​Red Hat Developer Subscription​​,可用于开发环境。需要注册账户。
    Red Hat 官方下载入口https://access.redhat.com/downloadsRed Hat 客户和合作伙伴的官方下载门户,需有效的订阅账户才能访问。
    ​🔧 免费替代版​CentOShttps://www.centos.org/download/曾经是 RHEL 的著名免费克隆版,CentOS Linux 已停止更新,转向 CentOS Stream。
    Rocky Linuxhttps://rockylinux.org/download/由原 CentOS 创始人发起,旨在继承 CentOS 的使命,提供企业级的稳定 Linux 发行版。
    AlmaLinuxhttps://almalinux.org/另一个 RHEL 的 1:1 二进制兼容发行版,由社区驱动。
    ​🇨🇳 国内镜像站​阿里云开源镜像站https://mirrors.aliyun.com/redhat/提供 Red Hat 相关镜像,国内下载速度通常较快。​​注意​​:访问某些受限资源可能仍需红帽账户。
    清华大学开源镜像站https://mirrors.tuna.tsinghua.edu.cn/国内高校镜像站,同步多种开源软件镜像。
    中国科学技术大学镜像站http://mirrors.ustc.edu.cn/教育网和公网用户访问体验良好。
    ​🌍 国际资源​Fedora Linuxhttps://fedoraproject.org/Red Hat 赞助的社区发行版,适合桌面和前沿技术体验。

    💡 重要提示

    • •​​版本选择​​:Red Hat Enterprise Linux (RHEL) 是​​企业级收费操作系统​​,需购买订阅才能获得官方完整支持、安全更新和合规保障。个人开发者或学习环境,可优先考虑 ​​Rocky Linux​​、​​AlmaLinux​​ 或 ​​Fedora​​。
    • •​​开发者订阅​​:对于开发者,​​Red Hat Developer Subscription​​ 是个不错的选择。它免费提供 RHEL 用于开发目的,但​​不支持生产环境​​。
    • •​​文件校验​​:无论从何种渠道获取镜像,下载后务必校验 ​​SHA256​​ 校验和,以确保文件完整性和安全性。
    • •​​合规使用​​:使用 RHEL 时,请严格遵守 Red Hat 的订阅协议。不建议通过非官方渠道获取用于生产环境的 RHEL,这可能存在法律和安全风险。

    🔄 其他替代选择

    如果你正在寻找 RHEL 的免费替代品,除了上面表格中提到的 CentOS Stream、Rocky Linux 和 AlmaLinux,还有其他流行的 Linux 发行版可供选择,例如 ​​Ubuntu Server​​ 或 ​​Debian​​,它们在社区支持和软件生态方面也非常丰富。

    RHEL(Red Hat Enterprise Linux)系列是企业级 Linux 发行版的标杆,以其​​卓越的稳定性、强大的安全性和长期的技术支持​​而闻名。下面我将通过一个表格帮你快速了解 RHEL 系列的核心成员和主要特点,然后我们再展开聊聊。

    发行版名称核心定位与特点适用场景
    ​RHEL​​企业级商业发行版​​,提供​​10年生命周期支持​​,强调稳定性、安全性和官方技术支持,需付费订阅。大型企业关键业务系统、需要高可靠性和官方支持的环境。
    ​Fedora​​社区支持的免费发行版​​,是 RHEL 的​​上游测试平台​​,专注于引入新技术和创新。开发者、技术爱好者、追求最新技术的用户。
    ​CentOS Stream​位于 Fedora 之后,RHEL 之前,是 RHEL 的​​上游开发版​​,采用滚动更新模式。希望参与 RHEL 开发过程、需要接近 RHEL 但更前沿环境的用户。
    ​AlmaLinux​由社区驱动的免费发行版,旨在与 RHEL ​​1:1 二进制兼容​​,作为 CentOS Linux 的替代品之一。需要 RHEL 兼容性但无需付费商业支持的环境。
    ​Rocky Linux​同样由社区驱动,与 RHEL ​​1:1 二进制兼容​​,也是 CentOS Linux 的替代品之一。需要 RHEL 兼容性但无需付费商业支持的环境。
    ​Oracle Linux​由 Oracle 提供,与 RHEL ​​完全二进制兼容​​,提供两种内核选择(RHEL兼容内核或Oracle UEK),针对Oracle数据库和应用优化。运行 Oracle 数据库及软件栈的环境。

    🧭 ​​RHEL 系列的核心特点​

    RHEL 系列之所以能成为企业级应用的优选,主要得益于以下几个核心特点:

    • •​​极致的稳定性与可靠性​​:RHEL 经过严格的测试和验证,其​​长期支持(LTS)​​ 版本(通常提供10年的生命周期支持)确保了企业关键业务能够长期稳定运行。
    • •​​强大的安全性​​:集成 ​​SELinux(安全增强型 Linux)​​、防火墙管理工具(如 firewalld)以及定期且及时的安全更新和补丁,为系统提供多层次的保护。
    • •​​广泛的硬件与软件兼容性​​:支持多种硬件架构(x86_64, ARM64, IBM Power, IBM Z 等)4,并拥有大量经过认证的硬件和软件,减少了企业部署时的兼容性障碍。
    • •​​全面的技术支持与订阅服务​​:通过付费订阅,用户可以获得红帽官方的技术支持、安全更新和漏洞修复,这对于企业环境至关重要。
    • •​​丰富的生态系统与管理工具​​:提供如 ​​Red Hat Satellite​​(用于大规模系统管理)、​​Cockpit​​(Web 管理界面)以及深度集成 ​​Ansible​​ 自动化工具等,极大简化了系统管理和运维工作。
    • •​​优异的虚拟化与容器支持​​:原生支持 ​​KVM 虚拟化​​,并深度集成 ​​Podman​​、​​Buildah​​ 等容器工具,以及 ​​OpenShift​​(企业级 Kubernetes 平台),很好地适应了云原生和容器化趋势。

    💡 ​​如何选择 RHEL 系列的发行版?​

    选择哪一款 RHEL 系列的发行版,主要取决于你的具体需求、场景和预算:

    1. 1.​​企业关键业务,需要极致稳定与官方支持​​:选择 ​​RHEL​​ 本身。这是为那些需要最可靠支持、最长生命周期保障和经过最严格认证的环境准备的。
    2. 2.​​追求新技术,用于开发或学习​​:​​Fedora​​ 是一个很好的选择,你可以在这里体验到最新的技术和创新。
    3. 3.​​需要 RHEL 兼容性,但希望更早接触新特性或参与贡献​​:​​CentOS Stream​​ 可以让你提前了解 RHEL 下一个版本的内容。
    4. 4.​​需要 RHEL 的稳定性与兼容性,但无付费商业支持需求​​:​​AlmaLinux​​ 或 ​​Rocky Linux​​ 这些由社区驱动的、与 RHEL 1:1 兼容的发行版是很好的免费替代品。
    5. 5.​​深度依赖 Oracle 生态(如 Oracle 数据库)​​:​​Oracle Linux​​ 针对 Oracle 的软件栈进行了优化,是这类环境的自然选择。

    🔍 ​

    RHEL 系列通过其​​商业版(RHEL)​​、​​上游项目(Fedora, CentOS Stream)​​ 以及​​下游衍生版(AlmaLinux, Rocky Linux, Oracle Linux 等)​​,共同构成了一个既满足企业级严苛要求,又拥抱开源创新的强大生态系统。

  • GitHub 是一个全球知名的 ​​基于 Git 的代码托管和协作平台

    GitHub 是一个全球知名的 ​​基于 Git 的代码托管和协作平台

    GitHub 是一个全球知名的 ​​基于 Git 的代码托管和协作平台

    GitHub是一项基于云的服务,为软件开发和Git版本控制提供Internet托管。这有助于开发人员存储和管理他们的代码,同时跟踪和控制对其代码的更改。GitHub拥有超过1.5亿开发者,400万个组织机构,4.2亿个存储库。

    主要用于软件开发中的版本控制、项目管理和团队协作

    7。它由 Tom Preston-Werner、Chris Wanstrath、P.J. Hyett 和 Scott Chacon 于 ​​2008 年 2 月创立​​,并于同年 ​​4 月正式上线​

    2018 年,GitHub 被 ​​微软以 75 亿美元收购​

    以下是 GitHub 的一些核心功能和特点:

    🗂️ 1. ​​代码托管与版本控制​

    GitHub 使用 ​​Git​​ 作为其版本控制系统

    2,允许开发者:

    • •​​跟踪代码更改​​:记录每一次修改,便于回溯和历史查看。
    • •​​分支管理​​:开发者可以创建分支来独立开发新功能或修复问题,然后通过合并(Merge)将更改整合回主分支。
    • •​​协作开发​​:支持多人同时在同一个项目上工作,而不会互相干扰。

    👥 2. ​​协作与社交编程​

    GitHub 提供了丰富的工具来促进开发者之间的协作:

    • •​​Pull Requests(PR)​​:允许开发者提议更改并请求代码审查,确保代码质量后再合并。
    • •​​Issues​​:用于报告 Bug、提出新功能建议或跟踪任务进度。
    • •​​代码审查​​:团队成员可以在 PR 中评论代码、提出改进建议。
    • •​​社交功能​​:开发者可以 ​​Star(点赞)​​、​​Fork(复制仓库)​​ 和 ​​Watch(关注)​​ 项目,便于关注和参与开源项目。

    🌍 3. ​​开源社区​

    GitHub 是全球最大的 ​​开源社区​​:

    • •​​海量开源项目​​:数百万的开源项目托管于此,涵盖了几乎所有编程语言和技术领域。
    • •​​参与和贡献​​:任何开发者都可以轻松地 Fork 项目,进行修改并通过 Pull Request 贡献代码。
    • •​​探索与学习​​:开发者可以通过 GitHub 发现新技术、学习最佳实践并了解行业趋势。

    ⚙️ 4. ​​自动化与集成(CI/CD)​

    GitHub 提供了强大的自动化工具:

    • •​​GitHub Actions​​:允许开发者创建自定义的 CI/CD(持续集成/持续部署)工作流,自动化完成代码的构建、测试和部署6。
    • •​​第三方集成​​:支持与 Jenkins、Travis CI、Slack、Jira 等众多开发工具集成,扩展平台功能。

    📊 5. ​​项目管理​

    GitHub 也提供了一系列项目管理工具:

    • •​​Projects​​:看板式的项目管理工具,帮助团队跟踪任务和进度。
    • •​​Wiki​​:每个仓库都可以拥有一个 Wiki,用于编写和维护项目文档。
    • •​​GitHub Pages​​:允许用户直接从仓库托管静态网站,常用于搭建项目文档、个人博客或作品集6。

    🔒 6. ​​部署选项与安全性​

    • •​​仓库可见性​​:用户可以创建​​公开仓库​​(所有人可见)或​​私有仓库​​(仅限授权用户访问)。免费账户也可以创建无限量的私有仓库(但协作人数受限)。
    • •​​企业级服务​​:​​GitHub Enterprise​​ 提供私有化部署选项,满足大型组织对安全性、合规性和高级权限管理的需求。
    • •​​安全功能​​:提供如 CodeQL 代码扫描、Dependabot 漏洞警报等内置安全工具,帮助开发者识别和修复安全风险。

    🤖 7. ​​AI 赋能​

    近年来,GitHub 大力整合人工智能来提升开发者效率:

    • •​​GitHub Copilot​​:一款 AI 编程助手,基于 OpenAI 技术,可以在编写代码时提供实时的代码补全和建议。

    GitHub 已然成为现代软件开发不可或缺的基础设施,无论是个人开发者记录学习历程、团队协作开发项目,还是大型企业维护复杂系统,它都能提供强大的支持。

  • WordPress无需插件实现IndexNow提交搜索引擎促进抓取

    WordPress无需插件实现IndexNow提交搜索引擎促进抓取

    WordPress无需插件实现IndexNow提交搜索引擎促进抓取

    如果我们用过 IndexNow Plugin 插件的话应该知道在Bing搜索引擎工具中有这个插件可以提高必应和几个搜索引擎的抓取的,当然也不是所有的搜索引擎都识别。如果我们有需要做必应搜索推送的可以配合这个插件,当然我们也可以不用插件直接用代码实现。

    //NoPlugin IndexNow
    add_action('save_post','noplugin_indexnow',10,3);
    function noplugin_indexnow($post_id, $post, $update){
    if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
    return;
    }
    if($post->post_status != 'publish'){
    return;
    }
    if (get_post_meta($post_id, 'apipush', true) == "0") {
    return;
    }
    $key = '自己获取KEY';
    $api = 'https://www.bing.com/indexnow';
    $url = get_permalink($post_id);
    wp_remote_post( add_query_arg( ['url'=>$url,'key'=>$key], $api ), [
    'headers' => ['Content-Type'=>'application/json; charset=utf-8'],
    'timeout' => 10,
    'sslverify' => false,
    'blocking' => true,
    'body' => json_encode([
    'host' => parse_url($url)['host'],
    'key' => $key,
    'urlList' => [$url]
    ])
    ]);
    update_post_meta($post_id, "apipush", "0");
    }


    这里我们需要打开 :https://www.bing.com/indexnow/getstarted

    这里我们获取KEY文件然后制作成对应的文件txt,丢到网站根目录后,然后再替换上面的代码 Key 后保存到我们的 Functions.php 中。

    这里无插件可以替换成之前用过的 IndexNow 插件。