利用 Python-user-agents 解析 User_Agent

利用 Python-user-agents 解析 User_Agen

需求分析

近期在尝试做一个登录日志的功能,及用户登录成功后我在后台进行一个用户的登录记录,两种解决方案:

  1. 由前端得到用户的手机型号,我在后台接收后在数据库进行保存
  2. 使用User_Agent, 它通过解析(浏览器/HTTP) user agent 字符串,提供了一种简单的方法,来识别/检测手机、平板等设备及其功能。目标是可靠地检测:设备是手机,平板还是电脑;是否有触摸屏。

用法

各种基本信息可以帮忙识别访问者,比如设备,操作系统,浏览器等属性


from user_agents import parse# iPhone's user agent string
ua_string = 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B179 Safari/7534.48.3'
user_agent = parse(ua_string) # 解析成user_agent# Accessing user agent's browser attributes
user_agent.browser # returns Browser(family=u'Mobile Safari', version=(5, 1), version_string='5.1')
user_agent.browser.family # returns 'Mobile Safari'
user_agent.browser.version # returns (5, 1)
user_agent.browser.version_string # returns '5.1'# Accessing user agent's operating system properties
user_agent.os # returns OperatingSystem(family=u'iOS', version=(5, 1), version_string='5.1')
user_agent.os.family # returns 'iOS'
user_agent.os.version # returns (5, 1)
user_agent.os.version_string # returns '5.1'# Accessing user agent's device properties
user_agent.device # returns Device(family=u'iPhone', brand=u'Apple', model=u'iPhone')
user_agent.device.family # returns 'iPhone'
user_agent.device.brand # returns 'Apple'
user_agent.device.model # returns 'iPhone'# Viewing a pretty string version
str(user_agent) # returns "iPhone / iOS 5.1 / Mobile Safari 5.1"
# 最后这个最好用

目前还支持这些属性:

  • is_mobile:判断是不是手机
  • is_tablet:判断是不是平板
  • is_pc:判断是不是电脑
  • is_touch_capable:有没有触屏功能
  • is_bot:是不是搜索引擎的爬虫

from user_agents import parse# Let's start from an old, non touch Blackberry device
ua_string = 'BlackBerry9700/5.0.0.862 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/331 UNTRUSTED/1.0 3gpp-gba'
user_agent = parse(ua_string)
user_agent.is_mobile # returns True
user_agent.is_tablet # returns False
user_agent.is_touch_capable # returns False
user_agent.is_pc # returns False
user_agent.is_bot # returns False
str(user_agent) # returns "BlackBerry 9700 / BlackBerry OS 5 / BlackBerry 9700"

常见机型映射字典

map_phone = {'Apple': 'Apple', 'KIW-AL10': 'Huawei', 'PRA-TL10': 'Huawei', 'BND-AL00': 'Huawei', 'XiaoMi': 'XiaoMi', 'MIX 2': 'XiaoMi', 'Oppo': 'Oppo', ' Oppo': 'Oppo', 'Gionee': 'Gionee', 'Samsung': 'Samsung', 'PRA-AL00X': 'Huawei', 'PACM00': 'Oppo', 'PBET00': 'Oppo', 'R7Plusm': 'Oppo', 'PAAT00': 'Oppo', 'PBAM00': 'Oppo', 'PADM00': 'Oppo', 'PAFM00': 'Oppo', 'PBEM00': 'Oppo', 'PAAM00': 'Oppo', 'PBBM00': 'Oppo', 'PACT00': 'Oppo', 'V1809A': 'vivo', 'PBAT00': 'Oppo', 'PADT00': 'Oppo', 'BND-TL10': 'Huawei', 'PBBT00': ' Oppo', 'PBCM10': 'Oppo', 'Mi Note 3': 'XiaoMi', 'V1816A': 'vivo', 'V1732T': 'vivo', 'V1813A': 'vivo', 'V1732A': 'vivo', 'V1818A':'vivo','CAM-TL00':'Huawei','Le X620':'leshi','M6 Note':'meizu','m3 note':'meizu','M5':'meizu','M1 E ':'meizu','BLN-AL10':'Huawei','M5 Note':'meizu','PRA-AL00':'honour','LND-AL30':'honour','NEM-AL10':'honour','BND-AL10':'honour','CAM-AL00':'honour','SCL-TL00':'honour','LLD-AL30':'honour','BLN-AL20':'honour','AUM-AL20':'honour','JSN-AL00':'honour','LLD-AL10':'honour','BLN-TL10':'honour','LLD-AL20':'honour','BLN-AL40':'honour','MYA-AL10':'honour','LLD-AL00':'honour','JSN-AL00a':'honour','JMM-AL10':'honour','DLI-AL10':'honour','JMM-AL00':'honour','V1809T':'vivo','LND-AL40':'honour','PLK-AL10':'honour','MX6':'meizu','PLK-TL01H':'honour','S9':'Samsung','KIW-TL00':'honour','V1813T':'vivo'}
  1. 常见的User_Agent各字段的解释
  • Mozilla/5.0: 网景公司浏览器的标识,由于互联网初期浏览器市场主要被网景公司占领,很多服务器被设置成仅响应含有标志为Mozilla的浏览器的请求,因此,新款的浏览器为了打入市场,不得不加上这个字段。
  • Windows NT 6.3 : Windows 8.1的标识符
  • WOW64: 32位的Windows系统运行在64位的处理器上
  • AppleWebKit/537.36:苹果公司开发的呈现引擎
  • KHTML:是Linux平台中Konqueror浏览器的呈现引擎KHTML
  • Geckeo:呈现引擎
  • like Gecko:表示其行为与Gecko浏览器引擎类似
  1. 请求中为什么既含有Chrome/33.0.1750.29又含有Safari/537.36字段?
    因为AppleWebKit渲染引擎是苹果公司开发的,而Google公司要采用它,为了获得服务器端的正确响应,仅在Safari浏览器UA字段中增加了Chrome字段。
    例如:
  • Safari浏览器的UA:Mozilla/5.0 (平台;加密类型;操作系统或CPU;语言)AppleWebKit/AppleWebKit版本号(KHTML, like Gecko) Safari/Safari 版本号
  • Chrome浏览器的UA:Mozilla/5.0 (平台;加密类型;操作系统或CPU;语言)AppleWebKit/AppleWebKit版本号 (KHTML, like Gecko) Chrome/
  • Chrome 版本号 Safari/Safari 版本号
  1. 为什么UA中包含多个浏览器的标识,如:Mozilla/5.0、Chrome/33.0.1750.29、Safari/537.36,以及渲染引擎标识?

多增加一些字段都是为了让服务器检测到它支持的浏览器标识,以便获得服务器的响应,从而提升用户体验。

这里有一个demo代码请参考

"""
Request工具类
"""
import json
import loggingfrom django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.urls.resolvers import ResolverMatch
from user_agents import parsefrom apps.vadmin.utils.authentication import OpAuthJwtAuthenticationlogger = logging.getLogger(__name__)def get_request_user(request, authenticate=True):"""获取请求user(1)如果request里的user没有认证,那么则手动认证一次:param request::param authenticate::return:"""user: AbstractBaseUser = getattr(request, 'user', None)if user and user.is_authenticated:return usertry:user, tokrn = OpAuthJwtAuthentication().authenticate(request)except Exception as e:passreturn user or AnonymousUser()def get_request_ip(request):"""获取请求IP:param request::return:"""ip = getattr(request, 'request_ip', None)if ip:return ipip = request.META.get('REMOTE_ADDR', '')if not ip:x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '')if x_forwarded_for:ip = x_forwarded_for.split(',')[-1].strip()else:ip = 'unknown'return ipdef get_request_data(request):"""获取请求参数:param request::return:"""request_data = getattr(request, 'request_data', None)if request_data:return request_datadata: dict = {**request.GET.dict(), **request.POST.dict()}if not data:try:body = request.bodyif body:data = json.loads(body)except Exception as e:passif not isinstance(data, dict):data = {'data': data}return datadef get_request_path(request, *args, **kwargs):"""获取请求路径:param request::param args::param kwargs::return:"""request_path = getattr(request, 'request_path', None)if request_path:return request_pathvalues = []for arg in args:if len(arg) == 0:continueif isinstance(arg, str):values.append(arg)elif isinstance(arg, (tuple, set, list)):values.extend(arg)elif isinstance(arg, dict):values.extend(arg.values())if len(values) == 0:return request.pathpath: str = request.pathfor value in values:path = path.replace('/' + value, '/' + '{id}')return pathdef get_request_canonical_path(request, *args, **kwargs):"""获取请求路径:param request::param args::param kwargs::return:"""request_path = getattr(request, 'request_canonical_path', None)if request_path:return request_pathpath: str = request.pathresolver_match: ResolverMatch = request.resolver_matchfor value in resolver_match.args:path = path.replace(f"/{value}", "/{id}")for key, value in resolver_match.kwargs.items():if key == 'pk':path = path.replace(f"/{value}", f"/{{id}}")continuepath = path.replace(f"/{value}", f"/{{{key}}}")return pathdef get_browser(request, *args, **kwargs):"""获取浏览器名:param request::param args::param kwargs::return:"""ua_string = request.META['HTTP_USER_AGENT']user_agent = parse(ua_string)return user_agent.get_browser()def get_os(request, *args, **kwargs):"""获取操作系统:param request::param args::param kwargs::return:"""ua_string = request.META['HTTP_USER_AGENT']user_agent = parse(ua_string)return user_agent.get_os()def get_login_location(request, *args, **kwargs):"""获取ip 登录位置:param request::param args::param kwargs::return:"""import requestsimport eventlet  # 导入eventlet这个模块request_ip = get_request_ip(request)# 从缓存中获取location = cache.get(request_ip)if location:return location# 通过api 获取,再缓存redistry:eventlet.monkey_patch(thread=False)  # 必须加这条代码with eventlet.Timeout(2, False):  # 设置超时时间为2秒apiurl = "http://whois.pconline.com.cn/ip.jsp?ip=%s" % request_ipr = requests.get(apiurl)content = r.content.decode('GBK')location = str(content).replace('\r', '').replace('\n', '')[:64]cache.set(request_ip, location, 86400)return locationexcept Exception as e:passreturn ""def get_verbose_name(queryset=None, view=None, model=None):"""获取 verbose_name:param request::param view::return:"""try:if queryset and hasattr(queryset, 'model'):model = queryset.modelelif view and hasattr(view.get_queryset(), 'model'):model = view.get_queryset().modelelif view and hasattr(view.get_serializer(), 'Meta') and hasattr(view.get_serializer().Meta, 'model'):model = view.get_serializer().Meta.modelif model:return getattr(model, '_meta').verbose_nameexcept Exception as e:passreturn ""

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/69830.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TF_SessionRun()各参数

如何使用Tensorflow C-API保存Tensorflow模型 C api中的所有操作都通过TF_SessionRun()函数执行。 此函数有12个参数: TF_CAPI_EXPORT extern void TF_SessionRun(TF_Session *session, // Pointer to a TF sessionconst TF_Buffer *run_options, //…

Linux中7种文件类型

Linux中文件类型 Linux中一切皆为文件。 查看文件类型(输入以下命令根据第一列的第一个字符可区别文件类型) ls -l目录文件 第一个字符为d 类似于Windows文件夹。 链接文件(软链接) 第一个字符为l 例如Windows的快捷方式&…

JDK7多线程并发环境HashMap死循环infinite loop,CPU拉满100%,Java

JDK7多线程并发环境HashMap死循环infinite loop,CPU拉满100%,Java HashMap底层数据实现是数组链表,链表在哈希碰撞后装入新数据,像是一个桶。 HashMap在JDK7的实现中,并发环境存在死循环infinite loop问题。导致的结果…

算法训练第五十七天

516. 最长回文子序列 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; class Solution { public:int longestPalindromeSubseq(string s) {vector<vector<int>> dp(s.size(),vector<int>(s.size(),0));for(int i 0;i < s.size();i){dp[i][i]…

PostgreSQL在进行除法时要注意

背景 整型除以整型&#xff0c;正常情况下当然得到的应该也是整型。数据库也是这么干的。 但是在数据库应用中&#xff0c;通常业务的需求是得到NUMERIC&#xff0c;不能直接把小数干掉。 数据库的行为给用户带来了诸多不便&#xff0c;例如1除以2&#xff0c;如果是整型除法会…

异常-java

目录 一、异常的概念和体系结构 1.1 异常的概念 1.2 异常的体系结构 1.3 异常的分类 二、异常的处理 2.1 防御式编程 2.2 异常抛出 2.3 异常捕获 2.4 异常处理流程 三、自定义异常类 一、异常的概念和体系结构 1.1 异常的概念 程序员在开发过程中&#xff0c;想要将代码写得…

<C++> STL_set/map

1.关联式容器 CSTL包含了序列式容器和关联式容器&#xff1a; 序列式容器里面存储的是元素本身&#xff0c;其底层为线性序列的数据结构。比如&#xff1a;vector&#xff0c;list&#xff0c;deque&#xff0c;forward_list(C11)等。关联式容器里面存储的是<key, value&g…

Centos7 + Apache Ranger 2.4.0 部署

一、Ranger简介 Apache Ranger提供一个集中式安全管理框架, 并解决授权和审计。它可以对Hadoop生态的组件如HDFS、Yarn、Hive、Hbase等进行细粒度的数据访问控制。通过操作Ranger控制台,管理员可以轻松的通过配置策略来控制用户访问权限。 1、组件列表 # Service Name Liste…

Springboot - 13.spring-boot-starter-security集成

&#x1f440;Spring Boot Starter Security 中文文档 Spring Security中文文档 &#x1f440;Spring Boot Starter Security 运行流程 当然可以。首先&#xff0c;我们会将用户存储和认证的流程融入整个Spring Boot Starter Security的使用流程中。以下是当你使用Spring Bo…

Excel VSTO开发4 -其他事件

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 4 其他事件 针对插件的事件主要有Startup、Shutdown这两个事件&#xff0c;在第2节中已经讲解。在开发窗口中&#xff0c;选择对象…

微信小程序检查版本更新

新建文件 version-util.js // 小程序启动时检查版本 class VersionUtil {/*** 检查更新*/checkUpdate(){const updateManager wx.getUpdateManager();updateManager.onCheckForUpdate((hasUpdate)>{if(hasUpdate){updateManager.onUpdateReady(()>{wx.showModal({title…

“谁天生是项目经理?四大特质决定你的机会“

大家好&#xff0c;我是老原。 但其实不少刚开始尝试项目管理的人&#xff0c;包括老原自己也曾经遇到过这样的问题&#xff1a; ▪ 自己没权没势&#xff0c;大家凭什么听我的&#xff1f; ▪ 资源受限&#xff0c;如何向老板争取更多资源&#xff1f; ▪ 怎样才能推进多方…

WebAssembly 在云原生中的实践指南

1 WebAssembly 介绍 WebAssembly&#xff08;Wasm&#xff09;是一种通用字节码技术&#xff0c;它可以将其他编程语言&#xff08;如 Go、Rust、C/C 等&#xff09;的程序代码编译为可在浏览器环境直接执行的字节码程序。 WebAssembly 的初衷之一是解决 JavaScript 的性能问…

【月报】Aavegotchi 开发进度更新 - 2023 年 8 月

嗨&#xff0c;Gotchigang&#xff01;2023 年的进程已经过了一半&#xff0c;我们团队一直在努力推动 Aavegotchi 生态系统迈向新的高度&#xff01;在本月的开发更新中&#xff0c;我们将分享在以下方面取得的进展&#xff1a; ● Gotchi 游戏 ● Gotchichain ● Aavegotc…

【iVX】十五分钟制作一款小游戏,iVX真有怎么神?

个人主页&#xff1a;【&#x1f60a;个人主页】 新人博主&#xff0c;喜欢就关注一下呗~ 文章目录 前言iVX介绍初上手布置背景制作可移动物体总结&#xff08;完善步骤&#xff09; 前言 在上篇文章中&#xff0c;我向大家介绍了一种打破常规的编程方式——iVX&#xff0c;可…

Go map转json

在Go中如何返回前端 字段名称/数量都不确定的json数据&#xff1f; 之前用Go写web服务&#xff0c;返回给前端的json格式的接口&#xff0c;有哪些要返回的字段都是明确的。都是预先定义一个结构体&#xff0c;json.Marshal一下即可~ 但当有的场景&#xff0c;要返回哪些字段不…

代码随想录day43|1049. 最后一块石头的重量 II494. 目标和474. 一和零

1049. 最后一块石头的重量 II class Solution:def lastStoneWeightII(self, stones: List[int]) -> int:target int(sum(stones)/2)dp [0] * (target1)for i in stones:for j in range(target ,-1 ,-1):if j>i:dp[j] max(dp[j],dp[j-i]i)# print(dp)return sum(stone…

RabbitMQ:hello结构

1.在Linux环境上面装入rabbitMQ doker-compose.yml version: "3.1" services:rabbitmq:image: daocloud.io/library/rabbitmq:managementrestart: alwayscontainer_name: rabbitmqports:- 6786:5672- 16786:15672volumes:- ./data:/var/lib/rabbitmq doker-compos…

【C++】函数重载 ④ ( 函数指针定义的三种方式 | 直接定义函数指针 | 通过 函数类型 定义 函数指针 | 通过 函数指针类型 定义 函数指针 )

文章目录 一、函数指针定义方法1、直接定义函数指针2、通过 函数类型 定义 函数指针3、通过 函数指针类型 定义 函数指针4、代码示例 - 不同方式定义函数指针 博客总结 : 重载函数 : 使用 相同 的 函数名 , 定义 不同 的 函数参数列表 ;判定标准 : 只有 函数参数 的 个数 / 类…

ConfigMaps in K8s

摘要 ConfigMaps是Kubernetes&#xff08;K8s&#xff09;中用于存储应用程序配置信息的一种资源对象。它将key-value对存储为Kubernetes集群中的一个资源&#xff0c;并可以在Pod中以卷或环境变量的形式使用。 ConfigMaps的设计目的是将应用程序配置与应用程序本身解耦。它可…