自动网页浏览助手:基于 Selenium + GLM-4V 的百度自动搜索与内容提取系统

智能网页浏览助手:基于 Selenium + GLM-4V 的百度自动搜索与内容提取系统

项目目标:构建一个能自主完成"打开百度 → 随机搜索 → 点击结果 → 提取内容"全流程的 AI 系统,全程无需硬编码元素定位器,完全依赖 GLM-4V 多模态理解能力。


1. 项目文件结构

bash 复制代码
baidu-ai-browser/
├── config/
│   └── settings.py          # 配置文件
├── core/
│   ├── browser.py           # Selenium 浏览器控制
│   ├── vision.py            # GLM-4V 视觉理解
│   └── content_extractor.py # 内容提取逻辑
├── utils/
│   ├── image_utils.py       # 图像处理工具
│   └── logger.py            # 日志记录
├── outputs/                 # 输出目录(自动生成)
│   ├── search_results.txt   # 搜索结果摘要
│   └── page_contents/       # 各网页内容
├── main.py                  # 主程序入口
├── requirements.txt         # 依赖列表
└── README.md                # 部署说明

2. 依赖安装(requirements.txt)

txt 复制代码
selenium==4.18.1
opencv-python==4.8.1.78
Pillow==10.2.0
requests==2.31.0
python-dotenv==1.0.1

3. 核心代码实现

3.1 配置文件(config/settings.py)

python 复制代码
import os
from dotenv import load_dotenv

load_dotenv()

class Settings:
    # GLM API 配置
    ZHIPU_API_KEY = os.getenv("ZHIPU_API_KEY")
    GLM_MODEL = "glm-4v"
    
    # 浏览器配置
    HEADLESS = False  # 调试时设为 False
    WINDOW_WIDTH = 1920
    WINDOW_HEIGHT = 1080
    
    # 搜索关键词池
    KEYWORDS = [
        "人工智能最新进展", "Python自动化教程", "大模型应用案例",
        "气候变化解决方案", "量子计算突破", "新能源汽车技术"
    ]
    
    # 输出路径
    OUTPUT_DIR = "outputs"
    CONTENT_DIR = os.path.join(OUTPUT_DIR, "page_contents")
    
    # 超时设置
    PAGE_LOAD_TIMEOUT = 10
    GLM_TIMEOUT = 30

settings = Settings()

3.2 浏览器控制模块(core/browser.py)

python 复制代码
import time
import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from config.settings import settings
from utils.logger import logger

class SmartBrowser:
    def __init__(self):
        self.driver = self._init_driver()
        self.wait = WebDriverWait(self.driver, settings.PAGE_LOAD_TIMEOUT)
        
    def _init_driver(self):
        options = Options()
        if settings.HEADLESS:
            options.add_argument("--headless")
        options.add_argument(f"--window-size={settings.WINDOW_WIDTH},{settings.WINDOW_HEIGHT}")
        options.add_argument("--disable-gpu")
        options.add_argument("--no-sandbox")
        options.add_argument("--disable-dev-shm-usage")
        return webdriver.Chrome(options=options)
    
    def capture_fullpage_screenshot(self):
        """捕获完整页面截图并返回缩放比例"""
        # 获取实际页面尺寸
        total_width = self.driver.execute_script("return Math.max(document.body.scrollWidth, document.documentElement.scrollWidth);")
        total_height = self.driver.execute_script("return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);")
        
        # 设置窗口大小
        self.driver.set_window_size(total_width, total_height)
        screenshot = self.driver.get_screenshot_as_png()
        
        # 计算缩放比例
        from PIL import Image
        import io
        img = Image.open(io.BytesIO(screenshot))
        scale_x = img.width / total_width
        scale_y = img.height / total_height
        
        return img, scale_x, scale_y
    
    def smart_click(self, x: int, y: int, scale_x: float, scale_y: float):
        """根据图片坐标执行点击"""
        web_x = int(x / scale_x)
        web_y = int(y / scale_y)
        self.driver.execute_script(f"document.elementFromPoint({web_x}, {web_y}).click();")
        time.sleep(2)  # 等待页面响应
    
    def get_page_text(self):
        """获取当前页面纯文本内容"""
        return self.driver.find_element(By.TAG_NAME, "body").text
    
    def quit(self):
        self.driver.quit()

3.3 视觉理解模块(core/vision.py)

python 复制代码
import base64
import io
import requests
import json
import re
from config.settings import settings
from utils.logger import logger

class GLMVision:
    def __init__(self):
        self.api_url = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
        self.headers = {
            "Authorization": f"Bearer {settings.ZHIPU_API_KEY}",
            "Content-Type": "application/json"
        }
    
    def analyze_image(self, image, prompt: str) -> str:
        """调用GLM-4V分析图像"""
        # 转换为base64
        buffered = io.BytesIO()
        image.save(buffered, format="PNG")
        img_str = base64.b64encode(buffered.getvalue()).decode()
        
        payload = {
            "model": settings.GLM_MODEL,
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": prompt},
                        {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_str}"}}
                    ]
                }
            ],
            "temperature": 0.1  # 降低随机性
        }
        
        try:
            response = requests.post(
                self.api_url, 
                headers=self.headers, 
                json=payload, 
                timeout=settings.GLM_TIMEOUT
            )
            response.raise_for_status()
            result = response.json()
            return result["choices"][0]["message"]["content"]
        except Exception as e:
            logger.error(f"GLM API 调用失败: {str(e)}")
            raise
    
    def extract_coordinates(self, response: str):
        """从响应中提取坐标"""
        # 匹配多种坐标格式
        patterns = [
            r'\(?(\d+)[,\s]+(\d+)\)?',
            r'x[=:\s]*(\d+).*?y[=:\s]*(\d+)',
            r'坐标.*?(\d+).*?(\d+)'
        ]
        
        for pattern in patterns:
            match = re.search(pattern, response, re.IGNORECASE)
            if match:
                return int(match.group(1)), int(match.group(2))
        return None
    
    def find_search_box(self, image):
        """定位百度搜索框"""
        prompt = """
        你是一个网页自动化专家,请精确识别百度首页搜索框的中心坐标。
        要求:
        1. 忽略广告和无关元素
        2. 返回整数坐标(x, y)
        3. 坐标基于图片左上角(0,0)
        4. 只返回坐标,不要其他文字
        """
        response = self.analyze_image(image, prompt)
        return self.extract_coordinates(response)
    
    def find_search_button(self, image):
        """定位百度搜索按钮"""
        prompt = """
        请找出百度搜索按钮(通常标有"百度一下")的中心坐标。
        返回格式:(x, y)
        """
        response = self.analyze_image(image, prompt)
        return self.extract_coordinates(response)
    
    def find_search_results(self, image):
        """识别前3个搜索结果的坐标"""
        prompt = """
        请识别搜索结果页面中前3个自然搜索结果(非广告)的标题区域中心坐标。
        按顺序返回3组坐标,格式:
        1. (x1, y1)
        2. (x2, y2)
        3. (x3, y3)
        """
        response = self.analyze_image(image, prompt)
        coords = []
        for line in response.split('\n'):
            coord = self.extract_coordinates(line)
            if coord:
                coords.append(coord)
                if len(coords) == 3:
                    break
        return coords[:3]

3.4 内容提取模块(core/content_extractor.py)

python 复制代码
import os
import re
from config.settings import settings
from utils.logger import logger

class ContentExtractor:
    def __init__(self):
        os.makedirs(settings.CONTENT_DIR, exist_ok=True)
    
    def extract_valuable_content(self, text: str, url: str) -> str:
        """提取有价值的内容(简化版)"""
        # 移除无用内容
        cleaned = re.sub(r'\s+', ' ', text)  # 合并空白字符
        cleaned = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9.,!?;:()\[\]{}\-_]', ' ', cleaned)
        
        # 保留有意义的段落(长度>50字符)
        sentences = [s.strip() for s in cleaned.split('。') if len(s.strip()) > 50]
        
        # 取前10句作为摘要
        summary = '。'.join(sentences[:10]) + '。' if sentences else cleaned[:500]
        
        return f"URL: {url}\n\n{summary}"
    
    def save_content(self, content: str, filename: str):
        """保存内容到文件"""
        filepath = os.path.join(settings.CONTENT_DIR, filename)
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(content)
        logger.info(f"内容已保存: {filepath}")

3.5 图像工具(utils/image_utils.py)

python 复制代码
from PIL import Image
import io

def resize_image_for_glm(image, max_width=768):
    """调整图片尺寸以优化GLM调用成本"""
    if image.width > max_width:
        ratio = max_width / image.width
        new_height = int(image.height * ratio)
        return image.resize((max_width, new_height), Image.LANCZOS)
    return image

3.6 日志工具(utils/logger.py)

python 复制代码
import logging
import os

# 创建日志目录
os.makedirs('logs', exist_ok=True)

logger = logging.getLogger('BaiduAIBrowser')
logger.setLevel(logging.INFO)

# 文件处理器
file_handler = logging.FileHandler('logs/app.log', encoding='utf-8')
file_handler.setLevel(logging.INFO)

# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

# 格式化器
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

logger.addHandler(file_handler)
logger.addHandler(console_handler)

3.7 主程序(main.py

python 复制代码
import random
import time
import os
from config.settings import settings
from core.browser import SmartBrowser
from core.vision import GLMVision
from core.content_extractor import ContentExtractor
from utils.image_utils import resize_image_for_glm
from utils.logger import logger

def main():
    # 初始化组件
    browser = SmartBrowser()
    vision = GLMVision()
    extractor = ContentExtractor()
    
    try:
        # 1. 打开百度
        logger.info("正在打开百度...")
        browser.driver.get("https://www.baidu.com")
        time.sleep(2)
        
        # 2. 随机选择关键词
        keyword = random.choice(settings.KEYWORDS)
        logger.info(f"随机选择关键词: {keyword}")
        
        # 3. 定位搜索框并输入关键词
        img, sx, sy = browser.capture_fullpage_screenshot()
        img_resized = resize_image_for_glm(img)
        
        search_box_coords = vision.find_search_box(img_resized)
        if not search_box_coords:
            raise Exception("未找到搜索框")
        
        # 点击搜索框
        browser.smart_click(search_box_coords[0], search_box_coords[1], sx, sy)
        
        # 输入关键词
        browser.driver.switch_to.active_element.send_keys(keyword)
        time.sleep(1)
        
        # 4. 点击搜索按钮
        img2, sx2, sy2 = browser.capture_fullpage_screenshot()
        img2_resized = resize_image_for_glm(img2)
        
        search_btn_coords = vision.find_search_button(img2_resized)
        if not search_btn_coords:
            raise Exception("未找到搜索按钮")
        
        browser.smart_click(search_btn_coords[0], search_btn_coords[1], sx2, sy2)
        logger.info("已执行搜索")
        time.sleep(3)
        
        # 5. 获取搜索结果坐标
        img3, sx3, sy3 = browser.capture_fullpage_screenshot()
        img3_resized = resize_image_for_glm(img3)
        
        result_coords = vision.find_search_results(img3_resized)
        if len(result_coords) < 3:
            logger.warning(f"只找到 {len(result_coords)} 个结果,继续处理...")
        
        # 6. 依次点击并保存内容
        results_summary = f"搜索关键词: {keyword}\n\n"
        
        for i, coords in enumerate(result_coords[:3], 1):
            logger.info(f"正在处理第 {i} 个搜索结果...")
            
            # 点击结果
            browser.smart_click(coords[0], coords[1], sx3, sy3)
            time.sleep(3)
            
            # 获取页面内容
            current_url = browser.driver.current_url
            page_text = browser.get_page_text()
            
            # 提取有价值内容
            valuable_content = extractor.extract_valuable_content(page_text, current_url)
            
            # 保存到文件
            filename = f"result_{i}_{keyword.replace(' ', '_')}.txt"
            extractor.save_content(valuable_content, filename)
            
            # 添加到摘要
            results_summary += f"结果 {i}: {current_url}\n"
            results_summary += f"摘要: {valuable_content.split('URL:')[0][:200]}...\n\n"
            
            # 返回搜索结果页
            browser.driver.back()
            time.sleep(2)
            # 重新获取截图(页面可能变化)
            img3, sx3, sy3 = browser.capture_fullpage_screenshot()
            img3_resized = resize_image_for_glm(img3)
        
        # 7. 保存搜索结果摘要
        with open(os.path.join(settings.OUTPUT_DIR, "search_results.txt"), 'w', encoding='utf-8') as f:
            f.write(results_summary)
        logger.info("搜索结果摘要已保存")
        
    except Exception as e:
        logger.error(f"执行过程中出错: {str(e)}")
        raise
    finally:
        browser.quit()
        logger.info("浏览器已关闭")

if __name__ == "__main__":
    # 创建输出目录
    os.makedirs(settings.OUTPUT_DIR, exist_ok=True)
    main()

4. 部署说明(README.md

环境要求

  • Python 3.8+
  • Chrome 浏览器(版本 ≥ 115)
  • ChromeDriver(与 Chrome 版本匹配)

安装步骤

bash 复制代码
# 1. 克隆项目
git clone https://github.com/yourname/baidu-ai-browser.git
cd baidu-ai-browser

# 2. 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Linux/Mac
# venv\Scripts\activate  # Windows

# 3. 安装依赖
pip install -r requirements.txt

# 4. 配置API密钥
echo "ZHIPU_API_KEY=your_zhipu_api_key_here" > .env

# 5. 下载ChromeDriver
# 访问 https://chromedriver.chromium.org/ 下载对应版本
# 将 chromedriver 放入系统PATH或项目根目录

运行项目

bash 复制代码
python main.py

输出说明

  • outputs/search_results.txt:搜索结果摘要
  • outputs/page_contents/:各网页详细内容
  • logs/app.log:执行日志

注意事项

  1. API 成本:每次运行约调用 5-6 次 GLM-4V(约 0.1-0.15 元)
  2. 网络要求:需能访问百度和智谱AI API
  3. 反爬策略:百度可能触发验证码,建议降低运行频率
  4. 调试模式 :将 config/settings.py 中的 HEADLESS = False 可查看浏览器操作过程

5. 效果示例

search_results.txt 内容:

复制代码
搜索关键词: 人工智能最新进展

结果 1: https://www.example-ai-news.com/latest-ai-breakthroughs
摘要: 2024年人工智能领域迎来重大突破,多模态大模型在医疗诊断准确率提升至95%...

结果 2: https://tech.sina.com.cn/ai/2024-06-15/doc-ai_news
摘要: 中国科学家发布新型AI芯片,能效比提升10倍,专为大模型推理优化...

结果 3: https://www.zhihu.com/question/ai-progress-2024
摘要: 人工智能最新进展包括:1. 开源模型质量接近闭源 2. Agent技术实用化...

6. 扩展建议

  1. 增加重试机制:对 GLM 识别失败的情况自动重试
  2. 内容质量评分:用 GLM 对提取内容进行相关性打分
  3. 多语言支持:自动检测页面语言并调整提示词
  4. 分布式执行:使用 Celery 实现多任务并行处理

项目地址github.com/wyg5208/baidu-ai-browser
免责声明:本项目仅用于技术学习,请遵守百度 robots.txt 及相关法律法规。


通过这个项目,你将掌握 多模态大模型 + Web 自动化 的前沿技术组合,为构建更复杂的智能代理系统打下坚实基础!

相关推荐
云澈ovo2 小时前
AI算力加速的硬件选型指南:GPU/TPU/FPGA在创意工作流中的性能对比
人工智能·fpga开发
山烛3 小时前
计算机视觉:人脸关键点定位与轮廓绘制
人工智能·opencv·计算机视觉·dlib·人脸关键点定位·人脸轮廓绘制
爱读源码的大都督3 小时前
Spring AI Alibaba JManus底层实现剖析
java·人工智能·后端
且慢.5893 小时前
机器学习/深度学习名词理解
人工智能·深度学习·机器学习
☆cwlulu3 小时前
解码Android 系统蓝牙音频全流程
前端·人工智能·算法
嘀咕博客3 小时前
GPTEngineer:AI 驱动的Web应用开发平台
前端·人工智能·ai工具
SkyXZ~3 小时前
AWS SageMaker SDK 完整教程:从零开始云端训练你的模型
人工智能·深度学习·云计算·aws·sagemaker·boto3
黎燃3 小时前
RAG 技术合集:检索增强生成的实践指南
人工智能
nju_spy3 小时前
南京大学 LLM开发基础(二)大语言模型解析 -- 基于HF LlaMA实现的讲解
人工智能·pytorch·深度学习·大模型·多头注意力·rmsnorm·位置掩码