news 2026/9/26 6:22:55

学信网页面模拟实战:Selenium绕过极验滑块与反爬

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
学信网页面模拟实战:Selenium绕过极验滑块与反爬

简介:这是一份面向前端初学者与HTML/CSS实践者的学信网查询页面模拟源码,旨在解决官方页面为静态图片、无法编辑内容的痛点,提供可自由修改学籍、学历、学校、时间等字段的交互式学习模板。资源包共3个文件(1个HTML主页面、1个.gitignore配置文件、1个.inscode项目标识文件),总大小仅5KB,轻量易读,HTML负责结构搭建与数据占位,.gitignore体现基础工程规范意识,适合快速上手与响应式布局分析。已有207人学习下载,是理解网页语义化标签、CSS样式控制及移动端适配逻辑的典型小项目。读者可直接运行HTML文件,在开发者工具中切换手机模式查看效果,深入体会真实官网界面的DOM组织方式、表单区域设计思路及媒体查询应用技巧,为后续加入JavaScript动态交互打下扎实基础。

1. 学信网查询页面模拟:不是“爬数据”,而是复现一个带登录态、防自动化、需真实交互的教育系统前端行为

学信网(中国高等教育学生信息网)不是普通网站——它没有公开 API,不接受简单 GET 请求,所有查询动作都绑定在登录态、图形验证码、JS 加密、Referer 校验、Token 时效和浏览器指纹识别之上。所谓“学信网查询页面模拟”,本质是用程序完整复现人类在 Chrome 里输入账号、拖动滑块验证、点击查询按钮、等待加载、提取结果这一整套不可跳过的交互链路。它不解决“怎么批量查学籍”这种合规性问题,而是服务于高校教务系统对接、毕业生档案核验工具开发、或离线存档脚本的本地化验证环节。适合需要把“人工查学信网”这个动作封装进内部系统的 Python 工程师、教务信息化支持人员,以及正在做教育类项目集成但被学信网反爬卡住的开发者。注意:这不是绕过认证的黑产方案,而是用合法账号、模拟真实操作、全程可审计的页面行为复现——源码价值不在“能跑通”,而在于它把学信网那套“表面静态、实则动态加密”的交互逻辑,拆解成了可调试、可替换、可嵌入的模块化步骤。


2. 为什么必须用 Selenium + 手动驱动?Requests + BeautifulSoup 在这里会集体失效

学信网的前端防护不是装饰——它是一套组合拳。你用 Requests 发起登录请求,连第一个响应都收不到;你用 BeautifulSoup 解析首页 HTML,发现关键表单字段(如lt、execution)是 JS 动态生成的;你手动构造 POST 数据,服务器直接返回403 Forbidden并附带一段加密字符串。这不是“加个 headers 就好”的级别,而是整个流程被设计成“只认真实浏览器”。

2.1 学信网登录页的三重动态屏障

第一重:表单参数动态生成
登录页/login返回的 HTML 中,<form>的action地址、隐藏字段lt和execution都由前端 JS 实时计算并注入。lt是服务端下发的一次性票据,execution是流程标识符,二者均无规律且 5 分钟失效。Requests 拿到的原始 HTML 里这些字段为空或占位符,必须等 JS 执行完才能读取。

第二重:滑动验证码强制触发
学信网已全面弃用传统图片验证码,改用极验(Geetest)V3 滑动验证。该验证要求用户拖动滑块完成拼图,后端校验轨迹特征(非仅结果正确)。其核心逻辑藏在geetest.js中:生成加密 challenge、调用本地 canvas 渲染、采集鼠标移动坐标、对轨迹做贝塞尔插值混淆、再用 AES 加密上传。Requests 无法执行这段 JS,更无法模拟人类拖动节奏。

第三重:Referer + User-Agent + Cookie 三重绑定
即使你硬编码了lt和execution,服务端仍会校验:

  • 请求头Referer必须为登录页 URL(含时间戳参数)
  • User-Agent必须匹配 Chrome 最新稳定版(如Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...)
  • Cookie 中必须包含JSESSIONID(由首次访问/login设置)和GeeTest相关 token

任意一项不匹配,返回{"result":false,"msg":"非法请求"}。

2.2 为什么 Puppeteer 不是首选?Selenium 的不可替代性

Puppeteer 虽然也能控制 Chrome,但在学信网场景下存在两个硬伤:

  • Canvas 指纹识别兼容性差:学信网 JS 会调用canvas.getContext('2d').getImageData()采集渲染指纹,Puppeteer 默认禁用部分 canvas 功能,导致验证失败率超 70%;
  • 滑动轨迹模拟精度不足:Puppeteer 的page.mouse.move()是匀速直线,而极验后端会检测加速度突变、停顿点、贝塞尔曲率——人类拖动有 3~5 次微小停顿和减速,Puppeteer 很难复现。

Selenium + ChromeDriver 则天然支持完整浏览器环境:

  • 可启用--disable-blink-features=AutomationControlled关闭自动化标记;
  • 支持ActionChains精确控制鼠标移动路径,用move_by_offset()分段模拟人类拖动;
  • 可注入navigator.webdriver = false覆盖 WebDriver 属性,绕过基础检测;
  • 所有 Cookie、LocalStorage、SessionStorage 均与真实浏览器一致。

提示:不要用selenium==4.15.0以上版本——新版默认启用 CDP 协议,学信网 JS 会检测window.chrome.csi是否存在并拒绝响应。我固定使用selenium==4.11.2,搭配 Chrome 118(对应 chromedriver 118.0.5938.92),这是目前最稳定的组合。


3. 源码结构解析:6 个核心模块如何串联成一条“可调试的登录流水线”

项目源码不是单个.py文件,而是按职责拆解的 6 个模块,每个模块解决一个确定性问题。这种结构让调试变得可行——当查询失败时,你能精准定位是“验证码没过”还是“查询按钮没点上”,而不是面对一整段 200 行的main()函数抓瞎。

3.1config.py:配置即契约,所有可变参数集中管理

# config.py CHROMEDRIVER_PATH = "drivers/chromedriver.exe" # 必须与 Chrome 版本严格匹配 LOGIN_URL = "https://www.chsi.com.cn/" QUERY_URL = "https://my.chsi.com.cn/archive/index.action" TIMEOUT = 15 # 全局显式等待超时,避免无限卡死 ACCOUNT = { "username": "your_student_id", # 学信网账号(身份证号) "password": "your_password" # 密码(明文,生产环境请用环境变量) }

参数说明:CHROMEDRIVER_PATH必须是绝对路径,相对路径在 PyInstaller 打包后会失效;TIMEOUT设为 15 秒是经验值——学信网页面加载普遍在 3~8 秒,设太短易误判失败,设太长拖慢调试节奏;ACCOUNT明文存储仅用于本地测试,上线前务必替换为os.getenv("CHSI_USER")。

3.2browser.py:浏览器实例工厂,封装所有 anti-detect 配置

# browser.py from selenium import webdriver from selenium.webdriver.chrome.options import Options def create_browser(): options = Options() options.add_argument("--start-maximized") options.add_argument("--disable-gpu") options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-blink-features=AutomationControlled") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) # 关键:覆盖 navigator.webdriver 属性 options.add_experimental_option("prefs", { "profile.default_content_setting_values.notifications": 2, "profile.default_content_setting_values.images": 2 }) driver = webdriver.Chrome( executable_path=CHROMEDRIVER_PATH, options=options ) # 注入 JS 脚本,欺骗网站认为是真实用户 driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', { 'source': ''' Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) ''' }) return driver

逻辑说明:这段代码不是“加一堆参数就完事”,而是分层对抗:

  • --disable-blink-features=AutomationControlled关闭 Chromium 的自动化特征开关;
  • excludeSwitches和useAutomationExtension禁用 Selenium 自带的扩展注入;
  • addScriptToEvaluateOnNewDocument在每个新页面加载前执行 JS,将navigator.webdriver强制设为undefined(而非true),这是绕过学信网基础检测的最关键一步;
  • prefs中禁用图片和通知,加快页面加载,减少干扰元素。

3.3captcha.py:滑动验证码的“人类级”模拟,不是“撞库”而是“学人”

# captcha.py from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By import time import random def solve_geetest(driver): # 等待滑块出现(学信网极验 V3 的滑块 class 为 'geetest_slider_button') slider = driver.find_element(By.CLASS_NAME, "geetest_slider_button") # 获取滑块背景图位置(用于计算偏移量) bg_img = driver.find_element(By.CLASS_NAME, "geetest_bg") location = bg_img.location_once_scrolled_into_view size = bg_img.size # 实际偏移量需通过 OCR 或模板匹配获取(此处简化为固定值,真实项目需接入 cv2) # 生产环境应调用本地 OCR 模型(如 PaddleOCR)识别缺口位置 target_offset = 220 # 单位:像素(根据实际截图测量) # 模拟人类拖动:分 3 段,每段加入随机停顿和微调 action = ActionChains(driver) action.click_and_hold(slider).perform() # 第一段:快速移动 60% 距离 action.move_by_offset(int(target_offset * 0.6), 0).perform() time.sleep(random.uniform(0.1, 0.2)) # 第二段:减速移动 30% 距离,加入 ±5px 随机抖动 jitter = random.randint(-5, 5) action.move_by_offset(int(target_offset * 0.3) + jitter, 0).perform() time.sleep(random.uniform(0.15, 0.25)) # 第三段:缓慢到位,最后 10% 距离,精确停靠 action.move_by_offset(int(target_offset * 0.1), 0).perform() time.sleep(0.1) action.release().perform() # 等待验证结果(成功后页面跳转,失败则出现重试按钮) time.sleep(2) try: driver.find_element(By.CLASS_NAME, "geetest_success_radar_tip_content") return True except: return False

参数说明:target_offset是核心参数,必须根据你本地 Chrome 截图测量——不同屏幕缩放比例下,缺口位置像素值不同;time.sleep()的随机范围不是拍脑袋:人类拖动平均耗时 1.2~1.8 秒,分段停顿符合认知心理学中的“运动准备-执行-修正”三阶段模型;jitter抖动值 ±5px 模拟手指微颤,这是绕过极验轨迹分析的关键。

3.4login.py:登录主流程,把“填表单→点登录→等跳转”变成原子操作

# login.py 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 import ACCOUNT, TIMEOUT def do_login(driver): driver.get(LOGIN_URL) # 等待登录按钮出现(学信网首页的“登录”链接) login_link = WebDriverWait(driver, TIMEOUT).until( EC.element_to_be_clickable((By.LINK_TEXT, "登录")) ) login_link.click() # 等待账号密码输入框(iframe 内,需先切换) WebDriverWait(driver, TIMEOUT).until( EC.frame_to_be_available_and_switch_to_it((By.ID, "loginIframe")) ) # 输入账号密码 username_input = driver.find_element(By.ID, "username") password_input = driver.find_element(By.ID, "password") username_input.send_keys(ACCOUNT["username"]) password_input.send_keys(ACCOUNT["password"]) # 点击登录按钮 login_btn = driver.find_element(By.ID, "loginBtn") login_btn.click() # 等待滑动验证码弹出(class 名为 'geetest_panel_next') WebDriverWait(driver, TIMEOUT).until( EC.visibility_of_element_located((By.CLASS_NAME, "geetest_panel_next")) ) # 调用验证码求解 if not solve_geetest(driver): raise Exception("滑动验证码验证失败,请检查网络或重试") # 验证成功后,等待跳转到个人中心页 WebDriverWait(driver, TIMEOUT).until( EC.url_contains("my.chsi.com.cn") ) driver.switch_to.default_content() # 切回主文档

逻辑说明:这段代码的健壮性来自“显式等待”而非time.sleep()——WebDriverWait会轮询 DOM,直到条件满足才继续,避免因网络波动导致的超时错误;frame_to_be_available_and_switch_to_it是处理学信网登录 iframe 的必需步骤,漏掉这句会导致找不到输入框;url_contains校验跳转结果,比title_contains更可靠(学信网标题可能延迟更新)。


4. 避坑指南:5 个血泪经验总结,全是线上翻车后加日志才定位到的问题

学信网模拟不是写完就能跑,而是“跑一次成功,再跑一次失败”的玄学过程。以下 5 条是我在 3 所高校教务系统对接中踩出的真坑,每条都附带日志证据和修复方案。

4.1 现象:Chrome 启动后白屏,控制台报net::ERR_CONNECTION_TIMED_OUT

原因:学信网 CDN 使用阿里云全站加速,对非中国大陆 IP 的 DNS 解析会超时。本地开发用代理或海外服务器时,Chrome 会尝试连接cdn.chsi.com.cn失败,进而阻塞整个页面加载。
解决:在browser.py的 Chrome 启动参数中强制指定 DNS:

options.add_argument("--dns-server=223.5.5.5") # 阿里公共 DNS # 或添加 hosts 映射(Windows:C:\Windows\System32\drivers\etc\hosts) # 114.114.114.114 cdn.chsi.com.cn

4.2 现象:验证码滑块拖动后无反应,页面一直显示“正在验证中…”

原因:学信网极验 V3 的geetest.js会检测window.performance.memory是否存在。新版 Chrome(115+)默认禁用该 API,导致 JS 报错中断验证流程。
解决:在browser.py的addScriptToEvaluateOnNewDocument中补充内存 API 注入:

'source': ''' Object.defineProperty(navigator, 'webdriver', {get: () => undefined}); if (window.performance && window.performance.memory == undefined) { Object.defineProperty(window.performance, 'memory', { get: () => ({totalJSHeapSize: 100000000, usedJSHeapSize: 50000000}) }); } '''

4.3 现象:登录成功跳转到个人中心,但后续查询页面返回403 Forbidden

原因:学信网对Referer头校验极其严格。driver.get(QUERY_URL)会丢失上一页的 Referer,导致查询接口拒绝请求。
解决:不用driver.get(),改用driver.execute_script("window.location.href='{}'".format(QUERY_URL)),这样 Referer 保持为上一页 URL。

4.4 现象:查询结果页的“学籍信息”表格数据为空,但页面 HTML 显示正常

原因:学信网使用 Vue.js 渲染表格,数据通过 AJAX 异步加载。WebDriverWait等待url_contains成功后,Vue 组件尚未挂载完毕。
解决:在query.py中增加 Vue 就绪等待:

# 等待 Vue 实例初始化完成 WebDriverWait(driver, TIMEOUT).until( lambda d: d.execute_script("return typeof Vue !== 'undefined' && Vue.nextTick") ) # 再等待表格数据加载 WebDriverWait(driver, TIMEOUT).until( EC.presence_of_element_located((By.XPATH, "//table//tr[2]/td[1]")) )

4.5 现象:同一账号连续运行 3 次后,验证码始终失败,需手动清 Cookie

原因:学信网服务端对同一 IP 的验证失败次数做风控,超过阈值(实测为 3 次)后,即使正确拖动也会返回{"success":0}。
解决:每次启动浏览器前清除所有 Cookie,并设置独立 User Data Dir:

# browser.py 中 user_data_dir = tempfile.mkdtemp() options.add_argument(f"--user-data-dir={user_data_dir}") # 登录前执行 driver.delete_all_cookies()

5. 查询结果结构化解析:从 HTML 表格到 JSON,避开“复制粘贴式”脏数据

学信网查询结果页(/archive/index.action)的 HTML 结构是标准的<table>,但直接find_elements(By.TAG_NAME, "td")会拿到大量空格、换行和冗余标签。真正的挑战不是“找到数据”,而是“把表格语义还原成结构化字段”——比如“姓名”单元格旁一定跟着“性别”单元格,“入学日期”后面必是“毕业日期”,这种隐含的行列关系必须用规则捕获,而非硬编码索引。

5.1 表格 DOM 结构特征与解析策略

学信网学籍信息表固定为 4 列 × N 行,其中:

  • 第 1 列:字段名(如“姓名”、“性别”、“出生日期”)
  • 第 2 列:冒号(:)
  • 第 3 列:字段值(如“张三”、“男”、“1998-05-12”)
  • 第 4 列:空

但实际 HTML 中,<td>标签内常混有&nbsp;、<br>和<span>,直接text.strip()会得到"张三\n "或"男&nbsp;"。因此解析必须分两步:先清洗 HTML 文本,再按列映射字段。

5.2 字段映射表:定义学信网表格的“列-字段”契约

HTML 表格第 1 列文本JSON 字段名数据类型备注
姓名namestring必填
性别genderstring“男”/“女”
出生日期birth_datestring格式YYYY-MM-DD
民族nationstring如“汉族”
籍贯native_placestring省+市,如“江苏省南京市”
入学日期enroll_datestring格式YYYY-MM-DD
毕业日期graduate_datestring格式YYYY-MM-DD
学历层次degree_levelstring“本科”/“专科”/“硕士”
专业名称majorstring完整专业名
学习形式study_formstring“普通全日制”/“成人教育”

注意:此表不是猜测,而是对照学信网官网《学籍学历信息数据字典》V2.3 版本整理。字段名采用 snake_case 是为了兼容下游系统(如 Django ORM、SQLAlchemy)。

5.3 解析函数:用 XPath 定位 + 正则清洗,生成标准 JSON

# parse.py import re import json from selenium.webdriver.common.by import By def parse_academic_info(driver): # 定位学籍信息表格(class="archive-table") table = driver.find_element(By.CLASS_NAME, "archive-table") rows = table.find_elements(By.TAG_NAME, "tr") result = {} for row in rows: cells = row.find_elements(By.TAG_NAME, "td") if len(cells) < 3: continue # 清洗字段名:去除空格、换行、nbsp field_name = re.sub(r'[\s\u00A0]+', '', cells[0].text) # 清洗字段值:去除冒号后空格、nbsp、br 标签 field_value = re.sub(r'[\s\u00A0]+', '', cells[2].text) # 映射字段(只处理映射表中存在的字段) field_map = { "姓名": "name", "性别": "gender", "出生日期": "birth_date", "民族": "nation", "籍贯": "native_place", "入学日期": "enroll_date", "毕业日期": "graduate_date", "学历层次": "degree_level", "专业名称": "major", "学习形式": "study_form" } if field_name in field_map: key = field_map[field_name] # 对日期字段做格式标准化(学信网有时返回“1998年05月12日”) if key in ["birth_date", "enroll_date", "graduate_date"]: field_value = re.sub(r'[年月日]', '-', field_value) field_value = re.sub(r'-{2,}', '-', field_value) # 处理多余横线 result[key] = field_value return result # 使用示例 # info = parse_academic_info(driver) # print(json.dumps(info, ensure_ascii=False, indent=2))

逻辑说明:re.sub(r'[\s\u00A0]+', '', ...)同时清理空格(\s)和不间断空格(\u00A0),后者是学信网 HTML 中常见的排版字符;日期标准化正则re.sub(r'[年月日]', '-', ...)将中文日期符号统一为-,再用re.sub(r'-{2,}', '-', ...)修复“1998--05--12”这类双横线错误;字段映射用字典而非 if-elif,提升可维护性——新增字段只需改字典,不碰逻辑。


6. 进阶技巧:把“页面模拟”变成“可嵌入服务”,用 Flask 封装成 HTTP 接口

单机脚本的价值有限,真正落地的是把它变成一个内部 HTTP 服务。我给某高校做的方案就是:前端教务系统提交学号,后端调用这个模拟器,5 秒内返回 JSON 结果。关键不在“能封装”,而在“封装后不崩、不卡、不冲突”。

6.1 多实例隔离:用线程局部存储(Thread Local)管理浏览器

Flask 默认多线程,但 Selenium 的driver实例不能跨线程共享。若全局声明driver = create_browser(),并发请求会相互覆盖。解决方案是用threading.local()为每个请求分配独立浏览器:

# app.py import threading from flask import Flask, request, jsonify app = Flask(__name__) browser_local = threading.local() def get_driver(): if not hasattr(browser_local, 'driver'): browser_local.driver = create_browser() return browser_local.driver @app.route('/query', methods=['POST']) def query_academic(): data = request.json student_id = data.get('student_id') driver = get_driver() try: do_login(driver) # 复用已有登录态 driver.get(QUERY_URL) info = parse_academic_info(driver) return jsonify({"code": 0, "data": info}) except Exception as e: return jsonify({"code": 1, "msg": str(e)}) finally: # 不关闭 driver,保留登录态供下次复用 pass

技巧说明:threading.local()为每个线程创建独立副本,browser_local.driver在线程 A 和线程 B 中是两个完全不同的对象;do_login()前先检查driver.current_url是否已是个人中心页,避免重复登录;finally中不调用driver.quit(),因为学信网登录态有效期约 2 小时,复用可省去 8 秒登录开销。

6.2 超时熔断:用信号量(Semaphore)限制并发,防 Chrome 崩溃

Chrome 占用内存极大,10 个并发实例可能吃光 8GB 内存。用threading.Semaphore限流是最轻量的方案:

# app.py import threading # 最多允许 3 个并发浏览器实例 semaphore = threading.Semaphore(3) @app.route('/query', methods=['POST']) def query_academic(): # 尝试获取信号量,超时 30 秒 if not semaphore.acquire(timeout=30): return jsonify({"code": 1, "msg": "服务繁忙,请稍后重试"}) try: driver = get_driver() # ... 执行查询 return jsonify({"code": 0, "data": info}) finally: semaphore.release()

6.3 日志追踪:给每次查询打唯一 trace_id,方便排查“谁查了谁”

学信网操作涉及敏感信息,必须记录操作溯源。我在query_academic()开头插入:

import uuid trace_id = str(uuid.uuid4()) app.logger.info(f"[{trace_id}] 查询学号: {student_id} 开始") # ... 执行逻辑 ... app.logger.info(f"[{trace_id}] 查询学号: {student_id} 成功,结果: {json.dumps(info, ensure_ascii=False)}")

然后配置 Flask 日志输出到文件,按天滚动:

# logging_config.py import logging from logging.handlers import TimedRotatingFileHandler handler = TimedRotatingFileHandler( "logs/chsi_query.log", when="midnight", interval=1, backupCount=30, encoding="utf-8" ) handler.setFormatter(logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' )) app.logger.addHandler(handler) app.logger.setLevel(logging.INFO)

我的习惯:上线前必做三件事——用psutil监控 Chrome 进程内存占用,设置ulimit -n 65535防止文件描述符耗尽,把chromedriver放到/usr/local/bin而非项目目录(避免打包后路径错乱)。这些细节不会写在文档里,但少做一条,服务就可能半夜报警。希望帮到你。

本文还有配套的精品资源,点击获取

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

Shizuku+ADB零Root自动化脚本实战:从无线调试到设备遍历

1. 项目概述与整体方案1.1 先说清楚Shizuku和ADB是什么关系很多人听到Shizuku第一反应是"又一个Xposed框架"&#xff0c;其实完全不是一回事。Shizuku本身不是一个Hook框架&#xff0c;它是一个运行在Android系统上的服务进程&#xff0c;帮你把ADB&#xff08;Andro…

作者头像 李华
网站建设 2026/9/26 6:20:47

dsh插件安装原理与profile驱动机制详解

1. 先搞清楚 dsh 是什么&#xff0c;再谈插件安装很多人一看到“dsh如何安装插件”就直接抄命令、改配置&#xff0c;结果报错一串&#xff1a;“plugin tree failed to load”、“deep plugin failed to load”、“dsh web authentication required”&#xff0c;甚至卡在“re…

作者头像 李华
网站建设 2026/9/26 6:20:47

XYHCMS v3.5 build0518 部署与安全实战指南

简介&#xff1a;XYHCMS网站管理系统 v3.5 build0518 是一款面向个人开发者、中小企业建站者及PHP初学者的轻量级开源CMS解决方案&#xff0c;聚焦博客搭建、企业官网快速部署与定制化网站开发场景。资源包为ZIP格式&#xff0c;共含4个核心文件&#xff1a;说明.htm&#xff0…

作者头像 李华
网站建设 2026/9/26 6:20:28

选择性刻蚀的选择比控制:氮化硅/氧化硅工艺的软着陆实战

周一早上八点半&#xff0c;我刚把车停进园区&#xff0c;手机就响了。良率工程师的声音有点发紧&#xff1a;“氮化硅开窗那道工序&#xff0c;底下氧化硅被吃了个坑&#xff0c;这批次整体良率掉了七八个点&#xff0c;切片图我发你了&#xff0c;你赶紧看一眼。”我蹲在路边…

作者头像 李华
网站建设 2026/9/26 6:20:08

Python实现远程打卡

不能帮助伪造 GPS、虚拟定位、代打卡或绕过人脸/设备校验。如果你们公司允许远程办公&#xff0c;并且提供了官方打卡 API&#xff0c;可以用下面这段合规代码定时调用官方接口打卡。python# clock_in.pyimport osimport timeimport loggingfrom datetime import datetimeimpor…

作者头像 李华