阿里云 SLS 数据加工中使用 Python 数据编码

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 数据编码在大数据处理的基础操作,本文讨论了 Python3 中的数据编码方案,以及在 SLS 数据加工中内置的数据编解码函数使用。

引文

数据编码是互联网上计算机之间交流的语言基础,如果计算机之间甲流使用的是哪种编码方式没有达成共识,就会出现“锟斤拷���”这样的魔幻字符。
在大数据系统中,这样的场景非常常见,主要原因在于数据的数据的生产与处理是隔离的,比如不同的业务系统各自独立运行,其产生的数据都汇集到大数据系统进行统一处理。
以下是一个数据样例,直观看上去这个数据非常复杂,看不出其中的具体内容。这里我们将讨论Python的数据编码方式(Python3),以及在阿里云 SLS 数据加工中如何应用Python的编码方案快速的实现数据编码处理。

{\x22time\x22:1644460630577,\x22type\x22:\x22track\x22,\x22distinct_id\x22:\x221111111\x22,\x22login_id\x22:\x221111111\x22,\x22anonymous_id\x22:\x22b13f22aca3faa599\x22,\x22lib\x22:{\x22$lib_method\x22:\x22autoTrack\x22,\x22$lib\x22:\x22Android\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$app_version\x22:\x221.1.23\x22,\x22$lib_detail\x22:\x22com.zeekrlife.second_hand.view.TestActivity######\x22},\x22event\x22:\x22$AppViewScreen\x22,\x22properties\x22:{\x22$os_version\x22:\x222.0.0\x22,\x22$model\x22:\x22XXX\x22,\x22$os\x22:\x22iOS\x22,\x22$screen_width\x22:1133,\x22$brand\x22:\x22TEST\x22,\x22$screen_height\x22:2453,\x22$app_version\x22:\x221.1.23\x22,\x22$lib\x22:\x22Android\x22,\x22$device_id\x22:\x22b13f22aca3faa599\x22,\x22$app_name\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$timezone_offset\x22:-480,\x22$app_id\x22:\x22com.zeekrlife.mobile\x22,\x22$manufacturer\x22:\x22TEST\x22,\x22platform_type\x22:\x22Android\x22,\x22$referrer_title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$wifi\x22:true,\x22$network_type\x22:\x22WIFI\x22,\x22$referrer\x22:\x22com.zeekrlife.main.MainActivity\x22,\x22$url\x22:\x22com.zeekrlife.second_hand.view.TestActivity\x22,\x22$screen_name\x22:\x22com.zeekrlife.second_hand.view.TestActivity\x22,\x22$title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_method\x22:\x22autoTrack\x22,\x22$is_first_day\x22:false,\x22$ip\x22:\x2210.200.88.32\x22,\x22$is_login_id\x22:false,\x22$city\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$province\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$country\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22},\x22_flush_time\x22:1644460631538,\x22map_id\x22:\x221111111\x22,\x22user_id\x22:1234567890,\x22recv_time\x22:1644460631756,\x22project\x22:\x22haha\x22}\xC2\xA0

Python 数据编码

字符编码基础

首先我们来看几个基础编码概念。

  1. ASCII 编码定义了最初计算机可识别的127个字符,包括英文大小写字母、数字、~!@等特殊符号,也就是常见的键盘按键所代表的字符。比如英文字母A的编号为65(16进制位0x41),* 的编号为42。
  2. Unicode编码 。随着互联网发展,127个字符是远远不够的,因为各种语言文字都需要在互联网传播,新的符号也不断的被创造出来,Unicode 字符集就是为此而设计的。其目标是将我们使用到的所有字符都列举出来,并将其编号。比如英文字母A的编号为U+0041,中文字“我”的编号为U+6211,Emoji表情符号👍 的编号为U+1F44D。
  3. UTF-8 编码。Unicode编码带来2个问题:一是字符非常多,如果所有字符都是用相同的二进制位存储,对与存储空间有很大的浪费;另一个是字符不断的扩展,无法定义出使用多少二进制位可以完全表达。考虑到这些问题,UTF-8编码方式设计为一种变长编码,也就是不同的字符,其二进制表达位数不一样,编号越大的字符其编码长度也就越长,其使用频率相对较低,所以加大成都的节省存储空间。比如,英文字母A的编码十六进制串位0x41(长度位1个字节,与其ASCII码一致),中文字“我”的编码为0xe68891(长度为3个字节),Emoji表情符号👍 的编码为0xf09f918d(长度为4个字节)。GBK、Latin-1等编码方式设计都与UTF-8类似。

Python 字符编码

我们先来总结下 Python 的字符串编码的基础。Python 2 由于官方已不再支持,所以本文的讨论只针对Python 3。
加入我在 Python 代码中定义一个变量 x="hello 地球",那么这里面其实有两个内在的编码设计点:

  1. 字符串类型其实是程序代码中的概念,用于代码的编写。以上x 这个Python变脸存储的是Unicode字符串。
  2. 这段代码本身使用的是 UFT-8 编码存储的,数据落盘存储时需要转为特定的编码方式

Python 对与数据编码的转换会涉及到两个方向:

  1. Unicode ==> UTF-8/GBK,从字符串类型转为二进制编码类型,可以使用 "string".encode() 方法。
  2. UTF-8/GBK ==> Unicode,从二进制编码类型转为字符串类型,可以使用 b"bytes".decode() 方法.

如果数据编码要做转换 UTF-8 ==> GBK,则需要做两次转换:UTF-8 ==> Unicode ==> GBK。

另外一个Python字符串处理中常见的概念时 raw string。转义字符设计初衷是将特殊字符(无法直接表示)通过普通字符组合的方式表达出来,这样就可以在程序代码中直接使用,比如代码中使用\n来表示换行,这里反斜杠就是转义字符。当我们需要确切的表示\+n这两个字符连接的字符串时,就需要在转义一次,表示为x="\\n"。如果代码中出现多个连续反斜杠时,可读性就变得极差,因为看到的反斜杠数目与真实逻辑所表达数目是不一致的。Python 中考虑到了这个问题,直接使用 r(raw的缩写)作为字符串定义的前缀,比如x=r"\n"就可以表示\+n这两个字符连接的字符串。

SLS 数据加工应用

SLS 数据加工中通过内置函数来实现编码的转换:str_encode/str_decode,其使用方式与Python中的 str.encode()/bytes.decode() 完全一致,以上中提到的复杂数据为例。
原始数据如下:

content: {\x22time\x22:1644460630577,\x22type\x22:\x22track\x22,\x22distinct_id\x22:\x221111111\x22,\x22login_id\x22:\x221111111\x22,\x22anonymous_id\x22:\x22b13f22aca3faa599\x22,\x22lib\x22:{\x22$lib_method\x22:\x22autoTrack\x22,\x22$lib\x22:\x22Android\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$app_version\x22:\x221.1.23\x22,\x22$lib_detail\x22:\x22com.haha.second_hand.view.TestActivity######\x22},\x22event\x22:\x22$AppViewScreen\x22,\x22properties\x22:{\x22$os_version\x22:\x222.0.0\x22,\x22$model\x22:\x22XXX\x22,\x22$os\x22:\x22iOS\x22,\x22$screen_width\x22:1133,\x22$brand\x22:\x22TEST\x22,\x22$screen_height\x22:2453,\x22$app_version\x22:\x221.1.23\x22,\x22$lib\x22:\x22Android\x22,\x22$device_id\x22:\x22b13f22aca3faa599\x22,\x22$app_name\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$timezone_offset\x22:-480,\x22$app_id\x22:\x22com.haha.mobile\x22,\x22$manufacturer\x22:\x22TEST\x22,\x22platform_type\x22:\x22Android\x22,\x22$referrer_title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$wifi\x22:true,\x22$network_type\x22:\x22WIFI\x22,\x22$referrer\x22:\x22com.haha.main.MainActivity\x22,\x22$url\x22:\x22com.haha.second_hand.view.TestActivity\x22,\x22$screen_name\x22:\x22com.haha.second_hand.view.TestActivity\x22,\x22$title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_method\x22:\x22autoTrack\x22,\x22$is_first_day\x22:false,\x22$ip\x22:\x2210.200.88.32\x22,\x22$is_login_id\x22:false,\x22$city\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$province\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$country\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22},\x22_flush_time\x22:1644460631538,\x22map_id\x22:\x221111111\x22,\x22user_id\x22:1234567890,\x22recv_time\x22:1644460631756,\x22project\x22:\x22haha\x22}\xC2\xA0

加工脚本:

e_set(
    "content",
    str_decode(
        str_encode(
            str_decode(str_encode(v("content"), "latin1"), "unicode_escape"), "latin1",
        ),
        "utf8",
    ),
)

结果如下,是一个JSON对象:

content: {"time":1644460630577,"type":"track","distinct_id":"1111111","login_id":"1111111","anonymous_id":"b13f22aca3faa599","lib":{"$lib_method":"autoTrack","$lib":"Android","$lib_version":"5.2.6","$app_version":"1.1.23","$lib_detail":"com.haha.second_hand.view.TestActivity######"},"event":"$AppViewScreen","properties":{"$os_version":"2.0.0","$model":"XXX","$os":"iOS","$screen_width":1133,"$brand":"TEST","$screen_height":2453,"$app_version":"1.1.23","$lib":"Android","$device_id":"b13f22aca3faa599","$app_name":"我是谁","$lib_version":"5.2.6","$timezone_offset":-480,"$app_id":"com.haha.mobile","$manufacturer":"TEST","platform_type":"Android","$referrer_title":"我是谁","$wifi":true,"$network_type":"WIFI","$referrer":"com.haha.main.MainActivity","$url":"com.haha.second_hand.view.TestActivity","$screen_name":"com.haha.second_hand.view.TestActivity","$title":"我是谁","$lib_method":"autoTrack","$is_first_day":false,"$ip":"10.200.88.32","$is_login_id":false,"$city":"保留IP","$province":"保留IP","$country":"保留IP"},"_flush_time":1644460631538,"map_id":"1111111","user_id":1234567890,"recv_time":1644460631756,"project":"haha"}  

编解码函数通过 errors 参数来处理编码错误,其可选值:

  1. ignore:忽略
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="ignore"))

结果为:
xxx: "test "

  1. strict:直接报错,丢弃此条数据
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="ignore"))

执行时直接报错。

  1. replace:使用?替换
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="replace"))

结果为:

xxx: "test ????"
  1. xmlcharrefreplace:使用 XML 字符引用替换
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="xmlcharrefreplace"))

结果为:

xxx: "test 测试数据"

总结

数据编码在大数据处理的基础操作,本文讨论了 Python3 中的数据编码方案,以及在 SLS 数据加工中内置的数据编解码函数使用。
参考资料:

  1. 《Python and Unicode》PPT
  2. Python 文档 Unicode HOWTO

下图是 SLS 团队的技术博客,我们会不定期推出技术文章分享和产品更新介绍,欢迎大家订阅,有任何问题也欢迎与我们反馈。
SLS QR.png

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
存储 监控 安全
网络安全视角:从地域到账号的阿里云日志审计实践
日志审计的必要性在于其能够帮助企业和组织落实法律要求,打破信息孤岛和应对安全威胁。选择 SLS 下日志审计应用,一方面是选择国家网络安全专用认证的日志分析产品,另一方面可以快速帮助大型公司统一管理多组地域、多个账号的日志数据。除了在日志服务中存储、查看和分析日志外,还可通过报表分析和告警配置,主动发现潜在的安全威胁,增强云上资产安全。
140 11
|
5天前
|
数据采集 数据安全/隐私保护 Python
从零开始:用Python爬取网站的汽车品牌和价格数据
在现代化办公室中,工程师小李和产品经理小张讨论如何获取懂车帝网站的汽车品牌和价格数据。小李提出使用Python编写爬虫,并通过亿牛云爬虫代理避免被封禁。代码实现包括设置代理、请求头、解析网页内容、多线程爬取等步骤,确保高效且稳定地抓取数据。小张表示理解并准备按照指导操作。
从零开始:用Python爬取网站的汽车品牌和价格数据
|
1月前
|
数据采集 Web App开发 数据可视化
Python用代理IP获取抖音电商达人主播数据
在当今数字化时代,电商直播成为重要的销售模式,抖音电商汇聚了众多达人主播。了解这些主播的数据对于品牌和商家至关重要。然而,直接从平台获取数据并非易事。本文介绍如何使用Python和代理IP高效抓取抖音电商达人主播的关键数据,包括主播昵称、ID、直播间链接、观看人数、点赞数和商品列表等。通过环境准备、代码实战及数据处理与可视化,最终实现定时任务自动化抓取,为企业决策提供有力支持。
|
2月前
|
存储 监控 安全
网络安全视角:从地域到账号的阿里云日志审计实践
日志审计的必要性在于其能够帮助企业和组织落实法律要求,打破信息孤岛和应对安全威胁。选择 SLS 下日志审计应用,一方面是选择国家网络安全专用认证的日志分析产品,另一方面可以快速帮助大型公司统一管理多组地域、多个账号的日志数据。除了在日志服务中存储、查看和分析日志外,还可通过报表分析和告警配置,主动发现潜在的安全威胁,增强云上资产安全。
|
2月前
|
数据采集 Web App开发 监控
Python爬虫:爱奇艺榜单数据的实时监控
Python爬虫:爱奇艺榜单数据的实时监控
|
2月前
|
数据采集 存储 XML
python实战——使用代理IP批量获取手机类电商数据
本文介绍了如何使用代理IP批量获取华为荣耀Magic7 Pro手机在电商网站的商品数据,包括名称、价格、销量和用户评价等。通过Python实现自动化采集,并存储到本地文件中。使用青果网络的代理IP服务,可以提高数据采集的安全性和效率,确保数据的多样性和准确性。文中详细描述了准备工作、API鉴权、代理授权及获取接口的过程,并提供了代码示例,帮助读者快速上手。手机数据来源为京东(item.jd.com),代理IP资源来自青果网络(qg.net)。
日志服务数据加工最佳实践: 多子键为数组的复杂JSON加工
程序构建的日志经常会以一种统计性质的JSON格式写入, 通常其包含一个基础信息, 以及多个子健为数组的形式. 本篇如何使用日志服务数据加工处理多子键为数组的复杂JSON.
1110 0
|
3月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
937 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
2月前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
10天前
|
存储 SQL 关系型数据库
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log、原理、写入过程;binlog与redolog区别、update语句的执行流程、两阶段提交、主从复制、三种日志的使用场景;查询日志、慢查询日志、错误日志等其他几类日志
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log