1. 项目概述与核心思路

最近实验室新进了一批师弟师妹,安全考试成了他们头疼的第一关。题库几百道,题目还经常更新,手动刷题费时费力。正好手头有个阿里云的AI服务资源,结合Python写个自动化脚本,5分钟搞定安全考试,听起来是不是很酷?这其实就是一次典型的“AI+RPA”(机器人流程自动化)的轻量级应用实战。核心思路很简单:用Python模拟浏览器操作,自动登录考试系统,然后调用阿里云的AI大模型接口来识别题目、搜索答案并自动选择。整个过程完全自动化,解放双手。这个项目不仅实用,更能让你深入理解Python网络请求、AI接口调用和自动化控制的结合,是提升效率的绝佳案例。

适合谁呢?如果你是实验室的学生、科研助理,或者任何需要定期参加类似线上安全、规章考试的朋友,这个脚本能帮你节省大量时间。对于Python初学者,这是一个非常好的综合练习项目,涵盖了requests库、正则表达式、JSON数据处理和API调用等核心技能。当然,前提是你得有考试的合法访问权限,并且仅用于个人学习效率提升,切勿用于任何破坏规则或作弊的行为。

2. 核心工具选型与原理拆解

要实现这个“5分钟脚本”,我们需要几个核心组件:一个能模拟浏览器行为的工具、一个强大的“大脑”来理解题目并找到答案,以及将它们粘合起来的Python代码。下面我们来逐一拆解选型背后的考量。

2.1 浏览器自动化:Selenium vs. Playwright

首先,我们需要一个工具来驱动浏览器,完成点击、输入、获取页面元素等操作。这里有两个主流选择:老牌的Selenium和微软推出的新秀Playwright。

我最终选择了 Playwright 。原因有几个:第一,Playwright对现代Web应用(尤其是大量使用JavaScript动态加载内容的单页应用)的支持更好,速度更快。实验室的考试系统很可能就是这种。第二,它的API设计更现代、更简洁,同步和异步操作都支持得很好。第三,它内置了等待机制,能智能地等待元素加载完成,减少了我们写复杂等待逻辑的麻烦。相比之下,Selenium虽然生态庞大,但在处理动态页面时有时需要更多“补丁”代码。

安装Playwright非常简单: pip install playwright ,然后运行 playwright install 来下载它自带的浏览器(Chromium, Firefox, WebKit)。我们主要使用Chromium,因为它最通用。

2.2 AI大脑:为什么是阿里云通义千问?

接下来是最关键的部分——AI。我们需要一个能理解自然语言题目,并从知识库或上下文中推理出答案的模型。市面上有很多选择,比如OpenAI的GPT系列、国内的各种大模型。我选择 阿里云的通义千问 ,主要基于以下几点实战考量:

  1. 稳定与合规 :对于国内用户,阿里云的API服务访问稳定,无需复杂网络配置,符合内容安全要求。其服务条款对使用场景有明确规范,我们用于教育辅助目的在合理范围内。
  2. 成本与易用性 :新用户通常有免费额度,足够完成多次考试。阿里云的控制台清晰,API密钥(AccessKey)管理方便,文档也比较齐全。
  3. 能力足够 :通义千问在中文理解、推理和问答任务上表现优秀,完全能胜任从题干中提取关键信息并匹配答案的工作。

我们需要在阿里云官网开通“灵积模型服务”,创建一个API-KEY。核心是调用其 qwen-max qwen-plus 模型的对话(Chat)接口。

2.3 粘合剂:Python核心库

Python脚本是大脑和手脚的指挥中心。除了Playwright,我们还需要几个库:

  • requests aiohttp : 用于向阿里云AI接口发送HTTP请求。如果追求更高性能的并发(比如同时处理多道题),可以使用异步的aiohttp。
  • json : 处理API请求和返回的数据。
  • re (正则表达式) : 用于从杂乱的HTML或返回文本中,精准提取题目和选项的纯文本内容。
  • time : 添加适当的延迟,模拟真人操作,避免请求过快被服务器识别为机器人。

整个工作流原理如下:Playwright控制浏览器打开考试页面,定位到题目和选项的HTML元素,用正则表达式清洗出干净的文本。然后将“题目+选项”组合成一个清晰的Prompt,通过requests库发送给阿里云通义千问API。API返回推理出的答案(例如“A”或“C”),脚本再控制Playwright去点击对应的选项按钮,最后提交试卷。

3. 环境准备与关键配置

工欲善其事,必先利其器。在写代码之前,我们需要把环境搭建好,特别是阿里云AI服务的配置,这是整个脚本的“燃料”。

3.1 Python环境与依赖安装

首先确保你安装了Python 3.7或更高版本。建议使用虚拟环境来管理依赖,避免包冲突。

# 创建并激活虚拟环境(以venv为例)
python -m venv venv
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate

# 安装核心依赖
pip install playwright
pip install requests # 用于同步调用API,简单稳定
# 如果想尝试异步,可以安装 aiohttp
# pip install aiohttp

# 安装Playwright的浏览器
playwright install chromium

3.2 阿里云AI服务配置详解

这一步是重中之重,很多新手在这里会卡住。

  1. 开通服务 :登录阿里云控制台,在顶部搜索“灵积模型服务”或“DashScope”,进入产品页面。按照指引开通服务。通常新用户会有免费额度。
  2. 获取API-KEY :在控制台,找到“API密钥管理”页面。创建一个新的API密钥(AccessKey)。你会得到 AccessKey Id AccessKey Secret 请像保护密码一样保护它们,千万不要直接硬编码在代码里提交到Git等公共平台。
  3. 理解计费与模型 :在灵积模型服务页,查看模型列表。对于我们的刷题场景, qwen-max (能力最强)或 qwen-plus (性价比高)都是不错的选择。注意查看它们的计价方式,通常按输入和输出的总token数计费。一次简单的问答消耗极少,免费额度完全够用。

我们需要将API-KEY安全地配置到脚本中。最佳实践是使用环境变量。

# 在终端中设置环境变量(临时,重启终端失效)
export DASHSCOPE_API_KEY='你的API-KEY'
# Windows (Command Prompt):
set DASHSCOPE_API_KEY=你的API-KEY
# Windows (PowerShell):
$env:DASHSCOPE_API_KEY='你的API-KEY'

然后在Python代码中这样读取:

import os
api_key = os.environ.get('DASHSCOPE_API_KEY')
if not api_key:
    raise ValueError("请设置环境变量 DASHSCOPE_API_KEY")

3.3 考试页面分析与元素定位

在写自动化脚本前,必须手动操作一遍考试流程,并用浏览器开发者工具(F12)分析页面结构。这是自动化成功的基础。

你需要找到以下关键元素的CSS选择器或XPath:

  • 题目文本 :通常在一个 <div> <p> 标签里,id或class可能包含 question , title , topic 等。
  • 选项列表 :可能是多个 <label> <li> <div> ,里面包含单选按钮 <input type="radio"> 和选项文本。
  • “下一题”按钮 :也可能是“提交”或“确定”按钮。
  • 登录表单 (如果需要):用户名和密码的输入框。

实操技巧 :使用Playwright的 page.locator() 函数,结合Chrome开发者工具中的“检查”功能,右键点击元素选择“Copy” -> “Copy selector”或“Copy XPath”,可以快速获得定位器。但直接复制的选择器可能很脆弱(依赖于动态生成的id或复杂结构),最好自己编写更稳定、简洁的选择器,例如通过部分class名和文本内容组合定位。

注意 :不同学校的考试系统千差万别,没有通用的选择器。这一步需要你耐心分析和调试。一个稳定的选择器是脚本长期可用的关键。

4. 脚本核心代码实现与分步解析

下面我们进入核心环节,一步步构建脚本。我将代码分成几个功能模块,并详细解释每一部分的作用和注意事项。

4.1 初始化与登录模块

首先,初始化Playwright和浏览器,并处理登录(如果考试系统需要独立登录)。

import asyncio
from playwright.async_api import async_playwright
import requests
import json
import re
import os

class LabExamBot:
    def __init__(self, api_key):
        self.api_key = api_key
        self.api_url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        # 初始化Playwright对象和浏览器
        self.playwright = None
        self.browser = None
        self.page = None

    async def init_browser(self, headless=False):
        """初始化浏览器,headless=False表示显示浏览器窗口,方便调试"""
        self.playwright = await async_playwright().start()
        # 使用Chromium,可配置为有头模式便于观察
        self.browser = await self.playwright.chromium.launch(headless=headless)
        self.page = await self.browser.new_page()
        # 设置超时和视口大小
        self.page.set_default_timeout(30000) # 30秒超时
        await self.page.set_viewport_size({"width": 1280, "height": 720})

    async def login(self, login_url, username, password):
        """处理登录流程,需要根据实际考试系统页面调整选择器"""
        await self.page.goto(login_url)
        # 示例选择器,需要替换成实际的
        await self.page.fill('input[name="username"]', username)
        await self.page.fill('input[name="password"]', password)
        await self.page.click('button[type="submit"]')
        # 等待登录成功,跳转到考试页面或出现特定元素
        await self.page.wait_for_selector('#dashboard', state='visible') # 示例
        print("登录成功")

关键点解析

  • headless=False 在开发阶段非常有用,你能看到浏览器每一步操作,方便调试定位问题。脚本稳定后可以改为 True 在后台运行。
  • set_default_timeout 很重要,避免因为网络或页面加载慢导致脚本无限等待。
  • 登录部分的选择器 input[name="username"] 是相对稳定的写法,比依赖动态id的 #id_xxxx 更好。你需要根据实际页面调整。

4.2 题目抓取与文本清洗

登录后进入考试界面,我们需要抓取题目和选项的纯文本。

    async def get_question_and_options(self):
        """从当前页面提取题目和选项文本"""
        # 假设题目在一个id为`question-text`的div里
        question_element = await self.page.query_selector('#question-text')
        if not question_element:
            # 如果id不稳定,尝试用包含‘题目’文本的标签
            question_element = await self.page.query_selector('div:has-text("题目")')
        
        question_text = await question_element.inner_text() if question_element else ""
        # 清洗文本:去除多余空格、换行符
        question_text = re.sub(r'\s+', ' ', question_text).strip()
        print(f"捕获题目:{question_text[:50]}...") # 打印前50字符便于观察

        # 提取选项,假设每个选项在一个class为`option-item`的label里
        option_elements = await self.page.query_selector_all('.option-item')
        options = []
        option_labels = [] # 用于记录选项字母(A, B, C, D)
        
        for idx, elem in enumerate(option_elements):
            option_text = await elem.inner_text()
            cleaned_text = re.sub(r'\s+', ' ', option_text).strip()
            # 尝试提取选项字母和内容,例如“A. 必须戴防护眼镜”
            match = re.match(r'^([A-D])[\.、]?\s*(.+)', cleaned_text)
            if match:
                label, content = match.groups()
                option_labels.append(label)
                options.append(content)
            else:
                # 如果没有明显字母,用索引生成
                option_labels.append(chr(65 + idx)) # 65是'A'的ASCII码
                options.append(cleaned_text)
        
        print(f"选项:{list(zip(option_labels, options))}")
        return question_text, option_labels, options

实操心得

  • inner_text() text_content() 更能获取用户可见的文本,会自动处理一些隐藏元素。
  • 正则表达式 re.sub(r'\s+', ' ', text) 能将所有空白字符(空格、换行、制表符)替换为单个空格,是清理网页文本的利器。
  • 选项提取的逻辑需要很强的鲁棒性。有的系统用“A.”,有的用“A、”,有的甚至没有前缀。这里写的正则和备选逻辑(按索引生成字母)能覆盖大部分情况。你可能需要根据实际页面微调这个正则表达式。

4.3 构建Prompt与调用AI接口

拿到干净的题目和选项后,我们需要构造一个清晰的Prompt(提示词)给AI模型,让它扮演一个“实验室安全专家”来答题。

    def call_ai_for_answer(self, question, options):
        """调用阿里云通义千问API获取答案"""
        # 构建一个清晰的Prompt
        prompt = f"""你是一位实验室安全专家。请回答以下单选题,只输出选项字母(例如 A, B, C, D),不要输出任何其他解释。

题目:{question}

选项:
"""
        for label, opt in zip(self.current_option_labels, options): # 假设current_option_labels已在上一步赋值
            prompt += f"{label}. {opt}\n"
        
        prompt += "\n请根据你的专业知识,选择最正确的一项。只输出字母。"

        data = {
            "model": "qwen-max", # 或 "qwen-plus"
            "input": {
                "messages": [
                    {"role": "system", "content": "你是一个严谨的实验室安全助手,只根据专业知识回答问题。"},
                    {"role": "user", "content": prompt}
                ]
            },
            "parameters": {
                "result_format": "message", # 返回消息格式
                "temperature": 0.1, # 温度调低,让输出更确定,减少随机性
                "top_p": 0.8
            }
        }
        
        try:
            response = requests.post(self.api_url, headers=self.headers, json=data, timeout=10)
            response.raise_for_status() # 检查HTTP错误
            result = response.json()
            
            # 解析返回结果,不同模型返回结构可能略有差异
            answer_text = result.get("output", {}).get("choices", [{}])[0].get("message", {}).get("content", "").strip()
            # 使用正则从返回文本中提取大写字母
            match = re.search(r'\b([A-D])\b', answer_text.upper())
            if match:
                predicted_answer = match.group(1)
                print(f"AI预测答案:{predicted_answer}")
                return predicted_answer
            else:
                print(f"AI返回内容无法解析为选项:{answer_text}")
                return None
                
        except requests.exceptions.RequestException as e:
            print(f"调用AI API失败:{e}")
            return None
        except (KeyError, IndexError, json.JSONDecodeError) as e:
            print(f"解析AI响应失败:{e}, 响应内容:{response.text[:200]}")
            return None

为什么这样设计Prompt?

  1. 角色设定 “你是一位实验室安全专家” ,让模型进入特定领域语境。
  2. 明确指令 “只输出选项字母” ,这是最重要的,强制模型输出我们脚本能直接处理的格式,避免它长篇大论。
  3. 格式化输入 :将题目和选项清晰列出,便于模型阅读。
  4. 参数调整 temperature=0.1 让模型的输出更集中、更确定,对于有标准答案的题目非常合适。

注意事项

  • API的返回结构一定要仔细查阅阿里云官方文档,不同模型版本可能有细微差别。上述解析路径 result["output"]["choices"][0]["message"]["content"] 是常见格式。
  • 一定要做好异常处理( try...except )。网络请求可能失败,API可能返回错误,模型也可能“不听话”输出了一段话而不是单个字母。我们的正则提取 re.search(r'\b([A-D])\b', ...) 是最后一道防线。

4.4 模拟点击与流程控制

拿到AI返回的答案字母后,我们需要控制浏览器点击对应的选项,并进入下一题。

    async def select_answer_and_continue(self, answer_letter):
        """根据答案字母选择选项,并点击下一题"""
        if not answer_letter:
            print("未获得有效答案,暂时跳过此题")
            # 可以在这里实现一个备选策略,比如随机选一个,或者标记下来手动处理
            # await self.page.click(f'.option-item:nth-child({random.randint(1,4)})')
            await self.page.click('#next-btn') # 假设有跳过或下一题按钮
            return False
        
        # 寻找对应字母的选项进行点击
        # 方法1:如果选项元素有data-value或value属性对应字母
        # await self.page.click(f'input[value="{answer_letter}"]')
        
        # 方法2:更通用的方法,通过文本内容匹配
        # 注意:这里需要能精准定位到可点击的元素(如label或包含radio的div)
        selector = f'.option-item:has-text("^{answer_letter}[\.、]")'
        try:
            await self.page.click(selector)
            print(f"已选择答案:{answer_letter}")
        except Exception as e:
            print(f"点击选项{answer_letter}失败:{e},尝试备用选择器...")
            # 备用方案:通过索引点击
            idx = ord(answer_letter) - 65 # A->0, B->1...
            all_options = await self.page.query_selector_all('.option-item')
            if idx < len(all_options):
                await all_options[idx].click()
            else:
                print("备用方案也失败,无法选择答案。")
        
        # 点击“下一题”或“提交”按钮,需要根据实际页面调整选择器和等待逻辑
        next_btn_selector = '#next-question-btn, button:has-text("下一题"), button:has-text("提交")'
        await self.page.click(next_btn_selector)
        
        # 等待下一题加载或页面状态变化
        # 可以等待题目区域更新,或者一个加载动画消失
        await self.page.wait_for_selector('#question-text', state='visible') # 等待新题目出现
        # 或者简单等待一小段时间
        await self.page.wait_for_timeout(1000) # 等待1秒
        return True

流程控制主循环

    async def run_exam(self, exam_url, total_questions=50):
        """主执行流程"""
        await self.page.goto(exam_url)
        print(f"开始处理考试,预计{total_questions}题")
        
        for q_num in range(1, total_questions + 1):
            print(f"\n--- 正在处理第 {q_num} 题 ---")
            
            # 1. 获取题目和选项
            question_text, option_labels, options = await self.get_question_and_options()
            self.current_option_labels = option_labels # 存储给AI调用用
            
            # 2. 调用AI获取答案
            answer = self.call_ai_for_answer(question_text, options)
            
            # 3. 选择答案并进入下一题
            success = await self.select_answer_and_continue(answer)
            
            if not success and q_num < total_questions:
                # 如果本题失败,但还有题,等待稍长时间后继续
                await self.page.wait_for_timeout(2000)
            
            # 4. 控制速度,避免请求过快
            await asyncio.sleep(1) # 每题之间间隔1秒,更拟人
            
        print("所有题目处理完毕!")
        # 最后可能需要处理交卷
        # await self.page.click('#submit-paper-btn')

核心技巧

  • wait_for_selector wait_for_timeout 结合使用,前者用于等待特定元素出现(更精确),后者用于固定等待(更简单但可能低效)。
  • 在主循环中增加 await asyncio.sleep(1) 是非常重要的一步,这模拟了人的阅读和思考时间,能显著降低被反爬机制检测到的风险。
  • 对于点击失败的情况,设计了备用选择器(按索引点击),增强了脚本的容错能力。

5. 完整代码整合与使用指南

将上述所有模块整合,并添加一些必要的配置和主函数入口,就得到了完整的脚本。以下是整合后的核心框架和调用示例。

# lab_exam_bot.py
import asyncio
import re
import os
import requests
from playwright.async_api import async_playwright

class LabExamBot:
    # ... 此处整合上述所有方法 __init__, init_browser, login, get_question_and_options, call_ai_for_answer, select_answer_and_continue, run_exam ...
    
    async def close(self):
        """关闭浏览器和Playwright"""
        if self.browser:
            await self.browser.close()
        if self.playwright:
            await self.playwright.stop()

async def main():
    # 1. 从环境变量获取API Key
    api_key = os.environ.get("DASHSCOPE_API_KEY")
    if not api_key:
        print("错误:请设置环境变量 DASHSCOPE_API_KEY")
        return
    
    # 2. 创建机器人实例
    bot = LabExamBot(api_key)
    
    # 3. 初始化浏览器(开发阶段建议headless=False)
    await bot.init_browser(headless=False)
    
    try:
        # 4. 登录(如果考试系统需要独立登录)
        login_url = "https://your-lab-exam-system.com/login"
        username = "your_student_id"
        password = "your_password"
        # await bot.login(login_url, username, password)
        
        # 5. 开始刷题
        exam_url = "https://your-lab-exam-system.com/exam/123"
        total_questions = 50 # 根据实际考试题目数量修改
        await bot.run_exam(exam_url, total_questions)
        
    except Exception as e:
        print(f"程序运行出错:{e}")
    finally:
        # 6. 关闭资源
        await bot.close()

if __name__ == "__main__":
    asyncio.run(main())

使用步骤指南

  1. 环境准备 :按照第3部分安装Python、依赖和浏览器。
  2. 配置API-KEY :在阿里云开通服务并获取Key,设置为环境变量 DASHSCOPE_API_KEY
  3. 修改脚本配置
    • exam_url 替换为你实际考试页面的URL。
    • 修改 total_questions 为考试总题数。
    • 如果考试系统有独立登录页,取消注释 login 相关代码,并修改 login_url username password 以及 login 方法内的选择器。
    • 根据你的考试页面HTML结构,仔细调整 get_question_and_options select_answer_and_continue 方法中的所有CSS选择器(如 #question-text , .option-item 等)。这是脚本能否运行的关键。
  4. 测试运行 :首次运行务必在 headless=False 模式下,观察浏览器每一步操作是否如预期。可以先将 total_questions 设为1或2进行测试。
  5. 正式运行 :测试无误后,可将 headless 设为 True ,让脚本在后台安静运行。

6. 常见问题排查与优化技巧

在实际操作中,你几乎一定会遇到各种问题。下面是我在开发和测试中踩过的坑以及解决方案。

6.1 元素定位失败

这是最常见的问题,浏览器打开了,但脚本找不到题目或按钮。

  • 症状 TimeoutError: Timeout 30000ms exceeded. Error: No element found for selector: ...
  • 排查
    1. 确认页面加载完成 :在 page.goto() 后增加 await page.wait_for_load_state('networkidle') ,等待网络基本空闲。
    2. 检查选择器 :使用 headless=False 模式,在浏览器中打开开发者工具(F12),在Console里输入 document.querySelector('你的选择器') 看是否能找到元素。Playwright也支持在代码中截图 await page.screenshot(path='debug.png') 帮助查看页面状态。
    3. 处理iframe :如果考试内容嵌在 <iframe> 里,你需要先定位到iframe,再在iframe的上下文中查找元素。
      frame = page.frame(name='content-frame') # 通过name或selector
      # 或者 page.frames 列表
      question = await frame.query_selector('#question')
      
    4. 动态内容 :如果题目是AJAX加载的,可能需要等待特定元素出现。使用 await page.wait_for_selector('#question', state='visible') 而不仅仅是 query_selector

6.2 AI返回答案格式错误或不准

  • 症状 :AI返回了一整段话,或者答案明显错误。
  • 排查与优化
    1. 强化Prompt :在Prompt中更严厉地强调输出格式。例如:“你必须且只能输出一个大写字母,代表你认为正确的选项。不要输出任何其他字符、标点或解释。”
    2. 提供上下文 :如果题库是固定的,可以在Prompt开头加入少量背景知识,例如“以下是关于《高校实验室安全手册》的考试题目...”。
    3. 后处理校验 :在解析AI返回后,检查提取到的字母是否在预期的选项范围内(如[‘A’, ‘B’, ‘C’, ‘D’]),如果不是,可以记录该题并采用默认策略(如选C或跳过)。
    4. 模型调参 :尝试将 temperature 降得更低(如0.01),并设置 top_p=0.1 ,让模型输出更保守、更确定。也可以换用不同的模型试试(如 qwen-turbo 速度更快)。
    5. 人工复核 :对于非常重要的考试,可以设置脚本将AI不确定(例如返回的置信度低)或解析失败的题目记录下来,最后人工处理。

6.3 被反爬机制拦截

  • 症状 :脚本运行几题后页面卡住、跳出验证码、或直接提示异常。
  • 应对策略
    1. 降低速度 :这是最有效的方法。在每步操作间增加随机延迟, await page.wait_for_timeout(random.randint(1000, 3000)) ,模拟真人操作的不规律性。
    2. 模拟人类行为 :Playwright可以模拟鼠标移动、随机轨迹。虽然我们的场景不一定需要,但更复杂的系统可能需要。
      await page.mouse.move(x, y) # 移动到某个坐标
      
    3. 使用真实浏览器上下文 :Playwright可以复用已有的Chrome用户数据目录,让浏览器看起来更像一个常驻的真实用户会话。
      context = await browser.launch_persistent_context(user_data_dir='./user_data')
      page = await context.new_page()
      
    4. 处理验证码 :如果出现简单验证码,可以考虑集成OCR库(如 ddddocr pytesseract )进行识别。但复杂验证码通常意味着你需要重新评估自动化方案的可行性。

6.4 脚本稳定性优化

  • 增加重试机制 :对于网络请求或AI调用失败,可以加入重试逻辑。
    import time
    max_retries = 3
    for attempt in range(max_retries):
        try:
            answer = self.call_ai_for_answer(question, options)
            if answer:
                break
        except Exception as e:
            print(f"第{attempt+1}次尝试失败:{e}")
            time.sleep(2)
    
  • 详细日志 :将关键步骤(如捕获的题目、AI返回的原始文本、最终选择的答案)记录到文件,方便出错后回溯分析。
  • 断点续做 :对于题量很大的考试,可以考虑记录已完成的题号到文件。如果脚本中途崩溃,重启后可以从断点继续,避免重头再来。

这个项目从构思到实现,最深的体会就是“魔鬼在细节中”。一个看似简单的自动化想法,落地时需要仔细处理网页结构的细微差别、API调用的各种异常、以及模拟人类操作的真实感。它不仅仅是一个“偷懒”的工具,更是一个综合性的Python工程实践。当你看到浏览器自动一题题翻页、选择,最终提交成功时,那种效率提升的成就感是非常实在的。最后提醒一句,技术是用来提升学习和工作效率的,请务必在合规和道德的前提下使用它。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐