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

简介: 数据编码在大数据处理的基础操作,本文讨论了 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日志并进行多维度分析。
目录
相关文章
|
7天前
|
存储 JSON JavaScript
使用Python处理JSON格式数据
使用Python处理JSON格式数据
|
1天前
|
数据采集 Web App开发 数据处理
一步步教你用Python Selenium抓取动态网页任意行数据
使用Python Selenium爬取动态网页,结合代理IP提升抓取效率。安装Selenium,配置代理(如亿牛云),设置User-Agent和Cookies以模拟用户行为。示例代码展示如何使用XPath提取表格数据,处理异常,并通过隐式等待确保页面加载完成。代理、模拟浏览器行为和正确配置增强爬虫性能和成功率。
一步步教你用Python Selenium抓取动态网页任意行数据
|
1天前
|
存储 数据安全/隐私保护 计算机视觉
Python教程:一文了解从Bytes到Bits的数据转换
在Python编程中,处理数据时经常需要在字节(bytes)和位(bits)之间进行转换。这种转换在网络通信、数据加密、图像处理等领域尤为常见。本文将详细介绍如何在Python中进行字节与位之间的转换,并提供一个实用的功能:如何在指定的位位置替换位数据。
12 4
|
1天前
|
Python
Python+Jinja2实现接口数据批量生成工具
在做接口测试的时候,我们经常会遇到一种情况就是要对接口的参数进行各种可能的校验,手动修改很麻烦,尤其是那些接口参数有几十个甚至更多的,有没有一种方法可以批量的对指定参数做生成处理呢。
11 3
|
1天前
|
Python
Python列表推导式是一种简洁的创建新列表的方式,它允许你在一行代码中完成对数据的操作和转换
【6月更文挑战第19天】Python列表推导式是创建新列表的简洁语法,它在一行内处理数据。表达式如`[expr for item in iterable if cond]`,其中`expr`是对元素的操作,`item`来自`iterable`,`if cond`是可选过滤条件。例如,将数字列表平方:`[x**2 for x in numbers]`。嵌套列表推导处理复杂结构,如合并二维数组:`[[a+b for a,b in zip(row1, row2)] for row1, row2 in zip(matrix1, matrix2)]`。简洁但勿过度复杂化。
11 5
|
1天前
|
存储 JSON JavaScript
【chat-gpt问答记录】python将数据存为json格式和yaml格式
【chat-gpt问答记录】python将数据存为json格式和yaml格式
13 1
|
2天前
|
Python
【代码】Python实现Excel数据合并
【代码】Python实现Excel数据合并
7 0
|
2天前
|
存储 索引 Python
Python基础第五篇(Python数据容器)
Python基础第五篇(Python数据容器)
|
2天前
|
API Python
使用Python获取HTTP请求头数据
在Python Web开发中,`requests`库用于发送HTTP请求,请求头是关键元素,包含客户端信息和请求详情。要查看请求头,先创建`Request`对象,打印其`headers`属性,然后使用`get`等方法发送请求并获取响应头。别忘了处理不同HTTP方法、内容类型以及异常。使用`Session`管理会话状态,并考虑日志记录以调试。通过控制请求头,能有效与服务器通信。
17 0
|
3天前
|
XML 前端开发 数据挖掘
Web数据提取:Python中BeautifulSoup与htmltab的结合使用
Web数据提取:Python中BeautifulSoup与htmltab的结合使用

热门文章

最新文章