1
0

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_DB, 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, db=REDIS_DB, **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, db=db, 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.string())
  37. return self.db.zadd(REDIS_KEY, {proxy.string(): 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. if IS_REDIS_VERSION_2:
  63. self.db.zincrby(REDIS_KEY, proxy.string(), -1)
  64. else:
  65. self.db.zincrby(REDIS_KEY, -1, proxy.string())
  66. score = self.db.zscore(REDIS_KEY, proxy.string())
  67. logger.info(f'{proxy.string()} score decrease 1, current {score}')
  68. if score <= PROXY_SCORE_MIN:
  69. logger.info(f'{proxy.string()} current score {score}, remove')
  70. self.db.zrem(REDIS_KEY, proxy.string())
  71. def exists(self, proxy: Proxy) -> bool:
  72. """
  73. if proxy exists
  74. :param proxy: proxy
  75. :return: if exists, bool
  76. """
  77. return not self.db.zscore(REDIS_KEY, proxy.string()) is None
  78. def max(self, proxy: Proxy) -> int:
  79. """
  80. set proxy to max score
  81. :param proxy: proxy
  82. :return: new score
  83. """
  84. logger.info(f'{proxy.string()} is valid, set to {PROXY_SCORE_MAX}')
  85. if IS_REDIS_VERSION_2:
  86. return self.db.zadd(REDIS_KEY, PROXY_SCORE_MAX, proxy.string())
  87. return self.db.zadd(REDIS_KEY, {proxy.string(): PROXY_SCORE_MAX})
  88. def count(self) -> int:
  89. """
  90. get count of proxies
  91. :return: count, int
  92. """
  93. return self.db.zcard(REDIS_KEY)
  94. def all(self) -> List[Proxy]:
  95. """
  96. get all proxies
  97. :return: list of proxies
  98. """
  99. return convert_proxy_or_proxies(self.db.zrangebyscore(REDIS_KEY, PROXY_SCORE_MIN, PROXY_SCORE_MAX))
  100. def batch(self, cursor, count) -> List[Proxy]:
  101. """
  102. get batch of proxies
  103. :param cursor: scan cursor
  104. :param count: scan count
  105. :return: list of proxies
  106. """
  107. cursor, proxies = self.db.zscan(REDIS_KEY, cursor, count=count)
  108. return cursor, convert_proxy_or_proxies([i[0] for i in proxies])
  109. if __name__ == '__main__':
  110. conn = RedisClient()
  111. result = conn.random()
  112. print(result)