可能是一份沒什么用的爬蟲代理IP指南


寫在前面

做爬蟲的小伙伴一般都繞不過代理IP這個問題.

PS:如果還沒遇到被封IP的場景,要不就是你量太小人家懶得理你,要不就是人家壓根不在乎...

爬蟲用戶自己是沒有能力維護一系列的代理服務器和代理IP的,這個成本實在有點高了。
所以公用代理服務器應運而生,現在幾大雲服務商家都提供代理IP服務,一般論個買...

同時網上也有很多代理IP共享網站,會把一些免費的代理IP放出來給大家用。
大家都是做爬蟲的,那么,是不是可以先把代理IP網站的數據爬一遍?
所以可以看到不少的爬代理IP的爬蟲,如突破反爬蟲的利器——開源IP代理池之類的項目。
這些項目都能達到抓取代理IP數據的目的,很多時候也夠用了。

然而在使用過程中我們發現了一些問題:

  1. 網站公布的代理IP不一定是可用的。可能代理服務器掛了,可能IP無效了...等等之類的。
  2. 代理IP是部分可用的。某代理IP可用代理訪問百度,但是代理訪問谷歌的時候就GG了。
  3. 代理連通性是好的,但是已經被訪問站識別為代理IP返回驗證碼或者辣雞數據。

proxyipcenter的解決方案

出於以上種種的原因,按耐不住的dalao(@virjar)開始自己動手擼了。

於是,proxyipcenter出來了。

這個項目做了什么東西呢?
dalao是這樣寫的:

DungProxy是一個代理IP服務,他包括一個代理IP資源server端和一系列適配中心IP資源得客戶端。

server負責代理IP資源的收集維護。

client則是一系列方便用戶使用得API,他屏蔽了代理IP下載、代理IP選取、IP綁定、IP切換等比較復雜邏輯。用戶只需要引入client即可方便使用代理IP服務

簡單來說:

server是一個代理IP爬蟲,同時負責簡單的數據清洗。

client本質是一個代理IP池,獲取數據源之后,基於需要代理訪問的網站在本地維護一個代理IP池供爬蟲使用。

以下內容轉載自http://git.oschina.net/virjar/proxyipcenter,
並已獲得相關授權。(PS:dalao寫的太好了,我都懶得重新寫一遍了...問過dalao之后直接轉載過來算了。)

proxyipcenter server

DrungProxy的代理IP都是從互聯網收集,他是架設在一個高度不可用的資源上面的服務。server會負責對這些資源進行清洗、校驗、打分,最終輸出可以被客戶端使用的IP資源。IP資源從入庫到最終判定可用生命流程如下

  1. IP抓取
    server監聽了很多代理IP網站,這些網站包括國內外十幾家,有意思的是drungProxy的IP爬蟲是一系列網站模版。五六行配置即可實現一個簡單的網站模版,然后我們有一個上層調度模塊將會負責調起模版進行數據抓取。
  2. IP消重
    需要消重的原因是程序運行到一定時間之后,大量IP都是數據庫里面已經存在的了,這個時候如果在數據庫進行消重邏輯將會導致大量數據庫讀寫,實際上我們的服務器是一個1塊錢的騰訊雲(曾經是),看起來是撐不住這么大的請求的(平均每天可以有10K量級)。最后在入庫前設置了一個bloomFilter消重模塊,能夠高效的檢測資源是否被入庫過。
  3. 位置信息完善
    這個邏輯不大,通過taobaoIp接口獲取地址信息,完善IP資源元數據。taobaoIP
  4. IP驗證
    IP驗證分為好幾個步驟。我們的IP總資源有80W,檢驗一個IP是否可用一般來說需要20秒左右的時間,因為代理IP本身響應比較慢,我們會把超時時間設置得比較長。所以可以計算一下80W數據走一輪將要消耗得時間,即使在多線程並行環境下時間也是很多的。為了在一定資源下完成校驗,我們設計了如下步驟
  • 端口開啟校驗,在進行可用性校驗前,首先需要檢查IP端口是否開啟。調研發現大量資源其實端口都不通,所以專門設計一個任務驗證端口是否開啟,端口開啟驗證超時時間為5秒。由於大多數資源端口都沒有開啟,所以大部分資源的校驗時間下降到5秒了。
  • 可用性校驗,進行可用性校驗的需要先進行端口開啟校驗,系統中端口開啟的資源大概3W,所以校驗可用性的總資源有3W左右。可用性校驗存在如下問題,很多代理IP其實不是代理網站,想他發送請求最終不是我們預期的數據,比如他返回給我們一個代理IP認證網頁。所以我們不能根據是否能夠請求到數據來判定IP是否可用。我們的做法是在公網放置一個API接口,然后控制代理IP訪問我們自己的接口,如果能夠拿到符合我們接口的預期數據,那么認為IP可用。
  • domain可用該校驗,可用性校驗通過之后IP還不是真正可用,悲傷的發現代理IP是和域名相關的。所以同一個IP在不同域名下表現可能不一樣。所以我們維護了一個域名IP池,這里面存儲各個域名下可用IP
  1. IP分發
    IP分發是根據客戶請求分配可用IP。分發邏輯現在還沒有完全完善,但是已經實現了最迫切和有校的分發方案。分發邏輯設計是:先嘗試查詢domainIP池,再根據其他請求參數做條件匹配,再查詢系統可用IP,再隨機選擇可用填充。四個步驟如果有一個步驟得到的IP超過請求參數期待數目,則不進行接下來的動作。

IP驗證模型

再IP驗證的時候,我們設計了一個模型用來確定哪些IP應該優先驗證。模型描述如下:長期可用IP檢測頻率低,長期不可用IP檢測評率低。不穩定IP和剛加入的IP檢測頻率高。我們使用優先隊列來實現這個邏輯,所有IP根據分值放在不同優先隊列中,每次校驗的時候再不同優先隊列中拿出一定資源進行校驗(不同優先級拿出的資源數目不一樣,高優先級的對象拿出更多資源),對於同一個優先隊列,我們根據最后驗證時間排序。使上次更新時間最久的資源被優先選擇。

分發去重

分發資源的時候,設計去重問題,也就是根據相同條件,每次分發得到的IP很大可能會重復。為了規避這個問題,每次分發都會相應的下發一個資源簽名,他會記錄分發過的IP。在下次請求的時候,客戶端需要帶上這個簽名,服務器會根據簽名過濾,同時會重新對新分發的IP資源做再次簽名.

server部署

server端使用java編寫,使用maven管理項目,使用mysql作為數據庫。相關技術包括springMVC,spring,tomcat,mybatis,guava,fastjson,httpclient等。
運行server的方式很簡單

  1. 在項目根目錄執行maven命令(需要提前安裝maven,maven安裝方式略)mvn install -Dmaven.test.skip=true
  2. 在server目錄執行maven命令 mvn tomcat7:run

server配置

直接運行項目使用的是我們的默認數據庫,同時使用的是默認配置。實際上server存在一些配置用來設置運行參數。合理的運行參數能夠合理使用機器資源以及達到更好的運行效果。
項目主要有兩個配置文件需要配置:

  1. mysql.properties 用來配置數據庫信息
  2. config.properties 配置其他啟動參數,主要需要關注里面幾個url地址,還有 system.thread.的參數項。system.thread用於指定某一種類型的任務執行的線程數,如果數據小於1,則這個模塊不會啟動。但是如果這個模塊接收到了任務請求,那么他會轉發到其他服務器上面(也就是上面的兩個forward相關的url,沒辦法服務器都是臘雞服務器 )

其他的應該沒有了把,哦對了,項目存在多個profile,也就是resources.local,resources.beta,resources.prod等。他們叫做profile,是maven里面的概念,默認是resources.local生效的。如果想使用其他profile下面的配置,則增加 -Pprofile參數,如運行server mvn -Pskyee clean tomcat7:run

server接口事例

http://115.159.40.202:8080/proxyipcenter/av?usedSign=&checkUrl=http%3A%2F%2Ffree-proxy-list.net%2F&domain=free-proxy-list.net&num=10

{
     "data": {
         "data": [
             {
                 "id": 257,
                 "ip": "203.192.12.148",
                 "proxyIp": "203.192.12.149",
                 "port": 80,
                 "ipValue": 3418360980,
                 "country": "中國",
                 "area": "華北",
                 "region": "北京市",
                 "city": "北京市",
                 "isp": "",
                 "countryId": "CN",
                 "areaId": "100000",
                 "regionId": "110000",
                 "cityId": "110100",
                 "ispId": "-1",
                 "transperent": 2,
                 "speed": 104,
                 "type": 1,
                 "connectionScore": 1310,
                 "availbelScore": 8,
                 "connectionScoreDate": 1475641264000,
                 "availbelScoreDate": 1475646860000,
                 "createtime": 1473840886000,
                 "lostheader": false
             },
             {
                 "id": 654,
                 "ip": "120.55.245.47",
                 "proxyIp": "112.124.119.21",
                 "port": 80,
                 "ipValue": 2016933167,
                 "country": "中國",
                 "area": "華東",
                 "region": "浙江省",
                 "city": "杭州市",
                 "isp": "阿里雲",
                 "countryId": "CN",
                 "areaId": "300000",
                 "regionId": "330000",
                 "cityId": "330100",
                 "ispId": "1000323",
                 "transperent": 2,
                 "speed": 83,
                 "type": 1,
                 "connectionScore": 1429,
                 "availbelScore": 2,
                 "connectionScoreDate": 1475659905000,
                 "availbelScoreDate": 1475630273000,
                 "createtime": 1473840884000,
                 "lostheader": false
             },
             {
                 "id": 2489,
                 "ip": "124.193.33.233",
                 "proxyIp": "124.193.33.233",
                 "port": 3128,
                 "ipValue": 2093031913,
                 "country": "中國",
                 "area": "華北",
                 "region": "北京市",
                 "city": "北京市",
                 "isp": "鵬博士",
                 "countryId": "CN",
                 "areaId": "100000",
                 "regionId": "110000",
                 "cityId": "110100",
                 "ispId": "1000143",
                 "transperent": 2,
                 "speed": 3390,
                 "type": 1,
                 "connectionScore": 310,
                 "availbelScore": 2,
                 "connectionScoreDate": 1475657685000,
                 "availbelScoreDate": 1475661878000,
                 "createtime": 1473839334000,
                 "lostheader": false
             },
             {
                 "id": 5004,
                 "ip": "203.192.12.146",
                 "proxyIp": "203.192.12.149",
                 "port": 80,
                 "ipValue": 3418360978,
                 "country": "中國",
                 "area": "華北",
                 "region": "北京市",
                 "city": "北京市",
                 "isp": "",
                 "countryId": "CN",
                 "areaId": "100000",
                 "regionId": "110000",
                 "cityId": "110100",
                 "ispId": "-1",
                 "transperent": 2,
                 "speed": 161,
                 "type": 1,
                 "connectionScore": 1291,
                 "availbelScore": 10,
                 "connectionScoreDate": 1475638336000,
                 "availbelScoreDate": 1475636727000,
                 "createtime": 1473840882000,
                 "lostheader": false
             },
             {
                 "id": 5421,
                 "ip": "221.237.155.64",
                 "proxyIp": "221.237.155.64",
                 "port": 9797,
                 "ipValue": 3723336512,
                 "country": "中國",
                 "area": "西南",
                 "region": "四川省",
                 "city": "成都市",
                 "isp": "電信",
                 "countryId": "CN",
                 "areaId": "500000",
                 "regionId": "510000",
                 "cityId": "510100",
                 "ispId": "100017",
                 "transperent": 2,
                 "speed": 3238,
                 "type": 1,
                 "connectionScore": 119,
                 "availbelScore": -1,
                 "connectionScoreDate": 1475611973000,
                 "availbelScoreDate": 1475629954000,
                 "createtime": 1473840773000,
                 "lostheader": false
             },
             {
                 "id": 8722,
                 "ip": "58.243.0.162",
                 "proxyIp": "58.243.0.162",
                 "port": 9999,
                 "ipValue": 989003938,
                 "country": "中國",
                 "area": "華東",
                 "region": "安徽省",
                 "city": "安慶市",
                 "isp": "聯通",
                 "countryId": "CN",
                 "areaId": "300000",
                 "regionId": "340000",
                 "cityId": "340800",
                 "ispId": "100026",
                 "transperent": 2,
                 "speed": 5143,
                 "type": 1,
                 "connectionScore": 154,
                 "availbelScore": -3,
                 "connectionScoreDate": 1475665673000,
                 "availbelScoreDate": 1475614147000,
                 "createtime": 1473839836000,
                 "lostheader": false
             },
             {
                 "id": 11698,
                 "ip": "218.7.170.190",
                 "proxyIp": "218.7.170.190",
                 "port": 3128,
                 "ipValue": 3657935550,
                 "country": "中國",
                 "area": "東北",
                 "region": "黑龍江省",
                 "city": "綏化市",
                 "isp": "聯通",
                 "countryId": "CN",
                 "areaId": "200000",
                 "regionId": "230000",
                 "cityId": "231200",
                 "ispId": "100026",
                 "transperent": 2,
                 "speed": 3145,
                 "type": 1,
                 "connectionScore": 317,
                 "availbelScore": -1,
                 "connectionScoreDate": 1475642001000,
                 "availbelScoreDate": 1475524810000,
                 "createtime": 1473839128000,
                 "lostheader": false
             },
             {
                 "id": 13318,
                 "ip": "220.249.185.178",
                 "proxyIp": "220.249.185.178",
                 "port": 9999,
                 "ipValue": 3707353522,
                 "country": "中國",
                 "area": "華東",
                 "region": "福建省",
                 "city": "福州市",
                 "isp": "聯通",
                 "countryId": "CN",
                 "areaId": "300000",
                 "regionId": "350000",
                 "cityId": "350100",
                 "ispId": "100026",
                 "transperent": 2,
                 "speed": 5094,
                 "type": 1,
                 "connectionScore": 129,
                 "availbelScore": -1,
                 "connectionScoreDate": 1475615670000,
                 "availbelScoreDate": 1475585178000,
                 "createtime": 1473840539000,
                 "lostheader": false
             },
             {
                 "id": 57033,
                 "ip": "210.245.25.228",
                 "proxyIp": "210.245.25.228",
                 "port": 3128,
                 "ipValue": 3539278308,
                 "country": "越南",
                 "area": "",
                 "region": "",
                 "city": "",
                 "isp": "",
                 "countryId": "VN",
                 "areaId": "",
                 "regionId": "",
                 "cityId": "",
                 "ispId": "",
                 "transperent": 2,
                 "speed": 1024,
                 "type": 1,
                 "connectionScore": 488,
                 "availbelScore": 36,
                 "connectionScoreDate": 1475635386000,
                 "availbelScoreDate": 1475630473000,
                 "createtime": 1473836572000,
                 "lostheader": false
             },
             {
                 "id": 124334,
                 "ip": "60.194.72.253",
                 "proxyIp": "60.194.72.253",
                 "port": 3128,
                 "ipValue": 1019365629,
                 "country": "中國",
                 "area": "華北",
                 "region": "北京市",
                 "city": "北京市",
                 "isp": "鵬博士",
                 "countryId": "CN",
                 "areaId": "100000",
                 "regionId": "110000",
                 "cityId": "110100",
                 "ispId": "1000143",
                 "transperent": 2,
                 "speed": 2366,
                 "type": 1,
                 "connectionScore": 610,
                 "availbelScore": 16,
                 "connectionScoreDate": 1475643516000,
                 "availbelScoreDate": 1475631080000,
                 "createtime": 1473839561000,
                 "lostheader": false
             }
         ],
         "num": 10,
         "sign": "9999#C99+999#9B99B99999##Y9999+9999999999999999999999t9999s99999999s9999999999999999999999999999#99999999999999GB999999999G9999s9s99999#9999999999Y9+999##99999999+99999999999999+999999999999B999+Y9999G9+99999999999YB99999999999999999999999+99Y999999999B9999G999s99G999999999#99999#9Y999s999999999#B99999999999999999999+999999Y9999999Y9999999999999Y9999Y999999999999999"
     },
     "status": true
 }

proxyipcenter client

client 設計文檔

client 使用文檔

client運行原理
這里講述IP池的設計相關,如果您僅僅是為了使用dunproxy-client,則不必關心本文內容

client就是一個代理IP池的實現,IP池的設計基於兩個點:

  1. 代理IP都是不穩定的,不可靠的,需要一個機制來切換IP,盡可能使用高質量IP。

  2. IP和環境關系很大,同一個IP在不同的機器下訪問不同的目標網站,其可用性表現都是不一樣的

使用IpPoolAPI獲取IP資源

獲取IP

獲取一個IP的方式是這樣的 IpPool.getInstance().bind(domain, accessUrl);

  • 第一個參數是域名,可以傳遞null,傳遞null提取accessUrl schema里面的host
  • 第二個參數是你當前需要訪問的url, 可以為null,為null時domain不能為空

曾經有一個綁定用戶的功能,使得同一個賬戶每次獲取的IP相同,后來覺得是過度設計,因為對於抓取場景,切換IP是很普通的需求,而且貌似沒有多少server會檢查常用IP。就算有也是小眾需求,本框架不必支持

記錄IP使用

每當使用IP的時候,需要記錄一次IP使用,也就是將IP實例的使用次數加一,用於打分機制計算IP的使用分值,評估IP可用性
方式如下:com.virjar.dungproxy.client.model.AvProxy.recordUsage

記錄IP使用失敗

每當IP使用失敗的時候,需要記錄IP使用失敗,也就是將IP實例的失敗次數加一,用於打分機制計算IP的使用分值,評估IP可用性
方式如下:com.virjar.dungproxy.client.model.AvProxy.recordFailed()

IP下線

IP下線很簡單,拿到IP實例,這樣調用com.virjar.dungproxy.client.model.AvProxy.offline()
一般情況不建議這么做,因為IP池會自動檢查IP是否應該下線,IP池可以定制各種策略。當時,有些時候IP池的檢查機制比較緩慢,而上層業務可以明確知道本IP不可用,這個時候可以使用本API強制下線

銷毀IP池實例

IP池是單例的,同時里面維護了兩個任務線程,在業務完成的時候,需要銷毀IP池才能終止內部線程。同時也會執行一些收尾工作,如將可用IP dump。
銷毀方式是:com.virjar.dungproxy.client.ippool.IpPool.destroy

其他

IP池有其他很多擴展點,但是目前接口沒有開發完成,待后續完善

TODO 幾個主流語言的客戶端

  1. .NET/.NET core client (辣雞樓主還沒動手...)
  2. Python client(另外一個大佬好像忘了這事了...)
  3. Golang client(可能還是辣雞樓主動手...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM