Squid代理伺服器搭建億級爬蟲IP代理池

  • 2019 年 10 月 6 日
  • 筆記

做爬蟲抓取時,我們經常會碰到網站針對IP地址封鎖的反爬蟲策略。但只要有大量可用的IP資源,問題自然迎刃而解。

以前嘗試過自己抓取網路上免費代理IP來搭建代理池,可免費IP品質參差不齊,不僅資源少、速度慢,而且失效快,滿足不了快速密集抓取的需求。

收費代理提供的代理資源品質明顯提升,最終選定使用站大爺作為代理提供平台。

站大爺每天能提供大概5萬個不重複的短效高匿代理,每個代理存活期為2分鐘,總IP數有20億,IP數量足夠使用。價格為包天30元,包月500元,還有半年及一年的套餐可供選擇。只要能滿足項目要求,提供優質穩定的服務,這些成本值得付出。

高匿代理才可以真正用來防止爬蟲被封鎖,如果使用普通代理,爬蟲的真實IP還是會暴露。

搭建思路

站大爺提供了大量的代理伺服器資源,主要考慮如何將這些伺服器分配給爬蟲伺服器使用。最初的想法是使用Redis作為代理伺服器資源隊列,一個程式自動獲取站大爺API提供的代理,驗證可用後push到Redis里,每個程式再從Redis中pop一個代理進行抓取,但這樣的缺點是不太好控制每台爬蟲伺服器的代理品質,有的代理速度快,有的速度比較慢,影響抓取效率,其次就是需要自行維護一套代理驗證、分配的程式,增加了程式碼量,不便後期維護。

為了解決這些問題,我想到可以使用 Squid 提供的父代理功能,自動將爬蟲伺服器的請求轉發給代理伺服器。Squid提供了自動輪詢功能,自動驗證並剔除不可用的代理。減少了我們多餘的驗證步驟。

爬蟲軟體只需將代理設置為 Squid 伺服器即可,不需要每次重新設置為其他的代理伺服器。

這套方案明顯減少了工作量,提高了易用性和可維護性。

實現過程

  1. 首先獲取代理平台提供的代理伺服器資源
    • 建議購買短效代理,購買後在後台獲取API地址並設置IP白名單等參數
  2. 將獲取到的代理伺服器寫入squid配置文件
    • 解析網站提供的代理伺服器,按照一定規則寫入 /etc/squid/squid.conf
  3. 重新配置 squid
    • 寫入配置文件之後重新載入最新的文件,不會造成中斷
  4. 自動更新,重複1-3
    • 由於網站提供的代理存活時間只有2分鐘,所以需要每隔一段時間重新獲取一批新IP
from gevent import monkey  # isort:skip  monkey.patch_all()  # isort:skip  import logging  import os  import time    import requests  from gevent.pool import Pool    logger = logging.getLogger(__name__)  logger.setLevel(logging.INFO)  formatter = logging.Formatter(      "%(asctime)s - %(name)s - %(levelname)s: - %(message)s", datefmt="%Y-%m-%d %H:%M:%S"  )    # 使用StreamHandler輸出到螢幕  ch = logging.StreamHandler()  ch.setLevel(logging.INFO)  ch.setFormatter(formatter)    logger.addHandler(ch)    # Squid的配置文件語法  # 將請求轉發到父代理  PEER_CONF = "cache_peer %s parent %s 0 no-query weighted-round-robin weight=1 connect-fail-limit=2 allow-miss max-conn=5n"  # 可用代理  GOOD_PROXIES = []    pool = Pool(50)      def check_proxy(proxy):      """驗證代理是否可用      :param proxy list:[ip, port]"""      global GOOD_PROXIES      ip, port = proxy      _proxies = {"http": "{}:{}".format(ip, port)}      try:          ip_url = "http://2019.ip138.com/ic.asp"          res = requests.get(ip_url, proxies=_proxies, timeout=10)          assert ip in res.content          logger.info("[GOOD] - {}:{}".format(ip, port))          GOOD_PROXIES.append(proxy)      except Exception as e:          logger.error("[BAD] - {}:{}, {}".format(ip, port, e))      def update_conf():      with open("/etc/squid/squid.conf.original", "r") as F:          squid_conf = F.readlines()      squid_conf.append("n# Cache peer confign")      for proxy in GOOD_PROXIES:          squid_conf.append(PEER_CONF % (proxy[0], proxy[1]))      with open("/etc/squid/squid.conf", "w") as F:          F.writelines(squid_conf)      def get_proxy():      global GOOD_PROXIES      GOOD_PROXIES = []      # 1. 獲取代理IP資源      api_url = "http://s.zdaye.com/?api=YOUR_API&count=100&fitter=1&px=2"      res = requests.get(api_url).content      if len(res) == 0:          logger.error("no data")      elif "bad" in res:          logger.error("bad request")      else:          logger.info("get all proxies")          proxies = []          for line in res.split():              proxies.append(line.strip().split(":"))          pool.map(check_proxy, proxies)          pool.join()          # 2. 寫入Squid配置文件          update_conf()          # 3. 重新載入配置文件          os.system("squid -k reconfigure")          logger.info(">>>> DONE! <<<<")      def main():      start = time.time()      while True:          # 每30秒獲取一批新IP          if time.time() - start >= 30:              get_proxy()              start = time.time()          time.sleep(5)      if __name__ == "__main__":      main()

使用方法

  1. 按Squid 搭建正向代理伺服器、Squid 配置高匿代理介紹的方法搭建運行 Squid 高匿伺服器
  2. 備份原始配置文件cp /etc/squid/squid.conf /etc/squid/squid.conf.original,以供軟體使用
  3. 在squid伺服器上運行python zdy.py

實例

如果按照上述方法搭建好代理IP池,只需要在爬蟲程式碼中設置設置squid代理伺服器地址和埠(比如139.xxx.xxx.66:3188)。

from __future__ import print_function    import requests    s = requests.Session()  s.proxies.update({"http": "139.xxx.xxx.66:3188"})  print(s.get("http://httpbin.org/ip"))

每次運行這個程式時,返回的IP都不一樣,而且僅有一個,說明IP代理池已經搭建成功,可以應用在網路爬蟲項目中。

總結

這套解決方案結合了網路上的大量優質代理資源以及Squid伺服器提供的特性,基本解決了網站對於爬蟲IP的封鎖。

成本比較低,而且有比較高的易用性,很方便地能結合到各種爬蟲應用中,只需要增加一個代理地址即可,而由 Squid 統一管理父代理,不需要在爬蟲程式中進行代理的獲取驗證等等操作,便於維護。

實際使用中還沒有發現什麼特別重大的問題,更多擴展性還有待後續繼續研究。

項目地址: https://github.com/xNathan/squid_proxy_pool