当前位置: 首页 > news >正文

利用 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 ""

相关文章:

利用 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 中&#xff0c;对 GeoJSON 的支持是通过一个插件来完成的&#xff0c;用户同样可以在 Maven 的 pom.xml 配置文件中添加下述的依赖。 <dependency><groupId>org.geotools</groupId><artifactId>gt-geojson</artifactId><version&…...

【博客701】shell实现保留网络现场:ping失败时执行mtr

shell实现保留网络现场&#xff1a;ping失败时执行mtr 场景 当我们网络出现抖动&#xff0c;到某个目的地ping不通时&#xff0c;我们想知道路径上哪里出现问题时可以在那时候执行mtr并保留下现场以供排查 实现&#xff1a;ping_and_mtr.sh #!/bin/bash# 定义要ping的IP地址列…...

放弃手写代码吧!用低代码你能生成各种源码

很多同学不知道为什么要用Low-code做开发&#xff0c;传统IT开发不行么&#xff1f;当然可以。 传统IT自研软件开发&#xff0c;通过编程去写代码&#xff0c;还有数据库、API、第三方基础架构等。这个方式很好&#xff0c;但不可避免的会带来开发周期长、难度大&#xff0c;技…...

什么程度才算精通 Linux?

前言 Linux 的优秀之处自然不必多说。 如果将操作系统比作一辆汽车&#xff0c;那 Linux 就是一辆性能出色的多功能越野车&#xff0c;上山下海飞天无所不能。 如果你拥有了它&#xff0c;一定不会只满足于驾驶它上下班&#xff0c;不能只会挂挡、踩油门和控制方向之类的基本…...

jmeter中的__setProperty用法

__setProperty 是一个用于设置 JMeter 属性的函数&#xff0c;基本语法&#xff1a; __setProperty(property, value)** property : 是要设置的属性的名称 ** value : 是要设置的属性的值在 JMeter中&#xff0c;可以使用 __setProperty 函数的元素&#xff1a; BeanShell …...

vue基础知识六:v-show和v-if有什么区别?使用场景分别是什么?

一、v-show与v-if的共同点 我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含v-else)&#xff0c;都能控制元素在页面是否显示 在用法上也是相同的 <Model v-show"isShow" /> <Model v-if"isShow" />当表达式为true的时候&#…...

SpringBoot几个常用的注解

&#xff08;1&#xff09;RestController和Controller指定一个类&#xff0c;作为控制器的注解 &#xff08;2&#xff09;RequestMapping方法级别的映射注解&#xff0c;这一个用过Spring MVC的小伙伴相信都很熟悉 &#xff08;3&#xff09;EnableAutoConfiguration和Spri…...

腾讯JAVA后端秋招面试总结

腾讯秋招的面经,岗位是 java 后端开发。 说一下BIO、NIO和AIO 答: BIO是阻塞IO。在上一个线程的任务执行完之前,该线程必须阻塞等待上一个线程执行完毕。 NIO是非阻塞IO。一旦是响应事件发生了,该线程就会将对应的响应事件交给对应的事件处理器进行处理。 AIO是异步IO。主…...

随着iPhone 15降临,是时候扔掉所有的Lightning充电器了

自从苹果推出Lightning端口&#xff08;一直追溯到iPhone 5&#xff09;十多年后&#xff0c;你可能已经积累了相当多的Lightning电缆和配件。好吧&#xff0c;在下周的苹果活动之前&#xff0c;所有关于iPhone 15的传言都表明你不再需要它们了。 与最好的iPad和最好的MacBook…...

huggingface 使用入门笔记

概念 Hugging Face Hub​​和 Github 类似&#xff0c;都是Hub(社区)。Hugging Face可以说的上是机器学习界的Github。Hugging Face为用户提供了以下主要功能&#xff1a; ​模型仓库&#xff08;Model Repository&#xff09;​​&#xff1a;Git仓库可以让你管理代码版本、…...

ASP.NET Core 中的 Razor Pages

Razor Pages Razor Pages 是基于页面的 ASP.NET Core Web App 架构。 相比 MVC 模式&#xff0c;Razor Pages的生产效率更快。 Razer Pages 需要两个中间件&#xff1a; builder…Services.AddRazorPages 添加 Razor Pages servicesapp.MapRazorPages 添加 Razor Pages endpo…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...