HttpAsyncClient实战:从线程阻塞到异步NIO的架构迁移与埋坑指南
1. 从同步阻塞到异步回调我在生产环境第一次被逼着换 HttpAsyncClient先说一个让我印象很深的场景。某天下午我们监控大屏上的 Tomcat 工作线程曲线突然顶到了 200 的满配值很多接口响应时间早就超过了 SLO但下游服务的 CPU 和负载却低得离谱请求全堵在我们自己这一层。dump 出来的线程栈里密密麻麻都是同一个状态——java.net.SocketInputStream.socketRead0几十条线程被同一个慢接口牢牢摁住动弹不得。那个接口本身不复杂就是聚合下游多个数据源的列表查询平均耗时 1.5 秒左右。业务并发一上来需要的线程数就很容易算目标 QPS × 平均响应时间。每秒 200 个请求 × 1.5 秒 300 个线程才够扛但 Tomcat 线程池只有 200。等待 I/O 的时间里线程全部空转眼睁睁看着连接被占满却什么都做不了。这正是我后来下定决心把同步HttpClient换成HttpAsyncClient的直接原因。如果你现在还用着同步客户端又被下游慢接口折磨过这篇文章就是写给你看的。我不打算写入门教程假设你已经会用HttpClient发起同步请求、配置连接池现在就差“怎么把这套经验迁移到异步模型上”以及“异步模型底下到底发生了什么”这层窗户纸。1.1 同步客户端的线程账本为什么算不过来同步模型的根本问题不是“慢”而是“一个请求占一个线程”。你发起一个 GET 请求工作线程就阻塞在socketRead0上直到响应完全读完才返回。这中间的几个毫秒到几秒线程什么正事也干不了。我给这种问题起过一个外号叫“线程税”任何一次外部调用都要按QPS × 平均延迟缴纳线程资源。延迟是下游决定的你控制不了所以要么疯狂加大线程池要么眼睁睁看着排队。加大线程池也不是长久之计JVM 线程本身吃掉不少内存一个线程默认栈 1MB1000 个线程就是 1GB 虚拟内存上下文切换开销也会反过来拖垮吞吐。异步模型把这笔账抹掉了。发起请求的工作线程在“提交任务”后立刻解放出来真正等 I/O 的是底层那一小撮 NIO 线程。同样是 1.5 秒的慢接口4 个 I/O 线程就能同时盯住上千个在途请求。这不是谁更聪明而是它们根本不在同一套等法上。1.2 异步到底“异步”在哪里同一个线程不再让位给单一连接HttpAsyncClient的底层是 Java NIO 的Selector事件机制。你可以把Selector想象成餐厅门口的叫号屏顾客连接不需要占着一张桌子干等着菜做好服务员I/O 线程只要盯着叫号屏谁的菜好了就去端一下然后再回来继续盯屏。一个人能同时服务几十桌而不是一桌配一个人。所以这里的“异步”不是帮你把请求变快了而是把“等待 I/O”这件事从昂贵的业务线程上剥离出去交给少量专用的 NIO 线程去监听读写事件。真正理解这句话你后面读连接池、读超时、读回调才不会被坑。2. 连接池、事件循环与背压异步模式下必须重建的三大基础认知很多人从同步HttpClient迁移到异步最容易犯的错就是把连接池参数照搬过来改个类名就开始跑。实际上异步客户端的连接管理模型和同步有本质差异不只是“线程不阻塞了”那么简单。2.1 PoolingNHttpClientConnectionManager 是怎么管理异步连接的同步的PoolingHttpClientConnectionManager管理的是“已经建立好 socket 连接”的活对象请求来了直接从池子里拿一条连接就能用。异步的PoolingNHttpClientConnectionManager要麻烦得多它管理的每条连接不但要建立 TCP 链路还要绑定到一个 NIO reactor 的事件循环上后续的数据读写全部由这个事件循环驱动。正因为如此从异步连接池里取连接时你拿到的并不是一个可以直接调getOutputStream()的普通 socket而是一个“异步连接租约”——后续读写动作都要以回调的方式提交给对应的 NIO 线程去执行。这点决定了你在使用 API 时的感知完全不同后面 《第 3 章》 里展开说。2.2 IOReactor 与 Selector 的配合机制HttpAsyncClient4.x 的核心组件是DefaultConnectingIOReactor它内部会创建若干个IOReactor每个 IOReactor 都对应一个独立的Selector循环。你在配置里看到的ioThreadCount就是这些事件循环线程的数量。事件循环的工作流程大致是Selector等待感兴趣的事件比如连接可写、数据可读。事件到达后循环线程从事件中拿到对应的会话触发回调。回调执行完线程回到Selector继续阻塞等待下一个事件。这里的“回调执行”特别关键。默认情况下回调是在这个 I/O 循环线程上直接执行的。如果你在回调里做了耗时操作等于让叫号屏的服务员不只是端菜还得去后厨帮忙炒菜——其他所有正在等待事件的连接全部跟着遭殃。网上很多“异步客户端的回调主线程卡死”的案例十有八九就是这么来的。2.3 连接池打满后的排队行为和同步完全不是一回事同步连接池满了后来的请求直接抛ConnectionPoolTimeoutException你是能明确感知到“拿不到连接”的。异步连接池满了之后请求不会立刻失败而是进入内部一个等待队列。这个队列是有时间上限的由connectionRequestTimeout控制超时了才抛异常。这带来一个隐蔽的问题队列里的每个等待请求都持有完整的请求上下文、回调引用和 Future 对象。一旦下游持续不释放连接队列越积越长内存和 GC 压力会跟着上去。很多团队只盯着接口超时率忘了看连接池的“Pending”数量最后定位到的时候已经是 OOM 的边缘了。我建议在任何基于HttpAsyncClient的项目里至少要监控两个指标连接池的Leased数量和Pending数量。Pending 突然上涨比 Leased 上涨更值得警惕。3. 实战 API 的两种打开方式Future 模式和回调模式到底怎么选3.1 基础代码形态对比先看最常见的两种执行方式。Future 模式CloseableHttpAsyncClient client HttpAsyncClients.createDefault(); client.start(); HttpGet request new HttpGet(https://api.example.com/data); FutureHttpResponse future client.execute(request, null); // 这里会阻塞等待直到拿到响应 HttpResponse response future.get(5, TimeUnit.SECONDS);回调模式CloseableHttpAsyncClient client HttpAsyncClients.createDefault(); client.start(); HttpGet request new HttpGet(https://api.example.com/data); client.execute(request, new FutureCallbackHttpResponse() { Override public void completed(HttpResponse result) { // 请求成功解析响应 } Override public void failed(Exception ex) { // 请求失败处理异常 } Override public void cancelled() { // 请求被取消 } });很多从同步转过来的人第一反应是选 Future 模式——因为future.get()能“无缝替换”同步代码改动最小。这个想法我特别能理解但它也是最大的陷阱。3.2 为什么说future.get()是伪异步future.get()的效果是调用它的线程进入阻塞等待直到响应返回。如果你是在业务请求线程里直接调它那这个线程又回到了“阻塞等待 I/O”的老路上。表面上代码写的是异步客户端线程模型却和同步没有区别线程账本依旧算不过来。正确的姿势是业务线程只负责提交请求然后立刻返回响应处理全放在回调里完成。把异步客户端当成“发令枪”而不是“快递签收点”。你需要把后续依赖这个响应的逻辑拆成“拿到响应之后做什么”的回调片段这种写法刚开始确实别扭但它是异步模型能带来吞吐提升的唯一路径。我在团队里推过一个实用规则凡是需要future.get()的代码写法都必须在 code review 时给出明确理由没有理由的一律改成回调模式用CompletableFuture做编排时也保持异步链式调用拒绝中途.get()。3.3 回调线程上下文陷阱ThreadLocal 在回调里必然失效这是异步化改造时最容易翻车的细节而且往往要到生产环境排查问题时才暴露。同步调用里你的请求线程从头到尾是同一个线程ThreadLocal里的 traceId、租户信息、用户属性一路畅通。异步回调完全不同发起请求是业务线程 A回调执行却是 NIO 线程 B甚至可能是 C、D 里的任意一个。ThreadLocal里的东西在回调线程里是空的。我在某项目里见过一次诡异的问题接口响应时间正常但调用链追踪系统的 traceId 断了日志对不上。查了半天就是这个原因。回调线程没有继承父线程的上下文日志框架拿着一个空 traceId 在打点。常见解决办法有三种回调参数显式传递把需要的上下文值在发起请求前捕获作为闭包变量带入回调。自定义上下文传播器在提交请求前把 ThreadLocal 快照存到一个可传参的对象里回调取出后重新放回当前线程。结合 TraceId 扩展如果日志框架支持TraceId的动态解析在回调入口显式设置。3.4 回调里绝不能做的三件事根据我在生产环境踩过的坑以下操作都容易把问题放大不要在回调里访问远程资源比如再调一次数据库或另一个 HTTP 接口。回调线程不是你的业务线程池它不应该承担任何可能阻塞的 I/O 操作。不要Thread.sleep()哪怕你只是想做个限速也会把这个 NIO 线程摁住。不要做重计算大批量 JSON 解析、加解密这类 CPU 密集操作同样会拖慢事件循环。如果确实需要在回调里执行重活正确做法是把任务丢给你自己的业务线程池回调里只做最轻量的转发private final ExecutorService businessPool Executors.newFixedThreadPool(16); client.execute(request, new FutureCallbackHttpResponse() { Override public void completed(HttpResponse result) { businessPool.submit(() - handleResponse(result)); } // ... });4. 超时、连接池与重试参数异步场景下的调优实践同步客户端的调优经验在异步模型里并不能直接平移尤其是超时参数的设置逻辑。我列一下每个参数在我的项目里是怎么落地的。4.1 三个超时参数的语义重构参数同步语义异步语义我的推荐值connectTimeout建立 TCP 连接的超时建立 TCP 连接的超时3-5 秒connectionRequestTimeout从连接池获取连接的超时从连接池连接队列中等待的超时2-3 秒socketTimeout等待数据的超时I/O 事件等待数据的超时5-10 秒在异步模式下特别注意socketTimeout它表示从连接上读取数据的事件超时如果一个请求已经发出去但响应一直没回来这个超时就会在事件循环层被触发。同步时代你可以依赖 socketTimeout 兜底异步里我也建议加一层业务层的总超时控制防止个别连接因为事件循环繁忙导致迟迟没有回调。总超时可以用调度器实现发起请求时启动一个延迟任务到点还没收到完成信号就主动取消 Future 并释放连接。4.2 连接池参数怎么估算一个可复用的公式连接池大小不需要拍脑袋。核心公式和线程数公式一致连接数 ≈ 目标 QPS × 平均响应时间这是理论上限实际再乘以 1.2-1.5 作为缓冲。举个例子目标 QPS 300下游平均延迟 500ms那需要的连接数就是300 × 0.5 150缓冲后设成 200。单路由默认的maxPerRoute可以先设成 180maxTotal设成 220给重试、突发流量留点裕量。同步模型下连接数虚高出问题最多的是线程异步模型下连接本身就是稀缺资源——万一估算偏低请求不会立刻失败而是全部排队等连接connectionRequestTimeout一超就是一个批量事故。所以宁可比估算值多给一点。4.3 重试策略要重写别把同步重试逻辑粘过来同步客户端里我们习惯在异常后 catch 住重试一次。异步回调模型里重试逻辑往往在failed()回调里再发起一个新的请求这里有两个坑第一个坑不判断请求类型就重试。failed()里能捕获的异常包括连接超时、请求超时、I/O 错误等。连接超时重试是安全的但写入类接口在“请求已发出但响应丢失”的边界场景下重试可能造成重复提交。重试前要检查当前请求是否幂等写操作必须结合业务幂等键。第二个坑无节制重试。重试本质上是在放大下游压力。如果下游已经处于过载状态你把并发里每个失败请求都重试一次那就是火上浇油。我推荐的重试策略是最多重试 1 次且只对ConnectTimeoutException、ConnectException这类“一定还没发出去”的异常重试对已经发出请求后的超时不重试转人工或标记失败。5. 三个真实生产事故复盘从表象到根因的完整排查链路这一章换个节奏直接讲我遇到过的三次“看起来完全不一样但根子都在异步模型特殊性上”的线上问题。5.1 事故一连接池不够表现的却是“大量超时”现象监控上一片SocketTimeoutException第一反应是下游变慢了。但查看下游链路延迟毫无波动查看客户端才发现问题。排查过程分三步看异常堆栈发现超时类型不是SocketTimeoutException而是ConnectionPoolTimeoutException——这是异步连接池在connectionRequestTimeout超时后抛的。打开连接池统计Leased打满Pending持续爬升说明新请求拿不到连接全在排队。顺着链路回看下游有一个消费方接口的调用量突然翻倍平均响应时间从 300ms 涨到 2 秒连接数按QPS × RT估算直接被顶爆。根因是下游接口延迟变慢后连接占用时间线性变长而连接池没有同步扩容。解决措施分两段短期调大maxConnPerRoute和connectionRequestTimeout长期推动下游接口优化慢查询。提示遇到“超时”类异常先看异常类型对应的是哪个超时参数别一上来就怪下游。5.2 事故二回调里的同步操作把 I/O 线程池喂饱了现象某服务换了异步客户端之后初期吞吐确实涨了但运行一段时间后接口延迟开始出现周期性的长尾最长的能到几十秒。初步排查发现不是连接池问题连接数一直稳定。后来我 dump 了线程发现所有 NIO 线程都卡在java.sql.DriverManager.getConnection附近——回调里有人直接查询了 MySQL。问题确认有一个同学在completed()回调里做了同步数据库查询把本应快速返回的 I/O 线程占住了。I/O 线程只要有几个被占住整体网络事件的调度就会大幅变慢表现为所有经过该客户端的请求都出现长尾。修复方式就是我在《第 3.4 节》里强调的回调里一律不做阻塞操作重活丢给业务线程池。修完重启后长尾立刻消失。提示异步客户端性能衰减的第一怀疑对象不是连接池而是回调线程被“污染”。5.3 事故三回调异常吞没与连接泄漏现象服务内存曲线缓慢上涨重启后能撑两周不重启就 OOM。GC 日志显示堆上有大量FutureCallback持有者对象无法回收。排查链路是先压内存快照发现是PoolingNHttpClientConnectionManager里连接对象的数量异常多。检查代码发现一处failed()回调里处理异常后忘了释放持有的连接引用。更隐蔽的是回调内部抛出的异常没有兜底处理导致连接释放逻辑根本没执行。这里要特别记住FutureCallback的三个方法里任何未被捕获的异常都会直接打断后续流程。我后来在所有异步请求的封装的failed()和completed()里都加了 try-finally确保连接引用置空。更彻底的做法是统一封装一个BaseAsyncCallback把连接释放操作落在 finally 里业务方只负责实现处理逻辑public abstract class SafeHttpCallback implements FutureCallbackHttpResponse { Override public final void completed(HttpResponse result) { try { onSuccess(result); } catch (Throwable t) { log.error(callback process error, t); } finally { releaseReferences(result); } } }6. 从 HttpAsyncClient 4.x 到 HttpClient 5版本演进的选型思考6.1 5.x 把异步收编进主库解决了什么老牌的HttpAsyncClient4.x 是独立模块使用时要额外引入httpasyncclient依赖还要依赖httpcore-nio、httpclient等一整套组件版本匹配是一件容易让人头疼的事。HttpClient 5把异步能力直接收编到主库里类统一成了CloseableHttpAsyncClient不仅在依赖管理上简化了还把连接池管理、异步身份认证、路由策略整合到了一套 API 体系里。对老工程师来说变化最大的其实是包名和类名全部换了一批。老代码的PoolingNHttpClientConnectionManager在 5.x 里对应PoolingAsyncClientConnectionManagerIOReactorConfig的配置方式也有调整。迁移的时候不要试图做“文本级替换”建议照着 5.x 的官方示例重新组织配置代码。6.2 我的选型建议新项目用 5.x老项目别急着动如果你的系统已经是 HttpAsyncClient 4.x 的稳定运行状态我的建议是“别为自己的爽快搞大迁移”。老组件修修补补、锁版本、补监控都能用得挺好4.x 的坑大多已经被前人踩完社区解决方案也全生产环境里非常稳。新项目的选型我建议直接上HttpClient 5的异步客户端。理由有三个依赖更干净少了跨模块版本对齐问题。支持 HTTP/2对多路复用场景友好。接口 API 设计比 4.x 清晰尤其体现在AsyncClient的链式写法和请求配置统一管理上。5.x 的一个最小异步客户端示例CloseableHttpAsyncClient client HttpAsyncClients.custom() .setConnectionManager(PoolingAsyncClientConnectionManagerBuilder.create() .setMaxConnTotal(200) .setMaxConnPerRoute(160) .build()) .build(); client.start(); SimpleHttpRequest request SimpleRequestBuilder.get(https://api.example.com/data) .setTimeout(Duration.ofSeconds(5)) .build(); client.execute(request, SimpleHttpResponse.class, new FutureCallbackSimpleHttpResponse() { Override public void completed(SimpleHttpResponse result) { // 处理响应 } Override public void failed(Exception ex) { // 处理失败 } Override public void cancelled() { // 处理取消 } });6.3 异步客户端的最终价值不是“低延迟”而是“高资源利用率”把整个演进过程走完我的核心体会是不要把异步客户端当成“让接口更快”的银弹。它的价值在于让同样多的机器资源承载更大规模的并发减少线程膨胀、降低上下文切换开销、提升系统可扩展性。单次请求的延时不会因为换异步客户端就变短该 1.5 秒还是 1.5 秒但你能用 4 个 NIO 线程同时等 1000 个这样的请求而不用开 1000 个业务线程去陪跑。这也是我在评估是否值得引入异步客户端时的判断标准先算出同步模型下的线程数需求如果线程需求 线程池上限说明阻塞型等待已经成了瓶颈那就果断切异步如果量级不大线程宽裕异步带来的复杂度反而是多余的维持同步更舒服。技术选型说到底不是越高级越好而是越匹配场景越好。

相关新闻

永磁同步电机无感FOC零速启动:高频方波注入原理与STM32F405实现

永磁同步电机无感FOC零速启动:高频方波注入原理与STM32F405实现

做电机控制的调试多了,我慢慢有个体会:速度环和电流环谁都会调,真正考验功力的,是零速启动那一刻能不能稳准狠。低速段做无感FOC,用反电动势观测器基本是白搭,得靠HFI高频方波注入这类不依赖转速的主动激励…

2026/10/17 15:55:32 阅读更多 →
Python使用aiohttp实现每秒千次的网页抓取

Python使用aiohttp实现每秒千次的网页抓取

前言 先把标题里的前提点破:「每秒千次」对单一站点发起请求,不是技术指标,而是压站行为。任何有一定规模的网站,一秒收到上千次来自同一来源的请求,都会被判定为异常流量并触发限流甚至封禁;从合规角度&am…

2026/10/16 7:08:03 阅读更多 →
Gradle手动创建Web工程并打War包部署Tomcat实战指南

Gradle手动创建Web工程并打War包部署Tomcat实战指南

这一篇是Gradle入门系列里的第四篇,前几篇把Gradle的环境、基本命令和构建脚本语法聊完之后,很多人卡在了同一个地方:我到底怎么用它建一个能丢进Tomcat跑的web工程。网上一搜教程,要么是Spring Boot的starter模板,要么…

2026/10/17 13:06:45 阅读更多 →

最新新闻

数据指标多重应用:从口径定义到业务决策的实战指南

数据指标多重应用:从口径定义到业务决策的实战指南

看一眼标题,很多人第一反应是“哪个指标?”,然后就没有然后了。做数据和运营这些年,最明显的一个感受是:大家天天在看日活、看留存、看转化率,但这些“熟悉得不能再熟悉”的指标,绝大多数时候只…

2026/10/17 17:51:34 阅读更多 →
Windows 下 GDAL FileGDB 驱动编译与读写实战:从源码到可运行

Windows 下 GDAL FileGDB 驱动编译与读写实战:从源码到可运行

简介:这份资源面向在 Windows 平台从事地理数据处理与转换的开发者,尤其是需要在脱离 ArcGIS 环境的前提下读写 .gdb 文件地理数据库的工程师。针对 GDAL 3.5 及以下版本默认不支持写入 gdb 的问题,资源给出了基于 FileGDB 驱动的轻量级配置方…

2026/10/17 17:51:34 阅读更多 →
Hive动态分区为何必走Shuffle?揭秘Reduce强制触发机制

Hive动态分区为何必走Shuffle?揭秘Reduce强制触发机制

1. 动态分区不是“开个开关”就能跑得快:为什么Hive里一用动态分区就卡在Shuffle阶段你有没有遇到过这样的场景:写好一个带INSERT OVERWRITE TABLE ... PARTITION (dt, region)的SQL,本地小数据测试飞快,一上生产集群,…

2026/10/17 17:51:34 阅读更多 →
Teamcenter 2406部署避坑指南:四层客户端组件冲突与BMIDE环境变量配置

Teamcenter 2406部署避坑指南:四层客户端组件冲突与BMIDE环境变量配置

简介:这份文档面向Teamcenter实施与运维人员,聚焦PLM系统部署中客户端与开发工具的安装配置问题。内容围绕Deployment Center工具展开,覆盖TC24062、两层与四层客户端以及BMIDE的完整部署流程,适合具备一定PLM基础、需要独立完成环…

2026/10/17 17:51:34 阅读更多 →
基于Autoencoder的反欺诈异常检测实践:从原理到工程落地

基于Autoencoder的反欺诈异常检测实践:从原理到工程落地

做反欺诈相关算法的人,天天面对同一个矛盾:欺诈样本太少,而且永远在变。别的分类模型再强,喂进去的标签说白了都是历史旧账,而你要拦的是明天可能出现的新变种。所以我第一次在某个风控原型项目里尝试用 Autoencoder 做…

2026/10/17 17:51:34 阅读更多 →
MTK/高通/展锐刷机工具全解析:从协议到救砖实战

MTK/高通/展锐刷机工具全解析:从协议到救砖实战

简介:面向MTK、高通、展锐三大移动平台的版本升级烧录工具合集,适合设备厂商、开发者与售后维修人员使用,覆盖固件全量升级、增量升级、底层加载、分区写入、驱动识别与故障恢复等常见场景。资源包共1031个文件,压缩后181.59MB&am…

2026/10/17 17:50:33 阅读更多 →

日新闻

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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →