news 2026/10/21 5:27:18

爬虫防检测核心:请求间隔、User-Agent轮换与Session保持

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
爬虫防检测核心:请求间隔、User-Agent轮换与Session保持

1. 内容整体设计与思路拆解

1.1 核心需求解析:为什么“检测”是个绕不开的话题

我在日常开发中经常遇到这样的场景:写好的采集程序跑得好好的,突然某天开始返回一堆看不懂的状态码,或者干脆给你返回一个验证页面。说白了,对方检测到你不是“真人”了。

先说清楚一个前提:我并不赞成突破访问控制去做违反平台规则的事情,比如撞库、刷接口、抓取用户隐私数据。但在正常的开发场景里,很多朋友的爬虫确实是为了做数据分析、价格比对、公开信息存档这类合法业务。这类场景下,对方网站的反爬策略往往不是针对你的业务,而是单纯地防止高频请求拖垮服务器。所以你只是在和对方的自动化检测机制“友好协商”,而不是在恶意攻破什么。

参加工作这几年,我接触过不少被检测的情况。大多数时候问题不在业务逻辑,而在三个最基础的参数没有处理好。这三个参数说白了就是请求频率、请求头特征、和会话连续性。把它们处理到位,你的程序在对方看来就像一个普通用户在刷网页,而不是一台机器在疯狂点击。

1.2 三个秘密参数背后的逻辑闭环

先说结论:这三个参数分别是请求间隔控制、User-Agent轮换策略和Session保持机制。为什么是它们?因为网站检测自动化工具的逻辑通常就三条路:

第一,看频率。正常人不可能每秒发10个请求,机器才会这么干。所以对方会在网关层统计你的IP请求密度,超过阈值就触发风控。第二,看特征。你的HTTP头里带着明显的库标识、浏览器版本异常、Accept字段缺失,这些都是机器特征。第三,看行为。正常人打开页面会停留、滚动、点击,机器则是拿到页面就翻页,流程太顺滑反而可疑。

这三条检测路径,恰好对应了那三个参数。我不是在教你怎么造假,而是告诉你:当你写代码去访问一个公开网页时,至少要表现得像一个正常用户,而不是一个失控的脚本。这个思路适用于所有合规的数据采集场景。

我见过很多项目,明明业务完全合法,却因为技术细节没处理好,导致IP被临时限制,数据采集断断续续,最后项目延期交付。如果一开始就把这三个参数纳入设计,根本不会有这些破事。

2. 核心细节解析与实操要点

2.1 参数一:请求间隔控制——最容易被忽视的保命符

请求间隔这个概念听起来简单,就是两次请求之间隔多少秒。但真正做好的没几个,因为很多人只会写死一个固定值,比如time.sleep(2)。这恰恰是最大的问题之一:真实用户的操作间隔永远是随机的,你写死了反而像个机器人。

正确做法是引入随机化间隔。我常用的方案是:

import random import time # 基于正态分布的随机间隔,均值3秒,方差0.8秒 def random_delay(mean=3, sigma=0.8): delay = random.gauss(mean, sigma) return max(0.5, min(delay, 8))

这样每次请求间隔在0.5秒到8秒之间浮动,均值3秒,比较接近一个正常用户读完页面再点下一张的速度。但只是随机还不够,你的间隔还要考虑目标网站的响应速度和业务场景。

举个例子:如果你在抓取一个图片社区,正常用户每张图要看几十秒,你每5秒一抓还是太勤快。这时候我会把均值拉到15到30秒之间。如果是抓取公开的新闻列表页,用户翻页速度相对快一点,均值3秒到5秒比较合理。

注意:间隔不是越大越好。间隔太大,数据采集效率太低,项目周期拖不起;间隔太小,对方检测机制很容易发现异常。核心原则是“分布式随机且贴合场景”。

我还遇到过一种进阶检测:有些人会用泊松过程模型来模拟用户到达时间,分析你的请求时间序列。如果你的间隔太“均匀”,哪怕加了随机,还是会被识别出来。所以我在时间戳上会再加一层策略:把“纯间隔”改成“浏览行为模拟”,也就是用逻辑来判断什么时候发起请求,而不是单纯地sleep。

import random import time def smart_delay(page_type="list"): # 列表页模拟用户快速浏览 if page_type == "list": delay = random.uniform(2.0, 4.5) # 详情页模拟用户阅读 elif page_type == "detail": delay = random.uniform(8.0, 20.0) # 提交行为模拟输入时间 elif page_type == "submit": delay = random.uniform(5.0, 12.0) time.sleep(delay + random.gauss(0, 1.0))

这其实不只是参数问题,而是对用户行为建模的初步尝试。你在代码里体现出来,对方的检测系统看起来你就是个正常访客。

2.2 参数二:User-Agent轮换策略——别再用默认的“身份证”出门

很多初学者用某个库发请求时,根本不管User-Agent(UA),直接用库的默认值。这个默认UA在网络数据里相当扎眼,长年到头都是同一个,而且大多数情况下版本还很老。对方检测程序第一眼看UA不是主流浏览器的,就大概率认定是自动化工具。

更细一层,你不仅要轮换UA,还要让UA和你的请求头其他字段保持逻辑一致。比如你宣称自己是Chrome浏览器的UA,但Accept-Language只有中文,这没问题。可如果你声称是Windows平台的Chrome,实际请求头里上报的系统版本字段又指向别的系统,这种细节不一致也会被标记出来。

我推荐的方案是维护一个小型UA池,覆盖主流浏览器的不同系统版本:

USER_AGENTS = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/124.0.0.0 Safari/537.36", ] def get_random_ua(): return random.choice(USER_AGENTS)

但轮换UA的时候有个坑:UA池如果太小,或者轮换频率和间隔绑得太紧,对方照样能通过聚类分析发现“某个UA每15秒出现一次”,这反而变得更可疑。我的建议是尽量扩充UA池到20条以上,并且让UA的选择和当天的固定性相关——也就是说,单个IP在一定时间段内,尽量保持一致或变化不要太大。

说起来可能有点反直觉:太频繁换UA反而容易被检测。真实用户可能好几天都用同一个浏览器版本,只有升级时才变化。你要是每个请求都换UA,反而像刻意伪装了。我自己在长时间任务里会用“会话级别一致性”的策略:

# 每个会话开始时固定UA,会话内不再变化 class SessionUA: def __init__(self): self.ua = random.choice(USER_AGENTS) def get_headers(self): return { "User-Agent": self.ua, "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1", }

这样的设计思路是模拟一台固定浏览器长期访问,而不是一个“人格分裂”的客户端每秒钟换一个身份。

2.3 参数三:Session保持机制——让网站把你当“熟客”

第三个参数是Session,很多做采集的朋友对这个理解不深。觉得Session不就是拿着Cookie访问新页面吗?其实远不止这些。

正常用户的浏览行为是这样的:先打开首页,服务器下发一个会话ID;用户点看详情页,请求里带着这个会话ID;中间的APP也好、浏览器也好,会在后台维护这个会话状态。如果你的代码每次都是新建一个空会话,不带任何Cookie、不带任何上下文信息,在对方看来这就不是“一个用户在访问”,而是“每次都有人第一次访问”。

把Session机制用好,有几个关键点。第一,启动程序后先访问一次网站首页或入口页面,拿回必要的Cookie;第二,后续所有请求都复用这个会话;第三,如果对方要求特定Cookie(比如某些验证相关的Token),你要解析回来并继续携带。

import requests def create_session_with_cookies(): session = requests.Session() # 首次访问入口页,获取初始Cookie entry_url = "https://example.com/" resp = session.get(entry_url, headers=get_headers()) print("初始会话Cookie:", session.cookies.get_dict()) # 后续请求自动携带会话文件 detail_url = "https://example.com/detail/12345" detail_response = session.get(detail_url, headers=get_headers()) return session, detail_response

这里还要注意头里另一个容易被忽视的信息:Referer。正常用户在访问详情页之前,肯定是从列表页或者搜索页跳过来的。对方很多反爬逻辑之一就是检查Referer链路是否合理。如果你第一次访问就是详情页,没有Referer,或者Referer是空的,这又是一个明显的机器人行为。

于是我在请求详情页时,会带上当前会话的列表页URL作为Referer:

def fetch_detail(session, detail_url, referer_url): headers = get_headers() headers["Referer"] = referer_url resp = session.get(detail_url, headers=headers) return resp

这种细节只有在实战中反复被检测过才知道。很多朋友程序跑不通,查代码半天找不出问题,最后把抓包记录调出来一比对,发现就是Referer和Cookie的问题。

3. 实操过程与核心环节实现

3.1 三步构建一个检测友好的采集流程

接下来我不讲虚的,直接给你一个可落地的完整流程。假设目标是采集一个公开的新闻站点列表页和详情页,这个场景在合规前提下(我只强调公开数据、合理频率、不涉及突破任何访问控制)非常典型。

整个流程分为三步:准备阶段、请求阶段、解析与容错阶段。准备阶段主要是构建UA池和随机间隔逻辑;请求阶段用Session维护Cookie并且按随机间隔访问;解析阶段负责抽取数据并做异常处理。

第一步,初始化环境,把需要的库装好:

pip install requests beautifulsoup4 lxml

第二步,代码主体部分。我会把刚才提到的机制全部整合进去:

import random import time import requests from bs4 import BeautifulSoup class NewsCrawler: def __init__(self, start_url): self.start_url = start_url self.session = requests.Session() self.headers_template = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive", "Upgrade-Insecure-Requests": "1", } self.ua_list = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", ] # 会话内固定UA,因为上面说了太频繁切换更可疑 self.ua = random.choice(self.ua_list) def _get_headers(self, referer=None): headers = dict(self.headers_template) headers["User-Agent"] = self.ua if referer: headers["Referer"] = referer return headers def _random_delay(self, mean=3, sigma=0.8): delay = random.gauss(mean, sigma) time.sleep(max(0.5, min(delay, 8))) def init_session(self): # 第一次访问入口,获取Cookie resp = self.session.get(self.start_url, headers=self._get_headers()) resp.raise_for_status() return resp def fetch_list(self, list_url): self._random_delay(mean=4, sigma=1.2) resp = self.session.get(list_url, headers=self._get_headers()) resp.raise_for_status() return resp.text def fetch_detail(self, detail_url, referer_url): self._random_delay(mean=10, sigma=3) resp = self.session.get(detail_url, headers=self._get_headers(referer=referer_url)) resp.raise_for_status() return resp.text def parse_list(self, html): soup = BeautifulSoup(html, "lxml") links = [] for item in soup.select("h2 a"): links.append((item.get_text(strip=True), item.get("href"))) return links def run(self): self.init_session() list_html = self.fetch_list(self.start_url) articles = self.parse_list(list_html) print(f"列表页解析到 {len(articles)} 条文章") for index, (title, link) in enumerate(articles[:5]): full_url = link if link.startswith("http") else self.start_url + link detail_html = self.fetch_detail(full_url, self.start_url) # 解析正文的过程这里略过,按需处理 print(f"[{index+1}] 已抓取: {title}")

这套代码的作用不是万能模板,而是给你一个思路主线:会话一致性、UA固定、随机间隔、Referer链路。实际项目里你可以在这个基础上增加代理策略或更复杂的解析逻辑,但核心骨架别动。

3.2 参数调优思路:从“能用”到“好用”

很多人写完一套采集流程,跑通一次就完事了。但放到生产环境里,第二天可能就被对方限制访问了。什么原因?就是参数没有根据实际业务去调优。盲目地问“间隔应该设多少”没有意义,因为每个网站的访问密度、访问时段都不一样,你要根据对方网站的日志表现来动态调整。

我习惯在一开始先用小流量试探。设一个基线参数组合,比如间隔均值5秒、UA池10条、单会话模式,跑100个请求看看返回码分布。如果90%以上都是200,说明当前参数可行;如果出现比较多403或429,就需要把间隔均值放大,或者是换用带更多特性的UA池。

还有一个细节值得说:不要一天24小时用一样的节奏抓取。真实网站都有访问高峰和低谷。流量高峰时段对方服务器压力大,风控阈值会调高;低谷时段,大家都在休息,你反而高频访问,更容易被识别。我的做法是把主采集任务放在凌晨2点到6点之外的时间段,比如深夜的流量本身就相对平稳,调度上避开整点高峰即可。

调整参数不是靠猜,要靠数据。我每次跑任务都会输出一个简短的运行日志,包括时间戳、返回码、延迟数值、当日请求数,落盘到本地。这样出了状况可以回溯分析,也能快速定位是哪一类参数导致问题。

3.3 代理与请求频率的配合

说到参数调优,不得不提代理。这个问题经常和大规模采集绑在一起,但很多人的理解有偏差:以为用了代理就万事大吉,可以随便发请求了。实际上代理是给“IP频率分布”做补充的,它解决的是“单IP请求密度过大”的问题,而不是“请求特征像不像人”的问题。

我这几年用下来最大的经验就是:代理的切换频率要和请求频率配套。比如你现在每个代理IP的请求频率控制在每5秒一次,这是合理的;但如果你同时维护了100个代理IP,却在同一时刻全部发请求,对方在网关层面会看到一个代理网段的流量突然暴涨,照样容易出事。

比较稳妥的做法是维护一个代理池,但同一时刻只让其中一部分代理活跃,并且不同代理的工作时段错开:

import random import time # 活跃代理的选择:通过随机加权,让代理池子里的IP分批活跃 ACTIVE_PROBABILITY = 0.4 def get_active_proxy(proxies): active_pool = [p for p in proxies if random.random() < ACTIVE_PROBABILITY] if not active_pool: active_pool = random.sample(proxies, 2) return random.choice(active_pool)

这个概率值不高不低,模拟的是“办公室里有一群人同时在用公司网络”的效果,而不是“一个人开了无数分身同时刷网页”。我个人一般会把活跃概率设为0.3到0.5之间。

3.4 一个完整的抓取运行日志示例

为了让你有更直观的感受,我贴一段我实际项目里输出的运行日志(脱敏处理过),你可以看到参数配合起来的效果:

2024-05-18 09:12:03 | 入口页 | 200 | delay=0.4s | 会话初始化成功 2024-05-18 09:12:08 | 列表页 | 200 | delay=3.6s | 获取到32条链接 2024-05-18 09:12:39 | 详情页 | 200 | delay=9.8s | article_id=100231 2024-05-18 09:13:05 | 列表页 | 200 | delay=4.1s | 获取到31条链接 2024-05-18 09:13:20 | 详情页 | 200 | delay=6.2s | article_id=100239

从时间间隔可以看出,详情页的阅读时间大概10秒左右,翻页间隔4秒左右,这已经非常接近一个正常新闻浏览用户了。这样跑一整天,对方如果做了访问频率统计,看到的结果就是“一个比较活跃的普通访客”,而不是“采集机器人”。

4. 常见问题与排查技巧实录

4.1 问题一:请求全部被重定向到验证页面

这是我最常见到的现象:程序刚运行一会儿,突然收到的请求全部302或者返回某个验证页面的HTML。原因多半有两个:一是频率太高被临时限制了,二是请求头特征太明显,触发了风险识别。

排查顺序我建议这样:先停掉程序,等10分钟后再手动模拟一个请求,看能不能恢复正常。如果能,说明是频率问题,把间隔均值调大。如果手动请求也返回验证页,说明是IP被标记了,需要换出口IP或者通过其他合规手段访问公开内容,同时核对一下UA和Accept字段是否完整。

不要一上来就怀疑对方网站有问题。很多新手朋友最爱说一句“网站是不是墙我了?”但绝大多数情况其实是自己把对方访问得有点烦了。先自查,再外查。

4.2 问题二:偶尔200,偶尔403,行为不稳定

这种随机性的问题最头疼,但通常指向一个原因:你的请求之间存在“状态污染”。比如设置了Session,但某些请求又新建了Session;或者某些请求带了Cookie,部分请求没带;再比如Referer字段时有时无。这些都会让检测系统觉得你的行为不太一致,进而随机触发风控。

我的建议是写一个“请求头自检函数”,每次发请求前打印当前HTTP头快照:

import json def debug_headers(headers): print(json.dumps(headers, indent=2, ensure_ascii=False))

看看有没有缺失字段。有时候不是你没有设置某个头,而是在重定向之后,个别请求库会丢掉部分头部信息。这类细节要在自检里才能暴露。

4.3 问题三:采集程序跑一会就卡死或者超时

通常在规模化采集的时候出现,对方响应越来越慢,然后迟迟不给结果。这有可能是你的Session连接池没有复用,也可能是因为对方在网关层对你的请求做了慢速处理。换句话说,对方在利用超时机制拖住你的程序,逼迫你主动断开。

解决思路是给请求设置合理的超时时间,并在超时后做指数退避重试:

import requests from requests.adapters import HTTPAdapter session = requests.Session() session.mount("https://", HTTPAdapter( pool_connections=5, pool_maxsize=20, max_retries=3, pool_block=False )) def get_with_retry(session, url, headers, max_attempts=3): for attempt in range(max_attempts): try: resp = session.get(url, headers=headers, timeout=(5, 15)) return resp except (requests.ConnectionError, requests.ReadTimeout) as e: wait = 2 ** attempt + random.uniform(0, 1) print(f"第{attempt+1}次请求失败,等待{wait:.2f}秒重试") time.sleep(wait) raise RuntimeError("连续三次请求失败")

这里重试不是简单地死磕,而是加上退避时长,给对方网关一个喘息机会,也让你自己的请求序列显得更自然。

4.4 问题四:详情页拿到了HTML,但关键数据加载不出来

又有一种情况:页面本身返回200,也拿到了完整的HTML,可你要的数据不在里面。原因通常是对方用了异步加载,也就是首屏HTML只是一个壳,真实数据是浏览器执行JavaScript之后才渲染出来的。

严格来说这已经超出了“绕过自动化检测”的范畴,进入了动态渲染领域。但如果你非要处理,我有两种常规方案。一种是用无头浏览器渲染,加载量大但兼容好;另一种是分析网络请求,直接抓取后端接口。说一句掏心窝的话,能走接口就不走无头浏览器,效率至少快一个数量级。

用接口方案的时候,之前讲的头逻辑、Session逻辑照样适用,因为接口请求同样要带Cookie和会话标识。许多初学者绕了一圈才发现,真正想要的数据就藏在某个XHR请求里,用刚才的Session机制去访问那个请求,干净又快捷。

4.5 问题五:长时间运行后成功率越来越低

这是典型的漏斗现象。前期一切正常,越跑越慢,然后成功率从98%一路跌到40%。排除代码bug之后,最核心的原因是:你的请求密度在整个时间窗口上,已经超出了对方设定的“单IP累计阈值”。很多网站不只做即时频率检测,还会统计一个时间窗口内的累计访问量,比如一小时300次、一天2000次。

解决思路就两个字:降频。把单位时间内的请求总量降下来,同时拉长任务的运行时间。我通常会在一个批量采集任务里加入“主动暂停”机制,每抓满N个请求就休息10到20分钟:

MAX_REQUESTS_PER_BATCH = 200 REST_SECONDS = 600 request_count = 0 while has_next_page: # ... 采集逻辑 request_count += 1 if request_count % MAX_REQUESTS_PER_BATCH == 0: print(f"已连续抓取{request_count}条,进入休息窗口,时长{REST_SECONDS}秒") time.sleep(REST_SECONDS) request_count = 0

不要觉得暂停是浪费时间,稳定拿数据比强行拿数据重要得多。100个请求80个失败,不如40个请求40个成功。

5. 一文搞懂三个参数的配合关系

讲到这里,我发现不少人还停留在“有几个参数各设多少”的层面。其实更值钱的是理解它们之间如何联动。

如果把你的采集程序想象成一个人在图书馆里查资料,那么请求间隔就是“他翻书的节奏”,User-Agent轮换策略是“他的穿着打扮”,Session保持机制是“他是不是办了张借阅证”。你光把节奏调慢,但穿着怪异、又拒绝出示借阅证,图书馆管理员照样会盯上你。三者缺一不可。

我做了张简单的对照表,方便你在实际项目中快速定位问题:

现象可能原因对应调整方向
首轮请求就返回403UA特征异常/缺少关键头部检查UA池、补全Accept字段
前几十次正常,之后频繁失败频率累计超标拉大间隔,增加周期性休息
间歇性随机失败Session状态不一致统一会话复用,注意Referer链路
拿到页面但数据不全页面异步渲染改用接口请求或动态渲染方案
打开速度越来越慢对方限速或连接池挤占设置合理超时,限制连接池大小

这张表我自用了很久,每次排查问题基本都按这个思路走,效率挺高。它的价值不在于表格本身,而是把无头绪的调试过程变得有章法。

另外还有一点很关键:三个参数的优先级在不同阶段是不同的。程序刚上手时,首要任务是保证“入口页面能正常访问”,这时候Session初始化最重要;开始翻列表页了,要把请求间隔控住;等你跑到详情页时,UA的配合和Referer完整性就会浮现出来。别一上来就三管齐下乱调,那样只会让你分不清是哪一环出了问题。

6. 探索边界:这些参数还能怎么用

最后聊一点我自己的经验感悟。这三个参数表面上是采集程序的细节,但它们反映的其实是网络编程中的一个更普适的原则:尊重访问节奏,模拟真实行为,不拿机器思维去对抗人类设计的产品。

我现在写任何需要大量访问外部公开网页的工具,哪怕只是做一个自动化测试脚本,都会带着这三个参数的思维。因为测试环境里如果请求过快,同样会触发网关限流,导致测试结果失真。把间隔和头信息处理好,不仅是为了绕过某个检测,更是为了让我的程序在不同环境里都能稳定工作。

这里也想多说一句:参数能解决技术层面的问题,但解决不了需求层面的问题。如果某个业务需要高频访问一个公开网站,而且对方已经很明确地在反爬,那与其不断优化参数,不如先想想这个需求本身是否合理,有没有官方API或者其他数据源可以用。合规和可持续,永远排在技巧前面。

我之前带过一个小团队,当初就是太迷信“调参万能”,结果在某个项目上花了两周去研究各种细节,后来发现对方其实已经提供了结构化数据接口,虽然有一些调用限制,但足以满足业务需求,而那两周的调参工作基本白做了。从那以后,我给自己定了一个规矩:写任何采集逻辑之前,先花半天调研数据获取的合法渠道和频率限制,再决定要不要走浏览器模拟这条路。

回到那三个参数,如果你把它们当“银弹”,会走很多弯路;如果你把它们当成理解网络通信规律的角度,它们带来的价值会远超你的想象。做技术的人,最怕的就是埋头写代码不抬头看方向,而这几个参数恰恰给了我们一个从“能跑”走向“跑得稳”的观察窗口。

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

在线字典学习MATLAB实现:从稀疏编码到图像去噪

简介&#xff1a;这是一份基于MATLAB的在线字典学习实现代码&#xff0c;面向机器学习初学者和图像/信号处理方向的研究者&#xff0c;用于解决如何从序列数据中在线学习一组基字典的问题。与批处理方式不同&#xff0c;在线学习逐样本更新模型&#xff0c;适合内存有限或数据流…

作者头像 李华
网站建设 2026/10/21 5:27:01

图像分类全流程实战:从数据准备到模型部署的关键技术解析

图像分类大概是深度学习中门槛最低、但想真正做好又最不容易的一个方向。很多人第一次跑通手写数字识别之后&#xff0c;觉得分类任务不过如此&#xff0c;结果到了真实项目里&#xff0c;面对脏数据、类别不均衡、模型不收敛、过拟合、部署效果差这一连串问题&#xff0c;才发…

作者头像 李华
网站建设 2026/10/21 5:26:52

经典蓝牙和低功耗蓝牙的通信建立过程

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

作者头像 李华
网站建设 2026/10/21 5:26:28

自然语言驱动UI自动化:用Midscene替代XPath的实践与思考

在用 Midscene 做自然语言 UI 自动化之前&#xff0c;我大概有一年多的时间是跟 XPath 死磕过来的。当时接到的大部分测试任务其实没什么技术难度&#xff0c;无非是打开页面、点几个按钮、填几个表单、核对一下结果&#xff0c;可真正让人头大的反倒是“定位元素”这件事本身。…

作者头像 李华
网站建设 2026/10/21 5:26:15

JS逆向解析实战:从混淆代码到加密接口复现的完整指南

1. 拆解“JS逆向解析”到底在解决什么问题1.1 从一次真实需求说起去年帮一个做数据聚合的朋友处理过一个需求&#xff1a;他们需要定期从某个公开的行业信息平台上抓取一批商品价格数据&#xff0c;用于内部比价分析。听起来很简单对吧&#xff1f;但实际动手才发现&#xff0c…

作者头像 李华
网站建设 2026/10/21 5:25:43

算法公开,密钥保密:从AES到RSA的密码学基石

简介&#xff1a;围绕网络安全课程设计的加密技术资料包&#xff0c;聚焦加密算法原理与编程实现&#xff0c;主要面向高校信息安全、网络工程及密码学相关专业的学生&#xff0c;也适合需要借助具体案例快速理解经典算法的初级开发者。内容以RSA等经典加密算法的原理分析、课程…

作者头像 李华