feat: cache impl done
This commit is contained in:
parent
6c4116f240
commit
4bba1447f8
|
@ -1,5 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @Author : relakkes@gmail.com
|
|
||||||
# @Name : 程序员阿江-Relakkes
|
|
||||||
# @Time : 2024/6/2 11:05
|
|
||||||
# @Desc :
|
|
|
@ -5,10 +5,10 @@
|
||||||
# @Desc : 抽象类
|
# @Desc : 抽象类
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Any, Optional
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
|
|
||||||
class Cache(ABC):
|
class AbstractCache(ABC):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get(self, key: str) -> Optional[Any]:
|
def get(self, key: str) -> Optional[Any]:
|
||||||
|
@ -31,3 +31,12 @@ class Cache(ABC):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def keys(self, pattern: str) -> List[str]:
|
||||||
|
"""
|
||||||
|
获取所有符合pattern的key
|
||||||
|
:param pattern: 匹配模式
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Author : relakkes@gmail.com
|
||||||
|
# @Name : 程序员阿江-Relakkes
|
||||||
|
# @Time : 2024/6/2 11:23
|
||||||
|
# @Desc :
|
||||||
|
|
||||||
|
|
||||||
|
class CacheFactory:
|
||||||
|
"""
|
||||||
|
缓存工厂类
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_cache(cache_type: str, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
创建缓存对象
|
||||||
|
:param cache_type: 缓存类型
|
||||||
|
:param args: 参数
|
||||||
|
:param kwargs: 关键字参数
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if cache_type == 'memory':
|
||||||
|
from .local_cache import ExpiringLocalCache
|
||||||
|
return ExpiringLocalCache(*args, **kwargs)
|
||||||
|
elif cache_type == 'redis':
|
||||||
|
from .redis_cache import RedisCache
|
||||||
|
return RedisCache()
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unknown cache type: {cache_type}')
|
|
@ -6,12 +6,12 @@
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
from typing import Any, Dict, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from abs_cache import Cache
|
from cache.abs_cache import AbstractCache
|
||||||
|
|
||||||
|
|
||||||
class ExpiringLocalCache(Cache):
|
class ExpiringLocalCache(AbstractCache):
|
||||||
|
|
||||||
def __init__(self, cron_interval: int = 10):
|
def __init__(self, cron_interval: int = 10):
|
||||||
"""
|
"""
|
||||||
|
@ -60,6 +60,21 @@ class ExpiringLocalCache(Cache):
|
||||||
"""
|
"""
|
||||||
self._cache_container[key] = (value, time.time() + expire_time)
|
self._cache_container[key] = (value, time.time() + expire_time)
|
||||||
|
|
||||||
|
def keys(self, pattern: str) -> List[str]:
|
||||||
|
"""
|
||||||
|
获取所有符合pattern的key
|
||||||
|
:param pattern: 匹配模式
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if pattern == '*':
|
||||||
|
return list(self._cache_container.keys())
|
||||||
|
|
||||||
|
# 本地缓存通配符暂时将*替换为空
|
||||||
|
if '*' in pattern:
|
||||||
|
pattern = pattern.replace('*', '')
|
||||||
|
|
||||||
|
return [key for key in self._cache_container.keys() if pattern in key]
|
||||||
|
|
||||||
def _schedule_clear(self):
|
def _schedule_clear(self):
|
||||||
"""
|
"""
|
||||||
开启定时清理任务,
|
开启定时清理任务,
|
||||||
|
@ -93,11 +108,11 @@ class ExpiringLocalCache(Cache):
|
||||||
await asyncio.sleep(self._cron_interval)
|
await asyncio.sleep(self._cron_interval)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
cache = ExpiringLocalCache(cron_interval=2)
|
cache = ExpiringLocalCache(cron_interval=2)
|
||||||
cache.set('name', '程序员阿江-Relakkes', 3)
|
cache.set('name', '程序员阿江-Relakkes', 3)
|
||||||
print(cache.get('key'))
|
print(cache.get('key'))
|
||||||
|
print(cache.keys("*"))
|
||||||
time.sleep(4)
|
time.sleep(4)
|
||||||
print(cache.get('key'))
|
print(cache.get('key'))
|
||||||
del cache
|
del cache
|
||||||
|
|
|
@ -3,18 +3,18 @@
|
||||||
# @Name : 程序员阿江-Relakkes
|
# @Name : 程序员阿江-Relakkes
|
||||||
# @Time : 2024/5/29 22:57
|
# @Time : 2024/5/29 22:57
|
||||||
# @Desc : RedisCache实现
|
# @Desc : RedisCache实现
|
||||||
import os
|
|
||||||
import pickle
|
import pickle
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any, List
|
||||||
|
|
||||||
from abs_cache import Cache
|
|
||||||
from redis import Redis
|
from redis import Redis
|
||||||
|
|
||||||
|
from cache.abs_cache import AbstractCache
|
||||||
from config import db_config
|
from config import db_config
|
||||||
|
|
||||||
|
|
||||||
class RedisCache(Cache):
|
class RedisCache(AbstractCache):
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
# 连接redis, 返回redis客户端
|
# 连接redis, 返回redis客户端
|
||||||
self._redis_client = self._connet_redis()
|
self._redis_client = self._connet_redis()
|
||||||
|
@ -53,12 +53,19 @@ class RedisCache(Cache):
|
||||||
"""
|
"""
|
||||||
self._redis_client.set(key, pickle.dumps(value), ex=expire_time)
|
self._redis_client.set(key, pickle.dumps(value), ex=expire_time)
|
||||||
|
|
||||||
|
def keys(self, pattern: str) -> List[str]:
|
||||||
|
"""
|
||||||
|
获取所有符合pattern的key
|
||||||
|
"""
|
||||||
|
return [key.decode() for key in self._redis_client.keys(pattern)]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
redis_cache = RedisCache()
|
redis_cache = RedisCache()
|
||||||
# basic usage
|
# basic usage
|
||||||
redis_cache.set("name", "程序员阿江-Relakkes", 1)
|
redis_cache.set("name", "程序员阿江-Relakkes", 1)
|
||||||
print(redis_cache.get("name")) # Relakkes
|
print(redis_cache.get("name")) # Relakkes
|
||||||
|
print(redis_cache.keys("*")) # ['name']
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
print(redis_cache.get("name")) # None
|
print(redis_cache.get("name")) # None
|
||||||
|
|
||||||
|
|
|
@ -14,3 +14,7 @@ REDIS_DB_HOST = "127.0.0.1" # your redis host
|
||||||
REDIS_DB_PWD = os.getenv("REDIS_DB_PWD", "123456") # your redis password
|
REDIS_DB_PWD = os.getenv("REDIS_DB_PWD", "123456") # your redis password
|
||||||
REDIS_DB_PORT = os.getenv("REDIS_DB_PORT", 6379) # your redis port
|
REDIS_DB_PORT = os.getenv("REDIS_DB_PORT", 6379) # your redis port
|
||||||
REDIS_DB_NUM = os.getenv("REDIS_DB_NUM", 0) # your redis db num
|
REDIS_DB_NUM = os.getenv("REDIS_DB_NUM", 0) # your redis db num
|
||||||
|
|
||||||
|
# cache type
|
||||||
|
CACHE_TYPE_REDIS = "redis"
|
||||||
|
CACHE_TYPE_MEMORY = "memory"
|
|
@ -3,7 +3,6 @@ import functools
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import redis
|
|
||||||
from playwright.async_api import BrowserContext, Page
|
from playwright.async_api import BrowserContext, Page
|
||||||
from playwright.async_api import TimeoutError as PlaywrightTimeoutError
|
from playwright.async_api import TimeoutError as PlaywrightTimeoutError
|
||||||
from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
||||||
|
@ -11,6 +10,7 @@ from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
||||||
|
|
||||||
import config
|
import config
|
||||||
from base.base_crawler import AbstractLogin
|
from base.base_crawler import AbstractLogin
|
||||||
|
from cache.cache_factory import CacheFactory
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,13 +129,13 @@ class DouYinLogin(AbstractLogin):
|
||||||
|
|
||||||
# 检查是否有滑动验证码
|
# 检查是否有滑动验证码
|
||||||
await self.check_page_display_slider(move_step=10, slider_level="easy")
|
await self.check_page_display_slider(move_step=10, slider_level="easy")
|
||||||
redis_obj = redis.Redis(host=config.REDIS_DB_HOST, password=config.REDIS_DB_PWD)
|
cache_client = CacheFactory.create_cache(config.CACHE_TYPE_MEMORY)
|
||||||
max_get_sms_code_time = 60 * 2 # 最长获取验证码的时间为2分钟
|
max_get_sms_code_time = 60 * 2 # 最长获取验证码的时间为2分钟
|
||||||
while max_get_sms_code_time > 0:
|
while max_get_sms_code_time > 0:
|
||||||
utils.logger.info(f"[DouYinLogin.login_by_mobile] get douyin sms code from redis remaining time {max_get_sms_code_time}s ...")
|
utils.logger.info(f"[DouYinLogin.login_by_mobile] get douyin sms code from redis remaining time {max_get_sms_code_time}s ...")
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
sms_code_key = f"dy_{self.login_phone}"
|
sms_code_key = f"dy_{self.login_phone}"
|
||||||
sms_code_value = redis_obj.get(sms_code_key)
|
sms_code_value = cache_client.get(sms_code_key)
|
||||||
if not sms_code_value:
|
if not sms_code_value:
|
||||||
max_get_sms_code_time -= 1
|
max_get_sms_code_time -= 1
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -3,12 +3,10 @@ import functools
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import redis
|
|
||||||
from playwright.async_api import BrowserContext, Page
|
from playwright.async_api import BrowserContext, Page
|
||||||
from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
||||||
wait_fixed)
|
wait_fixed)
|
||||||
|
|
||||||
import config
|
|
||||||
from base.base_crawler import AbstractLogin
|
from base.base_crawler import AbstractLogin
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@ import functools
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import redis
|
|
||||||
from playwright.async_api import BrowserContext, Page
|
from playwright.async_api import BrowserContext, Page
|
||||||
from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
from tenacity import (RetryError, retry, retry_if_result, stop_after_attempt,
|
||||||
wait_fixed)
|
wait_fixed)
|
||||||
|
|
||||||
import config
|
import config
|
||||||
from base.base_crawler import AbstractLogin
|
from base.base_crawler import AbstractLogin
|
||||||
|
from cache.cache_factory import CacheFactory
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,14 +89,14 @@ class XiaoHongShuLogin(AbstractLogin):
|
||||||
await send_btn_ele.click() # 点击发送验证码
|
await send_btn_ele.click() # 点击发送验证码
|
||||||
sms_code_input_ele = await login_container_ele.query_selector("label.auth-code > input")
|
sms_code_input_ele = await login_container_ele.query_selector("label.auth-code > input")
|
||||||
submit_btn_ele = await login_container_ele.query_selector("div.input-container > button")
|
submit_btn_ele = await login_container_ele.query_selector("div.input-container > button")
|
||||||
redis_obj = redis.Redis(host=config.REDIS_DB_HOST, password=config.REDIS_DB_PWD)
|
cache_client = CacheFactory.create_cache(config.CACHE_TYPE_MEMORY)
|
||||||
max_get_sms_code_time = 60 * 2 # 最长获取验证码的时间为2分钟
|
max_get_sms_code_time = 60 * 2 # 最长获取验证码的时间为2分钟
|
||||||
no_logged_in_session = ""
|
no_logged_in_session = ""
|
||||||
while max_get_sms_code_time > 0:
|
while max_get_sms_code_time > 0:
|
||||||
utils.logger.info(f"[XiaoHongShuLogin.login_by_mobile] get sms code from redis remaining time {max_get_sms_code_time}s ...")
|
utils.logger.info(f"[XiaoHongShuLogin.login_by_mobile] get sms code from redis remaining time {max_get_sms_code_time}s ...")
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
sms_code_key = f"xhs_{self.login_phone}"
|
sms_code_key = f"xhs_{self.login_phone}"
|
||||||
sms_code_value = redis_obj.get(sms_code_key)
|
sms_code_value = cache_client.get(sms_code_key)
|
||||||
if not sms_code_value:
|
if not sms_code_value:
|
||||||
max_get_sms_code_time -= 1
|
max_get_sms_code_time -= 1
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
# @Author : relakkes@gmail.com
|
# @Author : relakkes@gmail.com
|
||||||
# @Time : 2023/12/2 11:18
|
# @Time : 2023/12/2 11:18
|
||||||
# @Desc : 爬虫 IP 获取实现
|
# @Desc : 爬虫 IP 获取实现
|
||||||
# @Url : 现在实现了极速HTTP的接口,官网地址:https://www.jisuhttp.com/?pl=mAKphQ&plan=ZY&kd=Yang
|
# @Url : 快代理HTTP实现,官方文档:https://www.kuaidaili.com/?ref=ldwkjqipvz6c
|
||||||
import json
|
import json
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Dict, List
|
from typing import List
|
||||||
|
|
||||||
import redis
|
|
||||||
|
|
||||||
import config
|
import config
|
||||||
|
from cache.abs_cache import AbstractCache
|
||||||
|
from cache.cache_factory import CacheFactory
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
from .types import IpInfoModel
|
from .types import IpInfoModel
|
||||||
|
@ -30,9 +30,9 @@ class ProxyProvider(ABC):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RedisDbIpCache:
|
class IpCache:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.redis_client = redis.Redis(host=config.REDIS_DB_HOST, password=config.REDIS_DB_PWD)
|
self.cache_client: AbstractCache = CacheFactory.create_cache(cache_type=config.CACHE_TYPE_MEMORY)
|
||||||
|
|
||||||
def set_ip(self, ip_key: str, ip_value_info: str, ex: int):
|
def set_ip(self, ip_key: str, ip_value_info: str, ex: int):
|
||||||
"""
|
"""
|
||||||
|
@ -42,7 +42,7 @@ class RedisDbIpCache:
|
||||||
:param ex:
|
:param ex:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
self.redis_client.set(name=ip_key, value=ip_value_info, ex=ex)
|
self.cache_client.set(key=ip_key, value=ip_value_info, expire_time=ex)
|
||||||
|
|
||||||
def load_all_ip(self, proxy_brand_name: str) -> List[IpInfoModel]:
|
def load_all_ip(self, proxy_brand_name: str) -> List[IpInfoModel]:
|
||||||
"""
|
"""
|
||||||
|
@ -51,13 +51,13 @@ class RedisDbIpCache:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
all_ip_list: List[IpInfoModel] = []
|
all_ip_list: List[IpInfoModel] = []
|
||||||
all_ip_keys: List[bytes] = self.redis_client.keys(pattern=f"{proxy_brand_name}_*")
|
all_ip_keys: List[str] = self.cache_client.keys(pattern=f"{proxy_brand_name}_*")
|
||||||
try:
|
try:
|
||||||
for ip_key in all_ip_keys:
|
for ip_key in all_ip_keys:
|
||||||
ip_value = self.redis_client.get(ip_key)
|
ip_value = self.cache_client.get(ip_key)
|
||||||
if not ip_value:
|
if not ip_value:
|
||||||
continue
|
continue
|
||||||
all_ip_list.append(IpInfoModel(**json.loads(ip_value)))
|
all_ip_list.append(IpInfoModel(**json.loads(ip_value)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
utils.logger.error("[RedisDbIpCache.load_all_ip] get ip err from redis db", e)
|
utils.logger.error("[IpCache.load_all_ip] get ip err from redis db", e)
|
||||||
return all_ip_list
|
return all_ip_list
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# @Author : relakkes@gmail.com
|
# @Author : relakkes@gmail.com
|
||||||
# @Time : 2024/4/5 09:32
|
# @Time : 2024/4/5 09:32
|
||||||
# @Desc : 极速HTTP代理提供类实现,官网地址:https://www.jisuhttp.com?pl=zG3Jna
|
# @Desc : 已废弃!!!!!倒闭了!!!极速HTTP 代理IP实现
|
||||||
import os
|
import os
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from proxy import IpGetError, ProxyProvider, RedisDbIpCache
|
from proxy import IpCache, IpGetError, ProxyProvider
|
||||||
from proxy.types import IpInfoModel
|
from proxy.types import IpInfoModel
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class JiSuHttpProxy(ProxyProvider):
|
||||||
"pw": "1", # 是否使用账密验证, 1:是,0:否,否表示白名单验证;默认为0
|
"pw": "1", # 是否使用账密验证, 1:是,0:否,否表示白名单验证;默认为0
|
||||||
"se": "1", # 返回JSON格式时是否显示IP过期时间, 1:显示,0:不显示;默认为0
|
"se": "1", # 返回JSON格式时是否显示IP过期时间, 1:显示,0:不显示;默认为0
|
||||||
}
|
}
|
||||||
self.ip_cache = RedisDbIpCache()
|
self.ip_cache = IpCache()
|
||||||
|
|
||||||
async def get_proxies(self, num: int) -> List[IpInfoModel]:
|
async def get_proxies(self, num: int) -> List[IpInfoModel]:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,7 +9,7 @@ from typing import Dict, List
|
||||||
import httpx
|
import httpx
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from proxy import IpGetError, IpInfoModel, ProxyProvider, RedisDbIpCache
|
from proxy import IpCache, IpInfoModel, ProxyProvider
|
||||||
from proxy.types import ProviderNameEnum
|
from proxy.types import ProviderNameEnum
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class KuaiDaiLiProxy(ProxyProvider):
|
||||||
self.api_base = "https://dps.kdlapi.com/"
|
self.api_base = "https://dps.kdlapi.com/"
|
||||||
self.secret_id = kdl_secret_id
|
self.secret_id = kdl_secret_id
|
||||||
self.signature = kdl_signature
|
self.signature = kdl_signature
|
||||||
self.ip_cache = RedisDbIpCache()
|
self.ip_cache = IpCache()
|
||||||
self.proxy_brand_name = ProviderNameEnum.KUAI_DAILI_PROVIDER.value
|
self.proxy_brand_name = ProviderNameEnum.KUAI_DAILI_PROVIDER.value
|
||||||
self.params = {
|
self.params = {
|
||||||
"secret_id": self.secret_id,
|
"secret_id": self.secret_id,
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import re
|
import re
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import redis
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from fastapi import FastAPI, HTTPException, status
|
from fastapi import FastAPI, HTTPException, status
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
import config
|
import config
|
||||||
|
from cache.abs_cache import AbstractCache
|
||||||
|
from cache.cache_factory import CacheFactory
|
||||||
from tools import utils
|
from tools import utils
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
redis_client = redis.Redis(host=config.REDIS_DB_HOST, password=config.REDIS_DB_PWD)
|
cache_client : AbstractCache = CacheFactory.create_cache(cache_type=config.CACHE_TYPE_MEMORY)
|
||||||
|
|
||||||
|
|
||||||
class SmsNotification(BaseModel):
|
class SmsNotification(BaseModel):
|
||||||
|
@ -53,7 +54,7 @@ def receive_sms_notification(sms: SmsNotification):
|
||||||
if sms_code:
|
if sms_code:
|
||||||
# Save the verification code in Redis and set the expiration time to 3 minutes.
|
# Save the verification code in Redis and set the expiration time to 3 minutes.
|
||||||
key = f"{sms.platform}_{sms.current_number}"
|
key = f"{sms.platform}_{sms.current_number}"
|
||||||
redis_client.set(key, sms_code, ex=60 * 3)
|
cache_client.set(key, sms_code, expire_time=60 * 3)
|
||||||
|
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Author : relakkes@gmail.com
|
||||||
|
# @Name : 程序员阿江-Relakkes
|
||||||
|
# @Time : 2024/6/2 10:35
|
||||||
|
# @Desc :
|
||||||
|
|
||||||
|
import time
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from cache.local_cache import ExpiringLocalCache
|
||||||
|
|
||||||
|
|
||||||
|
class TestExpiringLocalCache(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.cache = ExpiringLocalCache(cron_interval=10)
|
||||||
|
|
||||||
|
def test_set_and_get(self):
|
||||||
|
self.cache.set('key', 'value', 10)
|
||||||
|
self.assertEqual(self.cache.get('key'), 'value')
|
||||||
|
|
||||||
|
def test_expired_key(self):
|
||||||
|
self.cache.set('key', 'value', 1)
|
||||||
|
time.sleep(2) # wait for the key to expire
|
||||||
|
self.assertIsNone(self.cache.get('key'))
|
||||||
|
|
||||||
|
def test_clear(self):
|
||||||
|
# 设置两个键值对,过期时间为11秒
|
||||||
|
self.cache.set('key', 'value', 11)
|
||||||
|
# 睡眠12秒,让cache类的定时任务执行一次
|
||||||
|
time.sleep(12)
|
||||||
|
self.assertIsNone(self.cache.get('key'))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
del self.cache
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -0,0 +1,40 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @Author : relakkes@gmail.com
|
||||||
|
# @Name : 程序员阿江-Relakkes
|
||||||
|
# @Time : 2024/6/2 19:54
|
||||||
|
# @Desc :
|
||||||
|
|
||||||
|
import time
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from cache.redis_cache import RedisCache
|
||||||
|
|
||||||
|
|
||||||
|
class TestRedisCache(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.redis_cache = RedisCache()
|
||||||
|
|
||||||
|
def test_set_and_get(self):
|
||||||
|
self.redis_cache.set('key', 'value', 10)
|
||||||
|
self.assertEqual(self.redis_cache.get('key'), 'value')
|
||||||
|
|
||||||
|
def test_expired_key(self):
|
||||||
|
self.redis_cache.set('key', 'value', 1)
|
||||||
|
time.sleep(2) # wait for the key to expire
|
||||||
|
self.assertIsNone(self.redis_cache.get('key'))
|
||||||
|
|
||||||
|
def test_keys(self):
|
||||||
|
self.redis_cache.set('key1', 'value1', 10)
|
||||||
|
self.redis_cache.set('key2', 'value2', 10)
|
||||||
|
keys = self.redis_cache.keys('*')
|
||||||
|
self.assertIn('key1', keys)
|
||||||
|
self.assertIn('key2', keys)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# self.redis_cache._redis_client.flushdb() # 清空redis数据库
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -39,7 +39,7 @@ class Slide:
|
||||||
"q=0.8,application/signed-exchange;v=b3;q=0.9",
|
"q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||||
"Accept-Encoding": "gzip, deflate, br",
|
"Accept-Encoding": "gzip, deflate, br",
|
||||||
"Accept-Language": "zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7,ja;q=0.6",
|
"Accept-Language": "zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7,ja;q=0.6",
|
||||||
"Cache-Control": "max-age=0",
|
"AbstractCache-Control": "max-age=0",
|
||||||
"Connection": "keep-alive",
|
"Connection": "keep-alive",
|
||||||
"Host": urlparse(img).hostname,
|
"Host": urlparse(img).hostname,
|
||||||
"Upgrade-Insecure-Requests": "1",
|
"Upgrade-Insecure-Requests": "1",
|
||||||
|
|
Loading…
Reference in New Issue