redis.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import redis
  2. from proxypool.exceptions import PoolEmptyException
  3. from proxypool.schemas.proxy import Proxy
  4. from proxypool.setting import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_KEY, PROXY_SCORE_MAX, PROXY_SCORE_MIN, \
  5. PROXY_SCORE_INIT
  6. from random import choice
  7. from typing import List
  8. from loguru import logger
  9. from proxypool.utils.proxy import is_valid_proxy, convert_proxy_or_proxies
  10. REDIS_CLIENT_VERSION = redis.__version__
  11. IS_REDIS_VERSION_2 = REDIS_CLIENT_VERSION.startswith('2.')
  12. class RedisClient(object):
  13. """
  14. redis connection client of proxypool
  15. """
  16. def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, **kwargs):
  17. """
  18. init redis client
  19. :param host: redis host
  20. :param port: redis port
  21. :param password: redis password
  22. """
  23. self.db = redis.StrictRedis(host=host, port=port, password=password, decode_responses=True, **kwargs)
  24. def add(self, proxy: Proxy, score=PROXY_SCORE_INIT) -> int:
  25. """
  26. add proxy and set it to init score
  27. :param proxy: proxy, ip:port, like 8.8.8.8:88
  28. :param score: int score
  29. :return: result
  30. """
  31. if not is_valid_proxy(f'{proxy.host}:{proxy.port}'):
  32. logger.info(f'invalid proxy {proxy}, throw it')
  33. return
  34. if not self.exists(proxy):
  35. if IS_REDIS_VERSION_2:
  36. return self.db.zadd(REDIS_KEY, score, proxy)
  37. return self.db.zadd(REDIS_KEY, {proxy: score})
  38. def random(self) -> Proxy:
  39. """
  40. get random proxy
  41. firstly try to get proxy with max score
  42. if not exists, try to get proxy by rank
  43. if not exists, raise error
  44. :return: proxy, like 8.8.8.8:8
  45. """
  46. # try to get proxy with max score
  47. proxies = self.db.zrangebyscore(REDIS_KEY, PROXY_SCORE_MAX, PROXY_SCORE_MAX)
  48. if len(proxies):
  49. return convert_proxy_or_proxies(choice(proxies))
  50. # else get proxy by rank
  51. proxies = self.db.zrevrange(REDIS_KEY, PROXY_SCORE_MIN, PROXY_SCORE_MAX)
  52. if len(proxies):
  53. return convert_proxy_or_proxies(choice(proxies))
  54. # else raise error
  55. raise PoolEmptyException
  56. def decrease(self, proxy: Proxy) -> int:
  57. """
  58. decrease score of proxy, if small than PROXY_SCORE_MIN, delete it
  59. :param proxy: proxy
  60. :return: new score
  61. """
  62. score = self.db.zscore(REDIS_KEY, proxy.string())
  63. # current score is larger than PROXY_SCORE_MIN
  64. if score and score > PROXY_SCORE_MIN:
  65. logger.info(f'{proxy.string()} current score {score}, decrease 1')
  66. if IS_REDIS_VERSION_2:
  67. return self.db.zincrby(REDIS_KEY, proxy.string(), -1)
  68. return self.db.zincrby(REDIS_KEY, -1, proxy.string())
  69. # otherwise delete proxy
  70. else:
  71. logger.info(f'{proxy.string()} current score {score}, remove')
  72. return self.db.zrem(REDIS_KEY, proxy)
  73. def exists(self, proxy: Proxy) -> bool:
  74. """
  75. if proxy exists
  76. :param proxy: proxy
  77. :return: if exists, bool
  78. """
  79. return not self.db.zscore(REDIS_KEY, proxy.string()) is None
  80. def max(self, proxy: Proxy) -> int:
  81. """
  82. set proxy to max score
  83. :param proxy: proxy
  84. :return: new score
  85. """
  86. logger.info(f'{proxy.string()} is valid, set to {PROXY_SCORE_MAX}')
  87. if IS_REDIS_VERSION_2:
  88. return self.db.zadd(REDIS_KEY, PROXY_SCORE_MAX, proxy.string())
  89. return self.db.zadd(REDIS_KEY, {proxy.string(): PROXY_SCORE_MAX})
  90. def count(self) -> int:
  91. """
  92. get count of proxies
  93. :return: count, int
  94. """
  95. return self.db.zcard(REDIS_KEY)
  96. def all(self) -> List[Proxy]:
  97. """
  98. get all proxies
  99. :return: list of proxies
  100. """
  101. return convert_proxy_or_proxies(self.db.zrangebyscore(REDIS_KEY, PROXY_SCORE_MIN, PROXY_SCORE_MAX))
  102. def batch(self, start, end) -> List[Proxy]:
  103. """
  104. get batch of proxies
  105. :param start: start index
  106. :param end: end index
  107. :return: list of proxies
  108. """
  109. return convert_proxy_or_proxies(self.db.zrevrange(REDIS_KEY, start, end - 1))
  110. if __name__ == '__main__':
  111. conn = RedisClient()
  112. result = conn.random()
  113. print(result)