socks5.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import copy
  2. import time
  3. import requests
  4. from config.load import jy_proxy, headers
  5. from utils.log import logger
  6. __all__ = ['Proxy']
  7. def decrypt(input_str: str) -> str:
  8. """
  9. 定义base64解密函数
  10. :param input_str:
  11. :return:
  12. """
  13. # 对前面不是“=”的字节取索引,然后转换为2进制
  14. key = jy_proxy['socks5']['decrypt']
  15. ascii_list = ['{:0>6}'.format(str(bin(key.index(i))).replace('0b', '')) for i in input_str if i != '=']
  16. output_str = ''
  17. # 补齐“=”的个数
  18. equal_num = input_str.count('=')
  19. while ascii_list:
  20. temp_list = ascii_list[:4]
  21. # 转换成2进制字符串
  22. temp_str = ''.join(temp_list)
  23. # 对没有8位2进制的字符串补够8位2进制
  24. if len(temp_str) % 8 != 0:
  25. temp_str = temp_str[0:-1 * equal_num * 2]
  26. # 4个6字节的二进制 转换 为三个8字节的二进制
  27. temp_str_list = [temp_str[x:x + 8] for x in [0, 8, 16]]
  28. # 二进制转为10进制
  29. temp_str_list = [int(x, 2) for x in temp_str_list if x]
  30. # 连接成字符串
  31. output_str += ''.join([chr(x) for x in temp_str_list])
  32. ascii_list = ascii_list[4:]
  33. return output_str
  34. class Socks5Proxy:
  35. __instance = None
  36. def __new__(cls, *args, **kwargs):
  37. if cls.__instance is None:
  38. cls.__instance = super().__new__(cls)
  39. return cls.__instance
  40. def __init__(self):
  41. self.__proxies = {}
  42. def _init(self):
  43. self.url = jy_proxy['socks5']['url']
  44. self.pool = []
  45. self.index = 0 # 当前代理在代理池的位置
  46. self.counter = {}
  47. self.seconds = 60
  48. while not self.__proxies:
  49. if len(self.pool) > 0 and not self.__proxies:
  50. self.__proxies = copy.deepcopy(self.pool[self.index])
  51. else:
  52. self.generate_pool()
  53. @property
  54. def proxies(self):
  55. return self.__proxies
  56. def switch(self, reset=False):
  57. """切换代理"""
  58. if reset is True:
  59. self.counter.clear()
  60. self.flush_pool()
  61. elif len(self.counter) > 0:
  62. end_time = self.counter[str(self.__proxies)]
  63. current_time = int(time.time())
  64. if end_time - current_time < self.seconds:
  65. self.pool.remove(self.__proxies)
  66. logger.info(f"[代理]移除:{self.__proxies}")
  67. del self.counter[str(self.__proxies)]
  68. logger.info(f"[代理]剩余个数:{len(self.pool)}")
  69. self.__proxies = {} # 重置代理
  70. while not self.proxies:
  71. if len(self.pool) > 0:
  72. self.index += 1
  73. if self.index >= len(self.pool):
  74. self.index = 0
  75. self.__proxies = copy.deepcopy(self.pool[self.index])
  76. logger.info(f"[代理]切换 - {self.index}")
  77. else:
  78. logger.info("[代理]无可用代理")
  79. self.flush_pool()
  80. def generate_pool(self):
  81. """初始化代理池"""
  82. self.__socks5()
  83. self.__check_proxies()
  84. def flush_pool(self):
  85. logger.info(f"[代理]刷新代理池")
  86. self.pool.clear()
  87. self.generate_pool()
  88. def __socks5(self):
  89. logger.info(f"[代理]请求服务:{self.url}")
  90. try:
  91. response = requests.get(self.url, timeout=10)
  92. self.__extract_ip(response)
  93. except requests.RequestException:
  94. pass
  95. def __extract_ip(self, response):
  96. for proxy in response.json():
  97. host = decrypt(proxy['host'])
  98. port = int(proxy['port'])
  99. end_time = proxy['EndTime']
  100. items = {
  101. 'http': 'socks5://{}:{}'.format(host, port),
  102. 'https': 'socks5://{}:{}'.format(host, port)
  103. }
  104. self.pool.append(items)
  105. self.counter.setdefault(str(items), end_time)
  106. def __check_proxies(self):
  107. check_ip = 'https://myip.ipip.net'
  108. logger.info(f"[代理]通信检查:{check_ip}")
  109. for proxies in self.pool[::-1]:
  110. try:
  111. requests_param = {
  112. "headers": headers,
  113. "proxies": proxies,
  114. "timeout": 10
  115. }
  116. requests.get(check_ip, **requests_param)
  117. except requests.RequestException:
  118. self.pool.remove(proxies)
  119. del self.counter[str(proxies)]
  120. logger.info(f"[代理]可用个数:{len(self.pool)}")
  121. def __call__(self, enable_proxy: bool = False, *args, **kwargs):
  122. if enable_proxy:
  123. self._init()
  124. return self
  125. Proxy = Socks5Proxy()