redis.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import redis
  2. from proxypool.exceptions import PoolEmptyException
  3. from proxypool.schemas.proxy import Proxy
  4. from proxypool.setting import REDIS_CONNECTION_STRING, 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,
  17. connection_string=REDIS_CONNECTION_STRING, **kwargs):
  18. """
  19. init redis client
  20. :param host: redis host
  21. :param port: redis port
  22. :param password: redis password
  23. :param connection_string: redis connection_string
  24. """
  25. # if set connection_string, just use it
  26. if connection_string:
  27. self.db = redis.StrictRedis.from_url(connection_string, decode_responses=True, **kwargs)
  28. else:
  29. self.db = redis.StrictRedis(
  30. host=host, port=port, password=password, db=db, decode_responses=True, **kwargs)
  31. def add(self, proxy: Proxy, score=PROXY_SCORE_INIT, redis_key=REDIS_KEY) -> int:
  32. """
  33. add proxy and set it to init score
  34. :param proxy: proxy, ip:port, like 8.8.8.8:88
  35. :param score: int score
  36. :return: result
  37. """
  38. if not is_valid_proxy(f'{proxy.host}:{proxy.port}'):
  39. logger.info(f'invalid proxy {proxy}, throw it')
  40. return
  41. if not self.exists(proxy, redis_key):
  42. if IS_REDIS_VERSION_2:
  43. return self.db.zadd(redis_key, score, proxy.string())
  44. return self.db.zadd(redis_key, {proxy.string(): score})
  45. def random(self, redis_key=REDIS_KEY, proxy_score_min=PROXY_SCORE_MIN, proxy_score_max=PROXY_SCORE_MAX) -> Proxy:
  46. """
  47. get random proxy
  48. firstly try to get proxy with max score
  49. if not exists, try to get proxy by rank
  50. if not exists, raise error
  51. :return: proxy, like 8.8.8.8:8
  52. """
  53. # try to get proxy with max score
  54. proxies = self.db.zrangebyscore(
  55. redis_key, proxy_score_max, proxy_score_max)
  56. if len(proxies):
  57. return convert_proxy_or_proxies(choice(proxies))
  58. # else get proxy by rank
  59. proxies = self.db.zrevrange(
  60. redis_key, proxy_score_min, proxy_score_max)
  61. if len(proxies):
  62. return convert_proxy_or_proxies(choice(proxies))
  63. # else raise error
  64. raise PoolEmptyException
  65. def decrease(self, proxy: Proxy, redis_key=REDIS_KEY, proxy_score_min=PROXY_SCORE_MIN) -> int:
  66. """
  67. decrease score of proxy, if small than PROXY_SCORE_MIN, delete it
  68. :param proxy: proxy
  69. :return: new score
  70. """
  71. if IS_REDIS_VERSION_2:
  72. self.db.zincrby(redis_key, proxy.string(), -1)
  73. else:
  74. self.db.zincrby(redis_key, -1, proxy.string())
  75. score = self.db.zscore(redis_key, proxy.string())
  76. logger.info(f'{proxy.string()} score decrease 1, current {score}')
  77. if score <= proxy_score_min:
  78. logger.info(f'{proxy.string()} current score {score}, remove')
  79. self.db.zrem(redis_key, proxy.string())
  80. def exists(self, proxy: Proxy, redis_key=REDIS_KEY) -> bool:
  81. """
  82. if proxy exists
  83. :param proxy: proxy
  84. :return: if exists, bool
  85. """
  86. return not self.db.zscore(redis_key, proxy.string()) is None
  87. def max(self, proxy: Proxy, redis_key=REDIS_KEY, proxy_score_max=PROXY_SCORE_MAX) -> int:
  88. """
  89. set proxy to max score
  90. :param proxy: proxy
  91. :return: new score
  92. """
  93. logger.info(f'{proxy.string()} is valid, set to {proxy_score_max}')
  94. if IS_REDIS_VERSION_2:
  95. return self.db.zadd(redis_key, proxy_score_max, proxy.string())
  96. return self.db.zadd(redis_key, {proxy.string(): proxy_score_max})
  97. def count(self, redis_key=REDIS_KEY) -> int:
  98. """
  99. get count of proxies
  100. :return: count, int
  101. """
  102. return self.db.zcard(redis_key)
  103. def all(self, redis_key=REDIS_KEY, proxy_score_min=PROXY_SCORE_MIN, proxy_score_max=PROXY_SCORE_MAX) -> List[Proxy]:
  104. """
  105. get all proxies
  106. :return: list of proxies
  107. """
  108. return convert_proxy_or_proxies(self.db.zrangebyscore(redis_key, proxy_score_min, proxy_score_max))
  109. def batch(self, cursor, count, redis_key=REDIS_KEY) -> List[Proxy]:
  110. """
  111. get batch of proxies
  112. :param cursor: scan cursor
  113. :param count: scan count
  114. :return: list of proxies
  115. """
  116. cursor, proxies = self.db.zscan(redis_key, cursor, count=count)
  117. return cursor, convert_proxy_or_proxies([i[0] for i in proxies])
  118. if __name__ == '__main__':
  119. conn = RedisClient()
  120. result = conn.random()
  121. print(result)