JAVA网络爬虫
HttpClient

导航

 

频率组件

  1. 频率组件的使用方式

    • 定义一个频率类

      class RateThrottle():
        	def allow_request(request, self):
            	if 没有超过限制:
                	return True
              else:
              		return False  	
                
          def wait(self):
            	return 10
      
    • 指定频率类

      class BookView(APIView):
        	throttle_classes = [RateThrottle]
      

局部频率组件

  1. 使用DRF的简单频率控制来控制用户访问频率

    • 导入模块

      from rest_framework.throttling import SimpleRateThrottle
      
    • 定义并继承SimpleRateThrottle

      class RateThrottle(SimpleRateThrottle):
        	# 指定访问频率
        	# 指定每分钟5次   想指定每小时5次  5/h
        	rate = "5/m"
          
          # 指定通过什么方式来区分用户
          def get_cache_key(self, request, view):
            	# 根据用户的ip地址
            	return self.get_ident(request)
      
    • 指定频率类

      class BookView(APIView):
        	throttle_classes = [RateThrottle]
      

局部频率案例

  • model.py

    from django.db import models
    
    from datetime import datetime
    # from django.contrib.auth.models import AbstractUser
    
    
    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name="用户名")
        password = models.CharField(max_length=40, verbose_name="用户密码")
        user_type_entry = (
            (1, "Delux"),
            (2, "SVIP"),
            (3, "VVIP")
        )
        user_type = models.IntegerField(choices=user_type_entry)
    
        class Meta:
            db_table = "db_user_info"
            verbose_name = "用户信息"
            verbose_name_plural = verbose_name
    
        def get_user_type_display(self):
            return self.user_type_entry[self.user_type]
    
    
    class UserToken(models.Model):
        # OneToOneField一对一关系
        # on_delete=models.CASCADE 当UserInfo数据表里面的数据被删除后UserToken里面的数据也随着被删除
        user = models.OneToOneField("UserInfo", on_delete=models.CASCADE, verbose_name="一对一关系")
        token = models.CharField(max_length=128, verbose_name="token")
    
        class Meta:
            db_table = "db_user_token"
            verbose_name = "用户token"
            verbose_name_plural = verbose_name
    
    
    class AuthorInfo(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者名称")
        age = models.IntegerField(verbose_name="作者年龄")
    
        class Meta:
            db_table = "db_author_info"
            verbose_name = "作者信息"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class PublishInfo(models.Model):
        name = models.CharField(max_length=32, verbose_name="出版社名称")
        city = models.CharField(max_length=32, verbose_name="出版社所在城市")
        email = models.EmailField(verbose_name="出版社邮箱")
    
        class Meta:
            db_table = "db_publish_info"
            verbose_name = "出版社信息"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.name
    
    
    class BookInfo(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")
        publishDate = models.DateField(default=datetime.now, verbose_name="出版日期")
    
        # max_digits小数位加整数位多少长度 decimal_places小数位长度为2
        price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="图书价格")
        publish = models.ForeignKey(PublishInfo, related_name="book", related_query_name="book_query", on_delete=models.CASCADE, verbose_name="出版社")
        # ManyToManyField多对多
        authors = models.ManyToManyField(AuthorInfo, verbose_name="图书作者")
    
        class Meta:
            db_table = "db_book_info"
            verbose_name = "图书信息"
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.title
    
    
  • url.py

    from django.urls import re_path
    from .views import UserView, BookView
    
    urlpatterns = [
        re_path(r"^books/$", BookView.as_view({
            "get": "list",
            "post": "create"
        })),
    
        re_path(r"^books/(?P<pk>\d+)/$", BookView.as_view({
            "get": "retrieve",
            "put": "update",
            "delete": "destroy"
        })),
    
        re_path(r"^user/$", UserView.as_view())
    ]
    
    
  • 定义频率类

    from rest_framework.throttling import SimpleRateThrottle
    
    
    class RateThrottle(SimpleRateThrottle):
      	# 指定访问频率
      	# 指定每分钟5次   想指定每小时5次  5/h
        rate = "5/m"
    
        # 指定通过什么方式来区分用户
        def get_cache_key(self, request, view):
          	# 根据用户的ip地址
            return self.get_ident(request)
    
    
  • views.py

    from django.shortcuts import render
    from django.http import JsonResponse
    
    from rest_framework.views import APIView
    from rest_framework.viewsets import ModelViewSet
    from rest_framework.exceptions import APIException
    from rest_framework.authentication import BaseAuthentication
    
    from .models import BookInfo, PublishInfo, AuthorInfo, UserInfo, UserToken
    from .app_serializers import BookSerializer
    from .utils import get_token, app_throttles
    
    
    # 定义认证类
    class UserAuth(BaseAuthentication):
        # 所有的逻辑都在authenticate上写
        def authenticate(self, request):
            # 获取token值
            user_token = request.GET.get("token", "")
            if user_token:
                try:
                    # 查询token值看有没有认证过的token
                    token = UserToken.objects.get(token=user_token)
                    # 后面权限会用到
                    # token.user.username赋值给了request.user, 可以去看源码
    
                    return token.user, token.token
                except UserToken.DoesNotExist:
                    raise APIException("没有认证")
            else:
                raise APIException("没有认证")
    
    
    class UserPerm(object):
        # 必须是message, 因为源码用的是message, 我们这里用message就是覆盖掉源码
        # 所以返回为假时, 我们可以用message自定义你想返回给用户看到的信息
        message = "您没有查看该数据的权限!"
    
        # 这是对所有数据
        # 这个has_permission也是重写的
        # 用户有权限必须返回真, 用户没权限必须返回假  不懂看, 源码
        def has_permission(self, request, view):
            if request.user.user_type == 1:
                # request.user 获取到 认证组件返回的用户对象
                # type是用户表中的一个字段
                # 这里如果等于3就代表该用户有看这个数据的权限, 返回能代表真的信息就行
                return True
            # 这里返回的东西必须需是能代表假, 因为用户没有这个权限, 所以不能等它看到数据
            return False
    
        # 这是对单条数据
        def has_object_permission(self, request, view, obj):
            if request.user.user_type == 1:
            	# request.user 获取到 认证组件返回的用户对象
                # type是用户表中的一个字段
                # 这里如果等于3就代表该用户有看这个数据的权限, 返回能代表真的信息就行
                return True
       	 	# 这里返回的东西必须需是能代表假, 因为用户没有这个权限, 所以不能等它看到数据
            return False
    
    
    class BookView(ModelViewSet):
        # 指定认证类 UserAuth
        authentication_classes = [UserAuth]
        # 指定权限类
        permission_classes = [UserPerm]
        # 指定评率类
        throttle_classes = [app_throttles.RateThrottle]
        queryset = BookInfo.objects.all()
        serializer_class = BookSerializer
    
    
    class UserView(APIView):
    
        def post(self, request):
    
            response = dict()
    
            # 定义需要的用户信息
            fields = {"username", "password"}
            # 定义一个用户信息字典
            user_info = dict()
    
            # fields.issubset表示 fields是request.data.keys()的子集就显示True, 相反False
            if fields.issubset(set(request.data.keys())):
                # username = request.data.get("username", "")
                # password = request.data.get("password", "")
                for key in fields:
                    user_info[key] = request.data[key]
    
            if user_info:
                # **user_info字典拆包 拆包成键值对, 而不是整个字典了 列 {"a":"bb"} 拆包成 a="bb"
                user_instance = UserInfo.objects.filter(**user_info).first()
    
                if user_instance is not None:
                    access_token = get_token.generate_token()
    
                    # 根据user=user_instance找到了直接更新, 把default的值复制给它
                    # 没有找到直接创建
                    # 意思就是有这个token更新token, 没有这个token创建一个token
                    UserToken.objects.update_or_create(user=user_instance, defaults={
                        "token": access_token
                    })
    
                    response["status_code"] = 200
                    response["status_message"] = "登入成功"
                    response["access_token"] = access_token
                    response["user_role"] = user_instance.get_user_type_display()
                else:
                    response["status_code"] = 201
                    response["status_message"] = "登入失败, 用户名或密码错误"
    
                return JsonResponse(response)
            else:
                return JsonResponse({"error": "参数不完整"})
    
  • postman效果图, 1分钟内连续访问5次
    在这里插入图片描述

全局频率组件

  1. 使用DRF的简单频率控制来控制用户访问频率(全局)

    • 导入模块

      from rest_framework.throttling import SimpleRateThrottle
      
    • 定义并继承SimpleRateThrottle

      class RateThrottle(SimpleRateThrottle):
        	# 指定访问频率
        	# 这个键可以自定义所以不是非要定义成visit_rate
        	scope = "visit_rate"
          
          # 指定通过什么方式来区分用户
          def get_cache_key(self, request, view):
            	# 根据用户的ip地址
            	return self.get_ident(request)
      
    • 在settings里面指定频率类和访问频率, 用了全局的把视图里指定的频率类注释掉, 其他同上

      REST_FRAMEWORK = {
      	# 动态导入模块
          "DEFAULT_THROTTLE_CLASSES": ("serializer.utils.app_throttles.RateThrottle", ),
          # 指定每分钟只能访问5次
          "DEFAULT_THROTTLE_RATES": {
              "visit_rate": "5/m"
          }
      }
      
    1. postman效果图, 1分钟内连续访问5次
      在这里插入图片描述
posted on 2019-07-29 12:12  gmlgxx  阅读(37)  评论(0)    收藏  举报