利用 Python-user-agents 解析 User_Agent
利用 Python-user-agents 解析 User_Agen
需求分析
近期在尝试做一个登录日志的功能,及用户登录成功后我在后台进行一个用户的登录记录,两种解决方案:
- 由前端得到用户的手机型号,我在后台接收后在数据库进行保存
- 使用
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'}
- 常见的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浏览器引擎类似
- 请求中为什么既含有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 版本号
- 为什么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 ""
相关文章:
利用 Python-user-agents 解析 User_Agent
利用 Python-user-agents 解析 User_Agen 需求分析 近期在尝试做一个登录日志的功能,及用户登录成功后我在后台进行一个用户的登录记录,两种解决方案: 由前端得到用户的手机型号,我在后台接收后在数据库进行保存使用User_Agent…...

Java版企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis
功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看…...
Mybatis如何给字段起别名?
Mybatis如何给字段起别名? 假如有一个学生表,有一个字段是class,你的实体类变量肯定不能用class,那么如何起别名? 通过以下代码实现 Result(column "class",property "clas")mapper代码 pub…...

php对接AWS S3云存储,上传S3及访问权限问题
首先先下载sdk包 https://docs.aws.amazon.com/zh_cn/sdk-for-php/v3/developer-guide/getting-started_installation.html S3创建存储桶 去安全凭证-》创建访问秘钥 创建的时候会提示,主账号创建不安全,这个时候我们需要创建一个IAM账号来创建秘钥 创…...
java 实现单例模式
单例模式是一种设计模式,用于确保一个类只有一个实例,并提供一种全局访问该实例的方式。在Java中,可以使用多种方式来实现单例模式,下面整理了几种常见的实现方式。 饿汉式单例模式(Eager Initialization)&…...
minio文件服务器开启https
一、准备证书 你要有https安全证书,我的是适用于nginx的证书 私钥 xxxx.key 公钥 xxxx.pem 二、上传证书到minio服务器 然后看看你的minio docker 有没有把 /root/.minio 挂载在主机上,如果有那么把两个证书文件放在/root/.minio/certs目录里面。…...

每日刷题(回溯法经典问题之子集)
食用指南:本文为作者刷题中认为有必要记录的题目 前置知识:回溯法经典问题之组合 ♈️今日夜电波:想着你—郭顶 1:09 ━━━━━━️💟──────── 4:15 …...
PostgreSQL在进行除法时要注意
背景 整型除以整型,正常情况下当然得到的应该也是整型。数据库也是这么干的。 但是在数据库应用中,通常业务的需求是得到NUMERIC,不能直接把小数干掉。 数据库的行为给用户带来了诸多不便,例如1除以2,如果是整型除法会…...

开开心心带你学习MySQL数据库之第五篇
😺欢迎来到我的博客, 记得点赞👍收藏⭐️留言✍️🐱 🐉做为一个怪兽,我的目标是少消灭一个奥特曼🐉 📖希望我写的博客对你有所帮助,如有不足,请指正📖 chatgpt 是否能够代替程序猿?…...
Geotools对geojson的解析
在 GeoTools 中,对 GeoJSON 的支持是通过一个插件来完成的,用户同样可以在 Maven 的 pom.xml 配置文件中添加下述的依赖。 <dependency><groupId>org.geotools</groupId><artifactId>gt-geojson</artifactId><version&…...
【博客701】shell实现保留网络现场:ping失败时执行mtr
shell实现保留网络现场:ping失败时执行mtr 场景 当我们网络出现抖动,到某个目的地ping不通时,我们想知道路径上哪里出现问题时可以在那时候执行mtr并保留下现场以供排查 实现:ping_and_mtr.sh #!/bin/bash# 定义要ping的IP地址列…...

放弃手写代码吧!用低代码你能生成各种源码
很多同学不知道为什么要用Low-code做开发,传统IT开发不行么?当然可以。 传统IT自研软件开发,通过编程去写代码,还有数据库、API、第三方基础架构等。这个方式很好,但不可避免的会带来开发周期长、难度大,技…...
什么程度才算精通 Linux?
前言 Linux 的优秀之处自然不必多说。 如果将操作系统比作一辆汽车,那 Linux 就是一辆性能出色的多功能越野车,上山下海飞天无所不能。 如果你拥有了它,一定不会只满足于驾驶它上下班,不能只会挂挡、踩油门和控制方向之类的基本…...
jmeter中的__setProperty用法
__setProperty 是一个用于设置 JMeter 属性的函数,基本语法: __setProperty(property, value)** property : 是要设置的属性的名称 ** value : 是要设置的属性的值在 JMeter中,可以使用 __setProperty 函数的元素: BeanShell …...

vue基础知识六:v-show和v-if有什么区别?使用场景分别是什么?
一、v-show与v-if的共同点 我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含v-else),都能控制元素在页面是否显示 在用法上也是相同的 <Model v-show"isShow" /> <Model v-if"isShow" />当表达式为true的时候&#…...
SpringBoot几个常用的注解
(1)RestController和Controller指定一个类,作为控制器的注解 (2)RequestMapping方法级别的映射注解,这一个用过Spring MVC的小伙伴相信都很熟悉 (3)EnableAutoConfiguration和Spri…...
腾讯JAVA后端秋招面试总结
腾讯秋招的面经,岗位是 java 后端开发。 说一下BIO、NIO和AIO 答: BIO是阻塞IO。在上一个线程的任务执行完之前,该线程必须阻塞等待上一个线程执行完毕。 NIO是非阻塞IO。一旦是响应事件发生了,该线程就会将对应的响应事件交给对应的事件处理器进行处理。 AIO是异步IO。主…...

随着iPhone 15降临,是时候扔掉所有的Lightning充电器了
自从苹果推出Lightning端口(一直追溯到iPhone 5)十多年后,你可能已经积累了相当多的Lightning电缆和配件。好吧,在下周的苹果活动之前,所有关于iPhone 15的传言都表明你不再需要它们了。 与最好的iPad和最好的MacBook…...

huggingface 使用入门笔记
概念 Hugging Face Hub和 Github 类似,都是Hub(社区)。Hugging Face可以说的上是机器学习界的Github。Hugging Face为用户提供了以下主要功能: 模型仓库(Model Repository):Git仓库可以让你管理代码版本、…...
ASP.NET Core 中的 Razor Pages
Razor Pages Razor Pages 是基于页面的 ASP.NET Core Web App 架构。 相比 MVC 模式,Razor Pages的生产效率更快。 Razer Pages 需要两个中间件: builder…Services.AddRazorPages 添加 Razor Pages servicesapp.MapRazorPages 添加 Razor Pages endpo…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...