思路分享

思路分享

來自專欄踩坑晉陞之路

歡迎關注我的公眾號: 一個簡單程序猿

歡迎與我交流。

在編程過程中十分的重要,一個人能否寫出高質量的代碼,關鍵就在於是否有一個清晰的思路。這裡分享兩個我最近一段時間遇到的兩個比較有意思的解決問題的思路。

兩個思路

思路一 (方法一)

這是我做的《基於lucene的全文搜索引擎》課程作業,其中添加了電影搜索功能,前端接受一個關鍵字,後端通過python腳本去獲取數據,然後再返回給前端。效果如下:

數據是通過種子帝(www.btdtdy.org)獲取的。一般獲取數據的方法是輸入關鍵詞,通過構造請求鏈接,然後獲取數據,解析數據。但是該網站的請求鏈接比較特殊,它把關鍵字加密了,如下圖我們搜索的 鋼鐵俠 請求鏈接里的search後面的關鍵詞顯然被加密了。想要請求它的內容就需要知道它的加密方式。

一般加密都是通過前端加密。我們通過分析請求發現s.php?id=243這個鏈接裡面定義了加密方式是Base64

我們使用python通過測試如下:

+ 先導入base64模塊

+ 定義關鍵字

+ 把關鍵字編碼為utf-8

+ 使用b64encode編碼後的關鍵詞

+ 解碼關鍵詞

通過上面的操作,我們就得到了加密後的關鍵詞。

通過對比我們發現url中的關鍵詞是:b-6ZKi6Z0B5L6

我們加密得到的是: 6ZKi6Z0B5L6g

經過比較我們發現前面的b-是固定不變的。這樣我們就相當於破解了它的加密方式。接下的請求和解析就很簡單了,這裡就不在介紹了,我們接下來介紹第二種方法。

### 思路一 (方法二)

在實際的測試中,我發現了上圖中框起來的地方。做過網站的應該都清楚rss,RSS訂閱能更快地獲取信息,網站提供RSS輸出,有利於讓用戶獲取網站內容的最新更新。網路用戶可以在客戶端藉助於支持RSS的聚合工具軟體,在不打開網站內容頁面的情況下閱讀支持RSS輸出的網站內容。

我們打開這個頁面之後發現,我們想要的內容都在這裡面(種子鏈接詳情頁,種子標題)而且關鍵詞也沒有加密,這樣的話,我們就可以直接請求這個xml的文件,然後從裡面提取我們想要的內容就可以了呀:

為了防止偶然,我們有換了一個關鍵詞,發現完全OK。這樣的話,我們只需要構造這個請求就可以獲取我們想要的東西。

> 方法一和方法二都能夠拿到數據,方法一採用的是硬肛的方法,而方法二明顯巧妙了許多。方法二比方法一要簡單很多,不僅沒有加密而且數據規則,方便提取。所以在行動前多思考,我相信方法一併不是所有人都能夠想的出來,還要分析請求。所以一定要多思考、多分析。

思路二

這是我搭建代理池的時候遇到的問題,代理池需要大量的代理,代理網站越多,獲取到的代理就越多,國內免費的代理就那麼幾個,而且都被別人爬爛了,質量十分的低。而國外的就不一樣,由於牆的關係,很大一部分人都被攔住了,而我剛好有國外的伺服器,搭建了爬蟲環境,所以這一層對我沒用。

這裡推薦一個國外的代理網站: spys.one/en/free-proxy-

如下圖,500個免費的ip,可用性高,更新速度快:

正當我準備把這500個熱乎乎的ip收入囊中的時候,問題來了,我發現它的埠號是加了密的,WTF?!!!如下圖:

上圖是複製出來的源代碼,通過正則表達式匹配到的ip,紅框圈起來的就是埠號,這是什麼鬼?!難道就這麼放棄嗎?放棄是不可能放棄的,這輩子也不會放棄的。就因為它有難度,所以擋住了絕大多數的爬蟲,如果我能爬下來,那豈不是美滋滋。

繼續分析, 在源代碼里發現了這個,如下圖:

這一段看起來骨骼驚奇的代碼,一看就不簡單。

把它複製出來,然後稍微整理一下,如下圖:

  • 1-20行是賦值出來的字元串
  • 22行是埠加密的字元串

通過比較發現它們之間果然有「見不得人的勾當」 ,比如

(g7g7f6^g7q7) 對應於上面的g7g7f6=8^g7q7; g7q7=1221;

通過python運算8^1221^1221得到結果8,如上圖右半部分。

其中的+不是加法運算,而是連接運算。它把每一個數字連接起來,最終組合成埠號:上圖中組合出來的埠號為8080。

請仔細觀察上圖中的這一部分:

它是從等號右面從0-9,比如:

8^1221^1221 = 8

0^7693^7693 = 0

……

從上面可以發現,^後面的都可以不要,只需要判斷埠加密字元串中包含上面哪一個字元串,如果包含b2t0l2那麼它就是0,如果包含z6l2w3,那麼它就是1。

這樣就可以把上面的內容整合成下面的樣子,通過正則匹配可以輕鬆的截取出來:

這樣的話,我們就可以很輕鬆的算出埠號。

你以為這樣就結束了?! 並沒有


我發現上面的字元串並不是固定的,它是動態變化的,這一次請求是:

r8d4=7693;h8c3=1203;c3i9=8380;w3v2=3981;i9u1=5597;y5j0=9372;d4h8=9969;z6l2=1350;g7q7=1221;k1o5=7185;b2t0l2=0^r8d4;z6l2w3=1^h8c3;n4a1v2=2^c3i9;p6w3q7=3^w3v2;u1p6n4=4^i9u1;l2x4k1=5^y5j0;s9r8y5=6^d4h8;k1q7g7=7^z6l2;g7g7f6=8^g7q7;f6h8a1=9^k1o5;

下一次請求就變成:

w3l2=2592;s9o5=3288;u1h8=6497;j0s9=7893;e5c3=1467;d4r8=8884;k1k1=8142;x4q7=4302;b2w3=2286;m3d4=1753;p6x4c3=0^w3l2;g7a1y5=1^s9o5;n4f6j0=2^u1h8;q7r8n4=3^j0s9;r8b2e5=4^e5c3;s9q7s9=5^d4r8;d4k1m3=6^k1k1;o5s9w3=7^x4q7;u1h8o5=8^b2w3;v2j0r8=9^m3d4;

這顯然是不一樣的。WTF?!!!

這…

放棄還是不可能放棄的,這輩子也不會放棄的。繼續分析,發現雖然它加密字元串每次都在變,但是我們已經知道了它的構造方法,那麼我們就跟著動態變化就是了。我們每次請求的時候,動態提取解密字元串,然後拿著它去解密埠號。

通過上面的方法,我們可以得到一個列表如下圖:

列表的對應位置剛好是解密字元串的值。

+ ips 是通過正則表達式匹配到的ip

  • base是通過正則表達式提取的解密字元串列表
  • ports是通過正則表達式提取的埠的加密字元串
  • aa 是把加密的埠號通過+劃分開
  • 內層for循環解密埠號
  • xs 是組裝好的埠號
  • result是ip加埠號

上面的代碼運行結果如下:

上面是我最近遇到的兩個比較有意思的問題,以及我的解決思路,希望能給你帶來一定的啟發。

公眾號: 一個簡單程序猿

推薦閱讀:

C語言基礎:函數參數與返回值
高效的面試方式:結對編程
學編程,要學會CRM
用ASP.NET MVC5 +SQLSERVER2014搭建多層架構的資料庫管理系統
襪套的編程

TAG:Python | 代理 | 編程 |