12306 搶票系列之只要搞定RAIL_DEVICEID的來源,從此搶票不再掉線(上)

鄭重聲明:
本文僅供學習使用,禁止用於非法用途,否則後果自負,如有侵權,煩請告知刪除,謝謝合作!

開篇明義

本文針對自主開發搶票腳本在搶票過程中常常遇到的請求無效等問題,簡單分析了 12306 網站的前端加密算法,更準確的說,是探究 RAIL_DEVICEID 的生成過程.

因爲該 cookie 值是搶票請求的核心基礎,沒有它將無法正確發送請求,或者一段時間後就會到期失效需要重新獲取,或者明明更改了瀏覽器用戶代理(navigator.userAgent)標識卻還是被限制訪問…

因爲它並不是真正的客戶端標識,只是迷惑性戰術,瀏覽器唯一標識其實是 RAIL_OkLJUJ 而它卻被 12306 網站設計者故意沒有添加到 cookie ,因此造成了很強的欺騙性,編程真的是一門藝術!

你以爲你的爬蟲已經可以正常模仿瀏覽器,殊不知,只要沒搞懂誰纔是真正的瀏覽器標識,那麼再怎麼換馬甲也難逃造假事實.

12306-algorithm-web-js-index-cookie-id.png

上圖展示了 RAIL_OkLJUJ 的存在位置,可能是爲了兼容市面上絕大數瀏覽器,也可能是爲了聯合各種前端緩存技術作爲特徵碼,總是除了 cookie 之外,RAIL_OkLJUJ 存在於 Local Storage , Session Storage , IndexedDBWeb SQL 等.

值得注意的是,cookie 中故意沒有設置 RAIL_OkLJUJ ,如果清空全部緩存後再次刷新網頁,你就會發現 RAIL_DEVICEID 已經發生變化了而 RAIL_OkLJUJ 依舊沒變!

12306-algorithm-web-js-index-cookie-RAIL_DEVICEID.png

下面簡單驗證一下說明誰纔是真正的瀏覽器唯一標識:

  • step 1 : 複製當前獲取到的 RAIL_DEVICEIDRAIL_OkLJUJ 的值

打開控制檯(Console),通過 js 代碼方式取出本地存儲(localStorage) 的值:

localStorage.getItem("RAIL_DEVICEID");

localStorage.getItem("RAIL_OkLJUJ");

控制檯會立即返回該值,接下來需要手動複製到其他地方等待和第二次結果作比較.

但是程序員總是喜歡能偷懶就偷懶,手動複製也懶得複製怎麼辦?

當然,繼續使用js 代碼複製了啊!

copy('雪之夢技術驛站歡迎您的訪問,https://snowdreams1006.cn');

比如這句代碼就會把文本'雪之夢技術驛站歡迎您的訪問,https://snowdreams1006.cn'複製到剪貼板,接下來選擇文本編輯器右鍵粘貼就能看到效果啦!

所以改造一下代碼就能複製第一次訪問 12306 網站獲取到的 RAIL_DEVICEIDRAIL_OkLJUJ 的值.

12306-algorithm-web-js-index-copy-cookie-id.png

copy("RAIL_DEVICEID:::"+localStorage.getItem("RAIL_DEVICEID"));
// RAIL_DEVICEID:::E5BDkKrPkZ6nuZruqUj9-3lUG1LBM7t9aTDbZwFSdrboaFG6odrWZ9yuphnas4Jwq5E_FXIwwqlRoSXFbJULUiBNwNGt61Ow6Zv0GFXRABipaeDJJ0Ub7G2g_B_aGwMF5DNZ5KJR4eWVl-P3zSHGKbczLB3WN0z-

copy("RAIL_OkLJUJ:::"+localStorage.getItem("RAIL_OkLJUJ"));
// RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI
  • step 2 : 等待 5 min 後再次獲取 RAIL_DEVICEIDRAIL_OkLJUJ 的值
copy("RAIL_DEVICEID:::"+localStorage.getItem("RAIL_DEVICEID"));
// RAIL_DEVICEID:::VUye37EEUdGHgrpJGo9J95hWMNSIUFPeYBjabDgCiYJbQIr53iVzIPQJwcLhbijL4OyPVGmzolsVEK8Pw7_DG_oPrUDpfbnRe7HvMWMJvU2MAbk-7EwNEePAlpnVb9QVZz4dtOUSCRVbS2zlwgS0xe2BOThpR9oy

copy("RAIL_OkLJUJ:::"+localStorage.getItem("RAIL_OkLJUJ"));
// RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI

或者清空網站 cookie 後再次刷新當前網頁,總之就是想辦法觸發瀏覽器再次運行相關邏輯重新生成 RAIL_DEVICEIDRAIL_OkLJUJ .

  • step 3 : 對比第一次和第二次獲取到的 RAIL_DEVICEIDRAIL_OkLJUJ 的值
RAIL_DEVICEID:::E5BDkKrPkZ6nuZruqUj9-3lUG1LBM7t9aTDbZwFSdrboaFG6odrWZ9yuphnas4Jwq5E_FXIwwqlRoSXFbJULUiBNwNGt61Ow6Zv0GFXRABipaeDJJ0Ub7G2g_B_aGwMF5DNZ5KJR4eWVl-P3zSHGKbczLB3WN0z-

RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI

RAIL_DEVICEID:::VUye37EEUdGHgrpJGo9J95hWMNSIUFPeYBjabDgCiYJbQIr53iVzIPQJwcLhbijL4OyPVGmzolsVEK8Pw7_DG_oPrUDpfbnRe7HvMWMJvU2MAbk-7EwNEePAlpnVb9QVZz4dtOUSCRVbS2zlwgS0xe2BOThpR9oy

RAIL_OkLJUJ:::FGFOJ75VdD8dQc2yh3yTJf2RBWES6uGI

顯而易見,肉眼直接就能看出兩次請求時 RAIL_OkLJUJ 的值並沒有變化而 RAIL_DEVICEID 的值很大可能會發生改變.

因此,RAIL_DEVICEID 應該並不是瀏覽器唯一標識,而 RAIL_OkLJUJ 纔是真正的唯一標識!

本文並不適合全部讀者,如果你屬於以下情況之一,那麼本文對你絕對幫助甚多,否則對你來說只能算是浪費生命.

  • 適合對自主搶票或者腳本搶票有需求的天涯遊子
  • 適合擁有一定 web 前端開發相關知識的開發者
  • 適合耐得住寂寞能夠獨自研究加密算法的孤獨人

最後的核心前提是有網,當然WiFi更佳,否則流量真的吃不消啊!

故事背景

獨在異鄉爲異客 每逢佳節要搶票
手動自動一起上 時常掉線心好傷
動手實踐出真理 原來身份是唯一
想要封你沒商量 只能動手來僞裝
加密請求在前端 後端返還控制權
還原算法改身份 穩定搶票不擔心
多種途徑齊上陣 車票速速快現身

不知道你是否遭遇過一票難求的困境,儘管網絡上關於第三方工具的加速包是否加速有過闢謠,但是每逢節假日總是會遇到搶不到車票的問題,大部分人還是會選擇買個心理安慰吧!

目前爲止,12306 官方線上售票渠道僅僅包括 12306 網站以及手機 app 客戶端,因此市面上流行的第三方搶票軟件均爲非正常途徑,而這些第三方渠道中最簡單的實現方式應該就算是爬蟲技術了.

不論是網頁端還是手機端,統統稱爲客戶端,客戶端的作用僅僅是傳聲筒,真正負責執行命令的人就是服務端.

當你提交購票需求時,客戶端會把這些車票信息一起打包發送給服務端,如果服務端有票的話,那麼有可能就會返回給客戶端成功信息,恭喜你訂票成功.

但是儘管有票也不一定會給你,唯一確定的是無票一定會失敗,總之不管結果如何服務端和客戶端總是按照既定的約定協議在默默交流着…

儘管官方渠道最可靠也最準確,可官方也還是沒能給你買到車票啊!

所以想要搶票還是得親自動手,不能完全依靠官方,這裏就誕生了爬蟲技術來冒充客戶端,想要成功騙過服務端就要先了解真正的客戶端到底有哪些特徵?

由於本文篇幅有限,暫時不做關於搶票方面的相關論述,直奔重點,講解 RAIL_DEVICEID 的請求過程,帶你一步一步還原 12306 網站的前端加密算法的實現邏輯!

效果預覽

在瀏覽器控制檯運行 chromeHelper.prototype.encryptedFingerPrintInfo() 方法時會計算真實瀏覽器信息,如果發現計算結果中的 value 值和真正請求 https://kyfw.12306.cn/otn/HttpZF/logdevicehashcode 值相同,那麼恭喜您,說明 12306 相關算法還沒更新,如果不相同估計算法又稍微調整了!

事實證明,12306 算法雖然在變但都是小打小鬧,根本沒有傷筋動骨,所以自己動手改改又能滿血復活了喲!

{
  "key": "&FMQw=0&q4f3=zh-CN&VPIf=1&custID=133&VEek=unknown&dzuS=0&yD16=0&EOQP=c227b88b01f5c513710d4b9f16a5ce52&jp76=52d67b2a5aa5e031084733d5006cc664&hAqN=MacIntel&platform=WEB&ks0Q=d22ca0b81584fbea62237b14bd04c866&TeRS=777x1280&tOHY=24xx800x1280&Fvje=i1l1o1s1&q5aJ=-8&wNLf=99115dfb07133750ba677d055874de87&0aew=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36&E3gR=9f7fa43e794048f6193187756181b3b9",
  "value": "owRJc8M4EkFMvcTkzibRFJoDSkUKCx6N9ictZIJLIeY"
}
  • step 1 : 使用 Chrome 瀏覽器打開 12306 網站並清空該站點全部緩存數據.

請確保當前正在使用的是谷歌 Chrome 瀏覽器,IE和 firefox 等瀏覽器暫未測試.

12306-algorithm-web-js-website-clear-storage.png

  • step 2 : 手動清空 window.name 屬性,保證瀏覽器處於首次打開 12306 網站狀態.

因爲非首次加載會攜帶上一次的請求信息,不方便學習驗證,經過分析試驗發現歷史狀態還保存在 window 對象的 name 屬性,因此僅僅清空緩存還不夠,還需要手動清空 name 屬性的值.

12306-algorithm-web-js-website-clear-name.png

  • step 3 : 強制刷新當前頁面並保持記錄請求信息,過濾請求類型 js ,找到 /otn/HttpZF/logdevice 請求.

在找到該請求保存查詢參數名爲 hashCode: owRJc8M4EkFMvcTkzibRFJoDSkUKCx6N9ictZIJLIeY ,方便和之後的計算方式生成的結果做對比.

12306-algorithm-web-js-website-find-logdevice.png

除了查詢請求信息外,更爲重要的是查看響應信息,當初次請求 /otn/HttpZF/logdevice 時除了返回過期時間 expdfp 設備信息之外,還會返回 cookieCode 設備唯一標識.

如果等到過期時間或手動清空站點緩存後,/otn/HttpZF/GetJS 腳本中的相關邏輯會再次發起 /otn/HttpZF/logdevice 請求,那時候的響應內容再也沒有 cookieCode 參數了.

讓我們再好好看一看初次請求的響應信息吧!

callbackFunction('{"exp":"1581948102442","cookieCode":"FGHcXsVmjf3oV0zm5qTDPFt-VcNhuDA-","dfp":"QNCYH1J5E9M7rl97uo_PUR1OSwRTcCe1xdnbX7h2V6Ewcq6kML0qzXD5y11rLv3FPX1ndOnhL_bjVkwwgtWTsHMFums60_4H9Lr-vJzJGq4tkaUEGfRNXN9IJlvptReSBa5PP7N5gxpSOBo-YlF5Ac98f-YlNlxi"}')

如果將 callbackFunction() 回調函數去掉,不難發現其實返回數據是 json 格式,格式化後發現響應內容如下:

{
    "exp": "1581948102442",
    "cookieCode": "FGHcXsVmjf3oV0zm5qTDPFt-VcNhuDA-",
    "dfp": "QNCYH1J5E9M7rl97uo_PUR1OSwRTcCe1xdnbX7h2V6Ewcq6kML0qzXD5y11rLv3FPX1ndOnhL_bjVkwwgtWTsHMFums60_4H9Lr-vJzJGq4tkaUEGfRNXN9IJlvptReSBa5PP7N5gxpSOBo-YlF5Ac98f-YlNlxi"
}

這裏不得不佩服 12306 的設計思路了,故佈疑陣,當你誤以爲自己已經更新了 RAIL_DEVICEID 的值,實際上 cookieCode 的值纔是唯一標識而它恰恰沒有設置到 cookie 中去,僅僅作爲本地緩存保持了,用於再次請求 RAIL_DEVICEID.

12306-algorithm-web-js-website-cache-OkLJUJ.png

  • step 4 : 複製源碼實現到控制檯,輸入 chromeHelper.prototype.encryptedFingerPrintInfo() 獲取請求 /otn/HttpZF/logdevice 的查詢參數,提取出其中的 value 值和真正的請求參數作對比.

假設真正請求參數 hashcode 的值已設置成變量,chromeHelper.prototype.encryptedFingerPrintInfo().value === hashcode 返回結果 true 說明覆現算法實現還在正常運行,否則很可能是相關算法又更新了!

12306-algorithm-web-js-website-generate-compare.png

直奔重點

如果你正在學習自動搶票或者打算研究如何自動搶票,那麼我可以負責任得告訴你,RAIL_DEVICEID 的值絕對是繞不過去的坎,堪稱 12306 反爬蟲技術的最精華手段!

現在目標已經鎖定,趕緊動手和我一起去探究 12306 到底是如何處理 RAIL_DEVICEID 的值吧!

無痕模式下訪問網站

衆所周知,谷歌 Chrome 瀏覽器是程序員專屬的瀏覽器,是因爲提供了強大的開發調試能力,簡單網站請求甚至根本不需要藉助第三方專業的抓包工具就能獨立完成分析整過程.

如果你還沒有聽說過 Chrome 瀏覽器或者正在使用其他瀏覽器,那麼建議你先自行下載最新版 Chrome 瀏覽器,和文章使用一樣的工具有助於順利復現相關步驟,否則遇到莫名奇怪的問題只能自己研究了.

首先打開 Chrome 瀏覽器的無痕模式,處於無痕模式最大的特點就是不會保存 cookie,在一定程度上對目標網站而言是新用戶(主要指的是新的客戶端終端).

12306-algorithm-web-js-non-trace-mode.png

輸入 12306 官網後,打開開發者控制檯(F12或右鍵檢查),選擇網絡(network)選項卡,確保一直處於監聽網咯請求並實時記錄狀態.

具體而言,最左邊的監聽狀態圓心是紅色,保持日誌(Preserve log)的複選框已勾選,禁用緩存(Disable cache) 的複選框已勾選,這三者是分析所有網絡請求的基礎.

12306-algorithm-web-js-network-listen.png

準備工作就緒後開始完整走一遍購票流程,即從首頁進入登錄頁,登錄並買票等過程,請求步驟越完整可提供分析的資料越多,也就基本上不會遺漏重要步驟,離真相越逼近.

12306-algorithm-web-js-query-ticket.png

凡是涉及到登錄操作,建議先故意輸出錯誤的賬號密碼等信息,這樣有利於登錄成功後重定向次數過多而導致無法找到之前的登錄請求,如果網絡(network)選項卡中的保持日誌(Preserve log)的功能沒有開啓的話,這一現象將會更加嚴重!

12306-algorithm-web-js-login-wrong.png

再次輸入正確的登錄信息成功登錄後進行買票行爲等操作,但是無需付款,只要正常操作到下單完成即可視爲整個購票流程.

12306-algorithm-web-js-purse-ticket.png

12306-algorithm-web-js-order-ticket.png

下單成功後整個購票流程已經基本完成,接下來開始全局搜索關鍵字 RAIL_DEVICEID 查看在哪裏生成又在何處使用?

全局模糊查找關鍵字

現在整個購票流程基本上已經完成,接下來開始全局搜索全部請求中是否包含關鍵字 RAIL_DEVICEID 吧!

首先打開網絡(network)選項卡,從左往右數第四個放大鏡圖標就是搜索功能,輸入搜素關鍵字 RAIL_DEVICEID 會過濾符合條件的網絡請求.

12306-algorithm-web-js-network-search.png

不搜不要緊,一搜一大把,只能看出來大部分網絡請求都會自動攜帶該 cookie,反而淹沒了到底是哪個網絡請求生成的 cookie?

12306-algorithm-web-js-network-search-result.png

所以必須想辦法精確搜索,過濾出生成該 cookie 的網絡請求,所以接下來的問題就變成了如果 RAIL_DEVICEID 屬於後端直接設置的行爲,那麼這樣的網絡請求應該長啥樣的?

最好的學習就是模仿,假設並不知道真實的設置過程如何,但是我們可以查看其它 cookie 的設置過程啊!

同樣地,在網絡(network)選項卡選擇第三個過濾器漏斗圖標,展開網絡請求類型,大致分爲 All|XHR|JS|CSS|Img|Media|Font|Doc|WS|Manifest|Other等類型.

簡單說一下網絡請求類型的相關含義,整理出表格直觀感受一下:

類型 名稱 描述 代碼
XHR XHR adn Fetch ajax異步請求 X-Requested-With: XMLHttpRequest
JS Scripts js腳本 Sec-Fetch-Dest: script
CSS Stylesheets css樣式 Sec-Fetch-Dest: style
Img Images 圖片 Sec-Fetch-Dest: image
Media Media 音視頻媒體 Sec-Fetch-Dest: audio
Font Fonts 字體 Sec-Fetch-Dest: font
Doc Documents html文檔 Sec-Fetch-Dest: document
WS WebSockets 長連接通信 暫無
Manifest Manifest 版本文件 暫無

由於 12306 暫未包括後兩種請求類型,所以無法判斷該請求有什麼特點,除了 ajax 異步請求外,其餘類型的網絡請求都是通過請求頭 Sec-Fetch-Dest 屬性標識的,當然設置瀏覽器的 cookie 也不例外,只不過大多數是通過服務端進行設置的,也就是網絡請求的響應頭標誌瞭如何設置 cookie 的行爲.

在前端 web 開發的過程中並不是一上來就前後端分離的,很長一段時間內前端頁面也是由後端人員完成的,因此好多網站至今爲止還保留着新舊交替的痕跡.

在上述網絡請求類型中,最能體現這種變化特點就是 XHR 和 Doc 請求,XHR的常見封裝實現 之一就是風靡全球的 ajax 異步請求,用於實現無刷新局部更新網頁內容,而 Doc 是文檔類型,無論是直接輸出原生 html 還是使用模板技術動態渲染頁面,最終輸出展現結果一律是 html 文檔,這一類的網絡請求最容易設置 cookie 之類的請求,體現了上一代技術的一貫風格,恨不得一個人一次性把全部的活都幹完!

但是隨着技術的發展進步舊技術暴露的問題越來越多,引起了包括開發者在內的業內重視,各大企業已經逐步開始轉變,也就是各司其職,物盡其用.

總結來說,XHR 和 Doc 有如下特點:

  • XHR 請求的數據絕大多數工作是在前端方面完成的,後端把相關數據返回給前端接口調用者,前端取到數據後進行業務組裝展現.
  • XHR 請求絕大多數是異步ajax 請求,優點是當前頁面不需要刷新就能看到最新內容,缺點是一旦涉及到相互依賴的業務就會出現請求等待噩夢.
  • XHR 請求是又前端發起也就是瀏覽器主動發出給後端,等後端服務器返回數據後繼續由前端完成相關業務,這部分數據傳輸量極少但非常重要.
  • Doc 請求大多數是後端在控制,方便設置各種頁面元素的表現形式,但是也不排除前端使用相關的模板引擎結合 XHR 數據在控制生成文檔.
  • Doc 請求設置包括 cookie 在內的一系列網絡行爲,轉發和重定向更是權限控制的常用做法.

下面我們已包括 RAIL_DEVICEID 關鍵字的網絡請求,簡單感受一下兩者的差異性.

XHR 請求重點在於如何請求數據和接收數據,主要體現在 Request Data 和 Response Data 兩方面,至於請求頭一般都是默認設置.

12306-algorithm-web-js-network-search-result-xhr.png

Doc 請求的重點就不一樣了,絕大多數請求就是輸入網址後自動跳轉頁面,因而關注的重點應該放在請求頭和響應頭信息上,因爲 cookie 的值就是通過請求頭進行發送到後端服務器,後端如需新增或修改 cookie 值就是通過響應頭進行設置的.

12306-algorithm-web-js-network-search-result-doc.png

柿子還要先捏軟柿子,現在無法判定 RAIL_DEVICEID 到底是服務端直接設置還是客戶端自行設置的,而客戶端的行爲不太直觀,所以相對而言還是先捏服務端軟柿子吧!

回顧剛纔講解的 Doc 網絡請求,不難發現設置 cookie 的行爲代碼類似如下:

Set-Cookie: JSESSIONID=D4CE095F5A21B38DF3389070F1E01FE6; Path=/otn

現在找到了學習對象,開始模仿查找類似請求的關鍵字應該是: Set-Cookie: RAIL_DEVICEID=

12306-algorithm-web-js-network-search-cookie-RAIL_DEVICEID.png

查無結果!

一般情況下出現無結果很可能是以下原因之一:

  • 恭喜您,真的查無結果,可以換條思路繼續探索了.
  • 很遺憾,當前網絡請求數據不足剛好缺失符合條件的請求.
  • 日了狗,操作不當誤輸多餘符號或者本是關鍵字搜索實際上卻開啓了正則匹配等

所以逐一排查以上原因,首先考慮換一個關鍵字 Set-Cookie: JSESSIONID 能否查找出相應的結果.

12306-algorithm-web-js-network-search-cookie-JSESSIONID.png

事實勝於雄辯,查詢過程並沒有任何問題而是查詢結果真的不存在,如此一來一次性排查兩個原因,那麼很有可能生成邏輯在於前端而非後端.

接下來只能在衆多請求中碰碰運氣尋找前端到底是在何處生成的 RAIL_DEVICEID ,然而請求衆多還是要稍微講究一下策略方向的.

既然是前端在控制 cookie 的生成邏輯,那麼很有可能是某個 js 文件在起作用,當然也不排除其他類型的文件有操作瀏覽器行爲的能力.

因此,通過分析進一步縮小範圍:在請求類型爲 JS 的網絡請求中查找包括關鍵字 RAIL_DEVICEID 的全部請求.

12306-algorithm-web-js-network-search-js-cookie-RAIL_DEVICEID.png

理想很豐滿,現實太骨感,本以爲選中 js 再搜索關鍵字能夠一起生效,結果並沒有,請求類型依舊沒有過濾出去,還是一大片的請求!

同時隨便選中任意請求可以看到此時網絡選項卡搜索匹配大結果其實是請求頭這些基本信息,應該並沒有包括 js 或者 doc 源碼,方向錯了,走再多路也是浪費時間.

12306-algorithm-web-js-network-search-js-cookie-analysis-RAIL_DEVICEID.png

雖然我不知道你從哪裏來,中間經歷了什麼,但是我知道你的最終歸宿一定會落到網絡文件系統.

Chrome 瀏覽器除了可以看出網絡請求也能看到最終呈現給用戶的文件系統,既然中間過程找不到你,那麼我直接到目的地去搜索吧!

打開源碼(Source)選項卡,整個面板大致分爲三部分,左側文件數,中間文件區,右側調試區.

12306-algorithm-web-js-source-workspace-pannel.png

其中左側的文件結構可以清楚看到當前所處的層級結構,有利於快速掌握項目輪廓.右側的調試區針對心中有想法但還不確定是否正確提供了非常好的驗證工具,調試別人的代碼就如本地開發那樣邊預言邊驗證.

中間的文件區域面積最大,功能自然也不能太弱,選中左側具體文件後可以顯示源碼,方便查看,進而去調試驗證心有所想.

所以問題來了,這一切的一切都要源於心有所想纔能有行動,那麼應該去哪裏搜索包括關鍵字 RAIL_DEVICEID 的文件呢?

一般而言,良好的用戶體驗是不需要告訴你用戶手冊的,給你一大堆詳盡的說明文檔也未必會耐得住去看一篇,先用用再說!

人生苦短,不要浪費太多時間放在無聊的事情上面,簡短的三行提醒富含哲理性,第一行告訴你怎麼打開文件,第二行告訴你如何運行命令,第三行告訴你如何操作實現什麼效果.

如果三行代碼還不足以解決你的問題,閱讀更多自己慢慢琢磨說明文檔吧!

當然,這裏和在文件系統中查找包含關鍵字 RAIL_DEVICEID 的需求最爲接近的應該就是第二行,運行命令了,那就試試看吧!

12306-algorithm-web-js-source-command-search.png

輸入搜索 search 後果然彈出了相關搜索命令,於是點擊開發工具(DevTools)後出現了搜索框,順理成章輸入關鍵字 RAIL_DEVICEID 進行搜索了啊!

12306-algorithm-web-js-source-search-result.png

終於等到你,還好我沒放棄,你就是我的唯一,看樣子和 RAIL_DEVICEID 有關的處理邏輯全部都在這麼一個 js 文件裏,看你還往哪裏跑!

直搗黃龍還往哪裏跑

找到該文件後點擊查看,紅藍黑密密麻麻一大片js 代碼,絕對不是給人看的而是給機器看的,想要給人閱讀還需要美化一下,將源碼醜化混淆成難以閱讀的代碼也是防止他人偷窺複製拷貝自己的勞動成果,同時也能減少文件大小,加速網絡傳輸數據,讓你的網站速度更快一些.

12306-algorithm-web-js-source-getjs-pretty.png

點擊中間區域的左下角格式化圖標進行美化代碼,然後在文件中搜素關鍵字 RAIL_DEVICEID 定位到具體代碼.

非常人性化的是,搜索功能是通用的快捷鍵 Ctrl + F,現在定位到具體代碼,截圖留念下,接下來纔是真正考驗技術的時刻!

12306-algorithm-web-js-source-getjs-search.png

$a.getJSON("https://kyfw.12306.cn/otn/HttpZF/logdevice" + ("?algID\x3drblubbXDx3\x26hashCode\x3d" + e + a), null, function(a) {
    var b = JSON.parse(a);
    void 0 != lb && lb.postMessage(a, r.parent);
    for (var d in b)
        "dfp" == d ? F("RAIL_DEVICEID") != b[d] && (W("RAIL_DEVICEID", b[d], 1E3),
        c.deviceEc.set("RAIL_DEVICEID", b[d])) : "exp" == d ? W("RAIL_EXPIRATION", b[d], 1E3) : "cookieCode" == d && (c.ec.set("RAIL_OkLJUJ", b[d]),
        W("RAIL_OkLJUJ", "", 0))
})

本地備份js方便復現

既然已經找到關鍵文件,自然需要留存快照進行存檔操作,否則哪一天文件更新了都不知道哪裏發生變化了,難不成還要從頭再分析一遍,我選擇差量更新而不是全量覆蓋!

選中源文件右鍵彈出菜單,選擇任意一款喜歡的方式複製源文件到本地留作學習備份,準備工作就緒後準備大幹一場.

12306-algorithm-web-js-source-getjs-backup.png

未完待續

由於篇幅有限,一篇博文不得不分成三部分,對此造成的不良體驗,還請見諒,如需閱讀剩餘部分,關注雪之夢技術驛站不迷路.

如果你覺得本文對你有所幫助,請隨手點個贊再走唄或者關注下公衆號「雪之夢技術驛站」定期更新優質文章喲!

雪之夢技術驛站.png

發佈了116 篇原創文章 · 獲贊 119 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章