構(gòu)解析到實戰(zhàn) UA 池與輪換技巧)
1. 從一個不起眼的字符串說起為什么我們需要認識 User Agent如果你做過爬蟲、寫過接口自動化測試、或者只是單純在瀏覽器里按過 F12 看過 Network 面板那你一定見過那一長串看起來像亂碼的字符串——Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36。這就是User Agent簡稱 UA。它本質(zhì)上就是客戶端在發(fā)起 HTTP 請求時主動貼在腦門上的一張“自我介紹便簽”告訴服務(wù)端“我是誰、我來自哪里、我大概能干什么”。很多人第一次接觸 UA 是因為遇到了“同一個頁面瀏覽器打開正常代碼請求卻返回一堆亂碼或者直接 403”。這背后的核心原因往往就是服務(wù)端根據(jù) UA 做了內(nèi)容協(xié)商或者訪問控制。UA 能做的事情遠比想象中多它決定了服務(wù)端返回桌面版還是移動版頁面、決定是否觸發(fā)反爬策略、影響 CDN 緩存命中、甚至影響某些前端庫的兼容性分支??梢哉fUA 是客戶端與服務(wù)端之間最廉價、最普遍、也最容易被忽視的“身份憑證”。這篇文章適合三類人看第一類是剛?cè)腴T爬蟲和數(shù)據(jù)采集的朋友經(jīng)常被 UA 卡住卻不知道從哪下手第二類是做前端兼容和自動化測試的工程師需要模擬不同設(shè)備環(huán)境第三類是對 HTTP 協(xié)議細節(jié)感興趣、想把“知其所以然”補齊的開發(fā)者。我會從 UA 的結(jié)構(gòu)講起把常見 UA 拆開揉碎再給出可直接復(fù)用的 UA 列表、構(gòu)造方法和實戰(zhàn)避坑經(jīng)驗。讀完你至少能做到看到一串 UA 能立刻判斷出瀏覽器內(nèi)核、操作系統(tǒng)、設(shè)備類型并且知道在什么場景下該用哪一類 UA。2. User Agent 的結(jié)構(gòu)拆解一串字符里到底藏了多少信息2.1 UA 的歷史包袱與字段構(gòu)成UA 字符串之所以看起來又長又亂是因為它背負了三十年的歷史包袱。最早的瀏覽器叫 Mosaic后來 Netscape 的瀏覽器代號是 Mozilla為了兼容只認 Mozilla 的服務(wù)器后來的瀏覽器紛紛在 UA 開頭加上Mozilla/5.0來“偽裝”自己。這個傳統(tǒng)一直延續(xù)到今天所以你會看到 Chrome、Edge、Safari 的 UA 全都以Mozilla/5.0開頭這純粹是歷史遺留的兼容性妥協(xié)跟 Mozilla 本身已經(jīng)沒什么關(guān)系了。一個典型的現(xiàn)代 UA 大致由以下幾段組成用空格和括號分隔Mozilla/5.0歷史兼容前綴幾乎所有主流瀏覽器都保留。(操作系統(tǒng)標識; 加密等級標識; 瀏覽器語言)括號內(nèi)是平臺信息比如Windows NT 10.0; Win64; x64表示 64 位 Windows 10。AppleWebKit/537.36渲染引擎標識WebKit 系內(nèi)核的通用標記。(KHTML, like Gecko)又一處歷史兼容標記表示“我像 Gecko 一樣渲染”。Chrome/120.0.0.0真正的瀏覽器名稱和版本號。Safari/537.36為了兼容 Safari 檢測而保留的尾巴。理解這個結(jié)構(gòu)之后你就能像讀身份證一樣讀 UA 了。比如看到iPhone; CPU iPhone OS 17_0就知道是 iOS 17 的 iPhone看到Android 13; Pixel 7就知道是安卓 13 的某款設(shè)備。這種“逐段解析”的能力是后面所有實戰(zhàn)操作的基礎(chǔ)。2.2 主流瀏覽器 UA 的差異對比不同瀏覽器廠商在 UA 里塞的東西并不一樣這直接影響了服務(wù)端的判斷邏輯。我整理了一張對比表把幾個主流桌面瀏覽器的 UA 關(guān)鍵字段列出來方便你快速對照瀏覽器內(nèi)核標識典型版本字段特殊標記ChromeAppleWebKit/537.36Chrome/120.0.0.0無EdgeAppleWebKit/537.36Edg/120.0.0.0注意是Edg不是EdgeFirefoxGecko/20100101Firefox/121.0不含 AppleWebKitSafariAppleWebKit/605.1.15Version/17.0含 Safari/605.1.15這里有個非常容易踩的坑Edge 的 UA 里寫的是Edg/而不是Edge/。早期 Edge 用的是Edge/后來為了和某些老檢測邏輯區(qū)分改成了Edg/。如果你寫正則去匹配 Edge用Edge會漏掉一大批新版本。同理Firefox 的 UA 里根本沒有AppleWebKit如果你用“是否包含 AppleWebKit”來判斷是不是現(xiàn)代瀏覽器Firefox 會被誤判。這些細節(jié)在寫兼容邏輯時都是實打?qū)嵉目印?.3 移動端 UA 的識別要點移動端 UA 比桌面端更復(fù)雜因為設(shè)備碎片化嚴重。但抓住幾個關(guān)鍵詞就能覆蓋絕大多數(shù)情況iPhone包含iPhone系統(tǒng)字段形如CPU iPhone OS 17_0 like Mac OS X。iPad包含iPad注意 iPadOS 13 之后默認請求桌面版 UA需要額外處理。Android 手機包含Android和Mobile比如Android 13; Pixel 7 Build/...。Android 平板包含Android但通常不含Mobile這是區(qū)分手機和平板的關(guān)鍵。微信內(nèi)置瀏覽器包含MicroMessenger這個標記在做微信生態(tài)適配時極其重要。提示判斷移動端時不要只匹配Mobile一個詞。有些安卓平板 UA 里也會出現(xiàn)Mobile穩(wěn)妥做法是結(jié)合Android和屏幕尺寸信息綜合判斷。3. 常見 User Agent 實戰(zhàn)清單可直接抄作業(yè)的 UA 庫3.1 桌面端高頻 UA 推薦在實際做數(shù)據(jù)采集時最省事的做法是維護一個 UA 池每次請求隨機挑一個。下面這些是我實測下來比較穩(wěn)定、不容易被識別為異常的桌面 UA你可以直接拿去用DESKTOP_UA_POOL [ # Chrome on Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, # Chrome on macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, # Firefox on Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0, # Safari on macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15, # Edge on Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0, ]選這些 UA 的邏輯是它們都是當(dāng)前主流版本覆蓋面廣且版本號不會太舊。版本號太舊是常見失誤——你用一個 Chrome 80 的 UA 去請求服務(wù)端一看就知道這是“老古董”很容易觸發(fā)風(fēng)控。所以 UA 池需要定期更新建議每季度檢查一次主流版本號。3.2 移動端 UA 與設(shè)備模擬移動端采集或者做響應(yīng)式測試時需要模擬具體設(shè)備。下面這組覆蓋了 iOS、Android、微信等高頻場景MOBILE_UA_POOL [ # iPhone Safari Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1, # Android Chrome Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36, # 微信內(nèi)置瀏覽器 Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.44, # Android 平板 Mozilla/5.0 (Linux; Android 13; SM-X700) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, ]這里要特別說明微信 UA 的用法。微信內(nèi)置瀏覽器的 UA 里帶MicroMessenger很多做微信分享、H5 頁面適配的邏輯都依賴這個標記。如果你要測試“在微信里打開是什么效果”就必須把 UA 換成帶MicroMessenger的否則服務(wù)端會返回普通瀏覽器版本測出來的結(jié)果完全不對。3.3 特殊場景 UA搜索引擎與爬蟲標識除了瀏覽器還有一類 UA 是搜索引擎爬蟲和自動化工具的。這類 UA 的特點是“自報家門”比如GooglebotMozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)BingbotMozilla/5.0 (compatible; bingbot/2.0; http://www.bing.com/bingbot.htm)通用爬蟲python-requests/2.31.0、curl/8.4.0、Go-http-client/1.1這里有個關(guān)鍵認知用python-requests這種默認 UA 去請求等于直接告訴服務(wù)端“我是腳本”。絕大多數(shù)有風(fēng)控的站點會第一時間攔截。所以做采集時第一件事就是把默認 UA 換掉。反過來如果你自己寫服務(wù)端想識別爬蟲也可以從這些默認 UA 入手做基礎(chǔ)過濾。4. 動手實操構(gòu)造、解析與輪換 UA 的完整流程4.1 用 Python 構(gòu)造和發(fā)送自定義 UA最基礎(chǔ)的用法是在請求頭里手動指定 UA。以requests庫為例import requests headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept-Language: zh-CN,zh;q0.9,en;q0.8, } resp requests.get(https://example.com, headersheaders, timeout10) print(resp.status_code)注意我同時加了Accept-Language。只改 UA 不改其他頭是很容易被識破的。因為一個真實的 Chrome 請求除了 UA 還會帶Accept、Accept-Language、Accept-Encoding、Connection等一系列頭。如果你的請求只有 UA 像瀏覽器其他頭都是 requests 默認值風(fēng)控系統(tǒng)一眼就能看出破綻。所以正確的做法是“成套偽裝”把常用請求頭一起補上。4.2 用正則解析 UA 提取關(guān)鍵信息有時候我們需要反過來從一串 UA 里提取瀏覽器、系統(tǒng)、設(shè)備信息。用正則是最直接的方式import re def parse_ua(ua: str) - dict: result {browser: Unknown, os: Unknown, device: Desktop} # 瀏覽器識別注意順序Edge 要在 Chrome 之前判斷 if Edg/ in ua: result[browser] Edge elif Firefox/ in ua: result[browser] Firefox elif Chrome/ in ua: result[browser] Chrome elif Safari/ in ua: result[browser] Safari # 系統(tǒng)識別 if Windows NT in ua: result[os] Windows elif Mac OS X in ua: result[os] macOS elif Android in ua: result[os] Android elif iPhone in ua or iPad in ua: result[os] iOS # 設(shè)備類型 if Mobile in ua or iPhone in ua: result[device] Mobile elif iPad in ua or (Android in ua and Mobile not in ua): result[device] Tablet return result ua Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0 print(parse_ua(ua)) # {browser: Edge, os: Windows, device: Desktop}這段代碼里最關(guān)鍵的是判斷順序。Edge 的 UA 里同時包含Chrome/和Edg/如果你先判斷 ChromeEdge 就會被誤判成 Chrome。同理很多國產(chǎn)瀏覽器 UA 里也帶Chrome/需要根據(jù)額外標記區(qū)分。這個“先特殊后一般”的判斷順序是寫 UA 解析邏輯的鐵律。4.3 構(gòu)建可輪換的 UA 中間件在規(guī)?;杉瘯r單個 UA 反復(fù)請求同一個站點很容易被限流。這時候需要 UA 輪換。下面是一個簡單的輪換中間件思路import random class UARotator: def __init__(self, ua_pool): self.ua_pool ua_pool self._last_ua None def get(self): # 避免連續(xù)兩次拿到同一個 UA candidates [ua for ua in self.ua_pool if ua ! self._last_ua] ua random.choice(candidates) self._last_ua ua return ua rotator UARotator(DESKTOP_UA_POOL) for _ in range(3): print(rotator.get()[:60], ...)這個實現(xiàn)里我加了一個“避免連續(xù)重復(fù)”的小邏輯。原因是如果隨機池里只有 5 個 UA純隨機很容易連續(xù)兩次抽到同一個而連續(xù)相同 UA 的請求模式反而更可疑。這個細節(jié)在常規(guī)教程里很少提但實測下來對降低觸發(fā)風(fēng)控的概率有幫助。5. 常見問題與排查技巧實錄5.1 UA 相關(guān)的典型報錯與解決思路做采集和接口調(diào)試時跟 UA 相關(guān)的問題主要集中在下面幾類。我整理成速查表遇到問題可以直接對照現(xiàn)象可能原因排查與解決返回 403 ForbiddenUA 被識別為腳本換成主流瀏覽器 UA補齊其他請求頭返回內(nèi)容為移動版UA 被判定為移動設(shè)備檢查 UA 是否含 Mobile換成桌面 UA返回亂碼或空內(nèi)容服務(wù)端按 UA 返回了不同編碼檢查響應(yīng)頭 Content-Type確認 UA 與預(yù)期一致頁面元素定位失敗服務(wù)端返回了不同版本頁面固定 UA確保每次請求環(huán)境一致登錄態(tài)頻繁失效UA 變化導(dǎo)致會話校驗失敗同一會話內(nèi)保持 UA 不變這里重點說“登錄態(tài)失效”這一條。很多站點的會話校驗會把 UA 作為指紋的一部分如果你在同一個會話里換了 UA服務(wù)端會認為“換人了”直接踢掉登錄態(tài)。所以UA 輪換只適合無狀態(tài)請求涉及登錄的會話必須固定 UA。這個坑我在早期做自動化時踩過排查了大半天才定位到是 UA 變了。5.2 那些文檔里不會寫的避坑經(jīng)驗第一個經(jīng)驗不要迷信“最新版本 UA 最好”。有些站點的風(fēng)控規(guī)則是“只允許最近 N 個版本”你用一個剛發(fā)布沒幾天的版本號反而可能因為規(guī)則庫還沒更新而被攔。穩(wěn)妥做法是用“當(dāng)前主流版本往前推一到兩個大版本”比如現(xiàn)在主流是 120你用 118 或 119 通常更安全。第二個經(jīng)驗UA 要和 IP、時區(qū)、語言保持一致。如果你用美國 IP卻配一個zh-CN的語言頭和中文系統(tǒng) UA這種“地理矛盾”很容易被識別。做海外采集時UA 里的系統(tǒng)語言、請求頭的Accept-Language、出口 IP 的地理位置三者最好能對上。第三個經(jīng)驗移動端 UA 不要隨便混用。比如你用一個 iPhone 的 UA但請求頭里Accept寫的是桌面瀏覽器的值或者屏幕分辨率參數(shù)對不上也會露餡。真要做移動端模擬建議直接用成熟的設(shè)備模擬方案把 UA、視口、觸摸事件等一整套都配齊而不是只改一個 UA 字符串。注意UA 只是客戶端指紋的一部分。現(xiàn)代風(fēng)控還會看 TLS 指紋、Canvas 指紋、鼠標軌跡等。UA 能解決大部分“低級攔截”但面對高級風(fēng)控單靠 UA 是不夠的。認清這一點能幫你少走很多彎路。5.3 服務(wù)端視角如何正確使用 UA 做判斷如果你站在服務(wù)端想用 UA 做設(shè)備適配有幾點建議。首先優(yōu)先用響應(yīng)式設(shè)計和特性檢測而不是 UA 判斷。UA 判斷是出了名的脆弱瀏覽器版本一更新、UA 一改你的判斷邏輯就可能失效。其次如果非要用 UA一定要做“優(yōu)雅降級”——判斷不出來時返回通用版本而不是直接報錯。最后不要把 UA 當(dāng)作安全邊界。UA 是客戶端可以隨意偽造的任何基于 UA 的“權(quán)限控制”都是紙糊的真正的安全校驗必須放在服務(wù)端會話和令牌層面。6. 關(guān)于 UA 的一些個人體會我做了這么多年采集和自動化UA 這個看似最簡單的東西反而是最容易被低估的。新手往往覺得“隨便填一個就行”結(jié)果卡在 403 上半天找不到原因老手則容易過度依賴 UA 池忽略了請求頭一致性、會話固定這些更本質(zhì)的問題。我的建議是把 UA 當(dāng)成整個請求指紋體系的一環(huán)來對待而不是孤立的一個字段。維護一個定期更新的 UA 池配合一致的請求頭、合理的請求頻率基本能覆蓋 80% 的常規(guī)場景。剩下那 20% 的硬骨頭靠的是對目標站點行為的細致觀察而不是堆砌更多的 UA。這個內(nèi)容后續(xù)還可以往“客戶端指紋體系”方向擴展把 TLS、Canvas、字體列表這些維度串起來看會更有意思。