在信息时代黎明之初,ASCII编码作为最早的标准字符集 ,仅包含128个字符,足以覆盖英文和其他西欧语言。然而,随着互联网的全球化发展,单一的ASCII编码已无法满足多元文化的交流需求。于是,Unicode字符集应运而生 ,它囊括了世界上几乎所有的书写系统,将全球的语言文字统一在一个巨大的编码空间内。Unicode不仅包含ASCII字符 ,还包括拉丁字母变体、东亚汉字、中东阿拉伯文等多种字符,为实现跨文化的信息传递奠定了坚实的基础。
# 示例代码:ASCII与Unicode的对比
ascii_str='Hello, World!'
unicode_str='你好 ,世界!'
print(len(ascii_str.encode('ascii'))) # 输出13,ASCII编码每个字符占一个字节
print(len(unicode_str.encode('utf-8'))) # 输出13,UTF-8编码下英文字符占一个字节 ,中文字符占三个字节
在全球互联的今天,无论是网页浏览、电子邮件收发,还是数据库存储、文件传输,都需要依赖统一的字符编码来确保信息的准确无误。特别是在软件开发领域,为了实现跨平台、跨地区的无缝协作,程序员必须精通字符串编码的相关知识,确保程序能够正确处理各种语言环境下的文本数据。
在Python 2中,默认字符串类型既可以是ASCII编码的 ,也可以是Unicode编码的,这取决于字符串前是否带有u前缀。而Python 3则更为简化和严谨 ,所有文本字符串均为Unicode编码,以str类型表示,而原始的二进制数据则由新的bytes类型表示。
# Python 2示例
py2_ascii_str='Hello'
py2_unicode_str=u'你好'
# Python 3示例
py3_str='你好' # 默认为Unicode字符串
py3_bytes=b'Hello' # 二进制数据,需通过encode()转化为bytes
Python以其对Unicode的出色支持而著称,内建的字符串方法如encode()和decode()使得在Unicode与指定编码间转换变得简单易行。同时,Python还提供了诸如unicodedata模块,可以查询特定Unicode字符的详细属性,以及处理如规范化、排序等更复杂的问题。
通过深入理解Python对字符串编码的支持,开发者能够在面对多语言环境时游刃有余 ,从而编写出更加健壮、兼容性强的应用程序。接下来的文章将进一步探讨计算机科学基础、编码原理及Python中实际的编码操作。
计算机内部采用二进制形式存储和处理信息。数字、字符等数据在计算机中均被转化为一串二进制数。例如,十进制数13转换为二进制为1101 ,字符A在ASCII编码中对应的二进制值为01000001。这种数字化的过程确保了计算机能够高效、准确地处理各类数据。
# 示例代码:数字与字符的二进制表示
import binascii
decimal_number=13
binary_number=bin(decimal_number)[2:] # 二进制表示 ,去掉前缀'0b'
print(binary_number) # 输出:1101
char='A'
ascii_value=ord(char)
binary_char=binascii.hexlify(char.encode('ascii')).decode() # 将ASCII编码的字节转换为十六进制字符串
print(binary_char) # 输出:41(十六进制表示,对应二进制01000001)
在计算机中,基本的数据存储单元是字节(byte) ,通常包含8位二进制数。对于单字节编码如ASCII,一个字节足以表示一个字符。然而,对于包含大量字符的编码如Unicode ,一个字符可能需要多个字节来存储。此外,字节序(endianness)决定了多字节数据在内存中的排列顺序 ,分为大端序(高位字节在前)和小端序(低位字节在前)。
# 示例代码:多字节字符编码与字节序
unicode_char='汉'
utf8_encoded=unicode_char.encode('utf-8') # UTF-8编码下,'汉'占用三个字节
print(utf8_encoded) # 输出:b'\xe6\xb1\x89'
# 字节序演示(此处以大端序为例)
multi_byte_number=0x12345678 # 假设这是一个多字节整数
big_endian_bytes=multi_byte_number.to_bytes(4, byteorder='big')
print(big_endian_bytes) # 输出:b'\x12\x34\x56\x78'
ASCII编码是最基础的字符编码标准,包含128个字符 ,包括英文字母、数字、标点符号等 ,每个字符用一个字节表示。由于其简洁性和广泛接受度,ASCII编码至今仍被许多系统和协议作为基础字符集。
# 示例代码:ASCII编码示例
ascii_text='Hello, World!'
ascii_encoded=ascii_text.encode('ascii')
print(ascii_encoded) # 输出:b'Hello, World!'
ISO-8859系列编码是对ASCII的扩展,旨在支持更多欧洲语言字符。每个ISO-8859编码(如ISO-8859-1、ISO-8859-2等)覆盖特定区域的语言 ,但总字符数量仍限制在256个以内,每个字符仍占用一个字节。
# 示例代码:ISO-8859-1编码示例
latin1_text='?Hola, mundo!'
latin1_encoded=latin1_text.encode('iso-8859-1')
print(latin1_encoded) # 输出:b'\xa1Hola, mundo!'
Unicode编码是一个庞大的字符集,包含了世界上几乎所有已知的书写系统。Unicode定义了统一码点(Unicode code point) ,每个码点对应一个字符。常见的Unicode编码方式包括UTF-8、UTF-16和UTF-32,它们以不同的字节数量和方式存储同一Unicode码点。
UTF-8是最常用的Unicode编码方式,其特点在于可变长编码 ,英文字符占用一个字节,其他字符根据需要使用1到4个字节。UTF-16和UTF-32则分别使用固定长度的2字节和4字节表示Unicode码点。这些UTF变体的选择主要取决于应用场景和性能需求。
# 示例代码:UTF-8编码示例
utf8_text='你好 ,世界!'
utf8_encoded=utf8_text.encode('utf-8')
print(utf8_encoded) # 输出:b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe4\xb8\x96\xe7\x95\x8c!\n'
通过深入理解计算机存储原理、字符编码标准及其相互关系,开发者能够更好地应对各种字符编码问题 ,为后续章节中Python中的字符串编码操作奠定坚实基础。
在Python中,str类型用于表示文本字符串,自Python 3起 ,str类型默认采用Unicode编码,这意味着它可以容纳全世界范围内的字符。每个Unicode字符都有一个唯一的码点(code point),可以通过\u或\U前缀在字符串中直接引用:
# 示例代码:Unicode码点表示
unicode_char='\u4f60\u597d' # 这两个Unicode码点代表“你好”
print(unicode_char) # 输出:“你好”
long_unicode_char='\U0001F600' # 这个Unicode码点代表笑脸表情
print(long_unicode_char) # 输出:
与str类型相对的是bytes类型,它表示的是不可变的字节序列 ,主要用于存储原始的二进制数据或经过编码后的文本数据。在处理文件读写、网络通信等场景时尤为关键:
# 示例代码:创建并操作bytes对象
binary_data=b'Hello, World!' # 创建一个bytes对象
print(binary_data) # 输出:b'Hello, World!'
encoded_text='你好,世界!'.encode('utf-8') # 将Unicode字符串编码为bytes
print(encoded_text) # 输出:b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe4\xb8\x96\xe7\x95\x8c!'
Python源代码文件开头通常有一行特殊的注释来声明文件的编码,例如# -*- coding: utf-8 -*-。这有助于解释器正确解析含有非ASCII字符的源代码:
# encoding=utf-8
message="你好,世界!"
print(message)
对于Python脚本处理的外部文件,也需要明确其编码格式,可通过open()函数的encoding参数指定:
with open('example.txt', 'r', encoding='utf-8') as file:
content=file.read()
print(content)
Python运行环境的默认编码可通过sys.getdefaultencoding()获取,但它并不直接影响str类型的字符串,而是影响如何将字符串转换为bytes类型。另外,操作系统环境变量如PYTHONIOENCODING可以在一定程度上影响Python处理I/O时的编码行为。
通过深入了解Python字符串类型与编码感知机制,我们可以更好地掌握字符串在内存中的表示方式 ,并在实际应用中灵活处理各种编码问题 ,为进一步探讨Python字符串的编码操作打下基础。
Python的str对象提供了encode()方法,用于将Unicode字符串转换为指定编码的bytes对象。基本语法如下:
encoded_bytes=unicode_string.encode(encoding, errors='...')
其中,encoding参数指定目标编码方式(如utf-8、gbk等),errors参数可选,用于指定遇到无法编码的字符时的处理策略,如strict(抛出异常)、ignore(忽略该字符)、replace(用特殊字符替换)等。
不同的编码方式决定了Unicode字符如何映射到字节序列。例如,UTF-8是一种变长编码,英文字符占用一个字节,其他字符可能占用多个字节。错误处理策略的选择会影响遇到非法字符或无法编码的字符时程序的行为。
# 示例代码:不同编码方式与错误处理策略的对比
unicode_str='你好 ,世界!'
# 使用UTF-8编码 ,错误处理策略为"strict"
utf8_strict=unicode_str.encode('utf-8', errors='strict')
print(utf8_strict)
# 使用GBK编码,错误处理策略为"ignore"
gbk_ignore=unicode_str.encode('gbk', errors='ignore')
print(gbk_ignore)
# 使用Latin-1编码 ,错误处理策略为"replace"
latin1_replace=unicode_str.encode('latin-1', errors='replace')
print(latin1_replace)
以下代码展示了同一Unicode字符串使用不同编码方式(UTF-8、GBK、Latin-1)进行编码后的结果差异:
# 示例代码:不同编码方式下的字符串转换
unicode_str='你好,世界!'
utf8_encoded=unicode_str.encode('utf-8')
gbk_encoded=unicode_str.encode('gbk')
latin1_encoded=unicode_str.encode('latin-1')
print('UTF-8编码:', utf8_encoded)
print('GBK编码:', gbk_encoded)
print('Latin-1编码:', latin1_encoded)
与encode()方法相对应 ,bytes对象提供了decode()方法,用于将字节序列还原为Unicode字符串。基本语法如下:
decoded_unicode=bytes_sequence.decode(encoding, errors='...')
其中 ,encoding参数指定字节序列的原始编码方式,errors参数同上,用于指定遇到无法解码的字节序列时的处理策略。
解码时,准确识别字节序列的原始编码至关重要。若编码方式不明,可以尝试使用编码检测工具(如chardet库)。错误处理策略的选择同样影响程序在遇到解码错误时的行为。
# 示例代码:不同编码方式的字节序列解码
utf8_bytes=b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe4\xb8\x96\xe7\x95\x8c!'
gbk_bytes=b'\xc4\xe3\xba\xc3,\xb5\xc4\xcb\xf3!'
utf8_decoded=utf8_bytes.decode('utf-8')
gbk_decoded=gbk_bytes.decode('gbk')
print('UTF-8字节序列解码:', utf8_decoded)
print('GBK字节序列解码:', gbk_decoded)
在实际应用中,我们可能会遇到未知编码的文本数据。这时,可以利用编码检测库(如chardet)辅助确定编码,然后使用正确的编码方式进行解码:
import chardet
# 假设这是未知编码的字节数据
unknown_bytes=b'\xc4\xe3\xba\xc3,\xb5\xc4\xcb\xf3!'
# 使用chardet检测编码
detected_encoding=chardet.detect(unknown_bytes)['encoding']
# 根据检测结果解码
decoded_text=unknown_bytes.decode(detected_encoding)
print('修复后的文本:', decoded_text)
熟练掌握Python字符串的编码与解码操作,不仅能帮助我们解决日常编程中的字符编码问题,还能为处理多语言数据、处理遗留数据、以及与其他系统交互提供有力支持。后续章节将进一步探讨编码相关的Python库与工具 ,以及在实际项目开发中的编码最佳实践。
chardet是一个强大的字符编码检测库,通过统计分析和概率模型识别文本的编码方式。在处理来源不明的文件或网络数据时,这个库能够快速准确地推测出文本的编码类型。
import chardet
# 示例代码:检测未知编码的文本数据
unknown_encoded_text=b'\xef\xbb\xbfHello, \xe4\xb8\x96\xe7\x95\x8c!'
encoding_detected=chardet.detect(unknown_encoded_text)['encoding']
decoded_text=unknown_encoded_text.decode(encoding_detected)
print(decoded_text) # 输出:'Hello, 世界!'
在实际开发中 ,我们经常会遇到需要处理多种编码格式的文本数据。例如,从Web抓取的数据、用户上传的文件或旧系统迁移过来的数据。此时 ,chardet可以帮助我们自动识别文本编码,避免因编码不匹配导致的乱码或错误。
Python的codecs模块提供了丰富的编码/解码函数和类,可以进行更为精细和低级别的字符编码控制。例如,codecs.open()可用于打开和读写指定编码的文件;IncrementalDecoder和IncrementalEncoder类允许逐块处理编码和解码,适合大数据流的实时处理。
import codecs
# 示例代码:使用codecs模块读取和写入UTF-8编码的文件
with codecs.open('example.txt', 'r', encoding='utf-8') as f:
content=f.read()
with codecs.open('output.txt', 'w', encoding='utf-8') as f:
f.write(content)
对于一些特殊的编码需求,比如读取带BOM的UTF-8文件或者处理编码边界条件等,codecs模块也能提供有效解决方案。例如,使用StreamReader和StreamWriter可以透明地处理BOM和编码转换。
除了Python内置的codecs模块,还有如iconv这样的命令行工具以及cchardet这样的C语言实现的高性能编码检测库,它们在处理大规模数据或追求极致性能时有着独特的价值。
# cchardet示例(假设已经安装)
import cchardet
# 同样检测未知编码的文本数据
result=cchardet.detect(unknown_encoded_text)
print(result['encoding']) # 输出:'utf-8-sig'
Python内置的textwrap模块常用于文本排版 ,虽然并非专门处理编码,但在显示多语言文本时十分有用。而unicodedata模块提供了访问Unicode字符数据库的功能 ,可用于获取字符的各种属性和分类,有助于处理编码相关的复杂问题。
通过掌握这些Python库与工具 ,开发者可以更高效地处理编码相关任务,提升软件的健壮性和兼容性,在面对编码问题时具备更强的解决能力。在接下来的章节中,我们将通过具体实践案例介绍如何运用这些知识解决实际编码问题。
当尝试解码字节序列时,如果提供的编码与实际编码不符,Python会抛出UnicodeDecodeError。例如,以下代码试图以ASCII编码解码包含中文的UTF-8字节序列:
incorrectly_encoded_bytes=b'\xe4\xbd\xa0\xe5\xa5\xbd'
try:
decoded_text=incorrectly_encoded_bytes.decode('ascii')
except UnicodeDecodeError as e:
print(f"解码失败:{e}")
输出:
解码失败:'utf-8' codec can't decode byte 0xe4 in position 0: invalid continuation byte
解决此类问题的关键是确定正确的编码方式,可以借助chardet等工具检测字节序列的编码,或根据数据来源和上下文信息推断。
Mojibake(文字化け)是指由于编码转换错误导致的字符显示异常。例如,将UTF-8编码的文本以GBK解码后,原本的中文字符会变成乱码。要修复Mojibake,首先需要识别出导致乱码的原始编码和错误解码方式,然后重新以正确的方式解码:
mojibaked_bytes=b'\xd6\xd0\xce\xc4\xb5\xc4\xcb\xf3!'
correct_encoding='utf-8' # 假设已确定原始编码为UTF-8
fixed_text=mojibaked_bytes.decode(correct_encoding)
print(fixed_text) # 输出:你好,世界!
UTF-8编码的文件可能包含BOM(Byte Order Mark),它是字节序标记,用于指示UTF-8编码。在处理这类文件时,需要考虑是否保留或去除BOM。无BOM的UTF-8文件在解码时无需特别处理,但有BOM的文件如果不正确处理,可能导致首字符显示异常。codecs模块的open()函数提供了'utf-8-sig'模式 ,可自动识别并去除BOM:
with codecs.open('file_with_bom.txt', 'r', encoding='utf-8-sig') as f:
content=f.read()
在项目开始阶段,应明确规定编码规范,如统一使用UTF-8编码,并在代码、配置文件、数据库连接等处明确声明编码。这有助于避免编码问题在整个项目中蔓延。
# 在Python源代码文件顶部声明编码
# -*- coding: utf-8 -*-
# 在数据库连接字符串中指定编码
db_connection='postgresql://user:password@localhost/dbname?charset=utf8'
# 在HTML文档中指定字符集
<meta charset="UTF-8">
确保数据库连接的字符集与应用程序一致 ,避免数据存储和检索时的编码问题。在创建表时指定字符集,并在连接字符串中指定客户端字符集:
CREATE TABLE my_table (
column1 VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci,
...
);
# Python SQLAlchemy示例
from sqlalchemy import create_engine
engine=create_engine('mysql+pymysql://user:password@localhost/dbname?charset=utf8')
在Web开发中 ,通过HTTP头部Content-Type字段的charset参数告知浏览器响应内容的编码。同时 ,处理POST请求时,检查Content-Type以确保正确解码请求数据:
# Flask示例
from flask import Flask, request, make_response
app=Flask(__name__)
@app.route('/api', methods=['POST'])
def handle_post():
if request.content_type=='application/json; charset=utf-8':
data=request.json
else:
data=request.form
response=make_response(json.dumps(result))
response.headers['Content-Type']='application/json; charset=utf-8'
return response
通过遵循编码最佳实践,开发者可以有效地预防和解决编码问题,确保项目在多语言环境中稳定、顺畅地运行。随着编码标准的演进和新挑战的出现,持续学习与适应将是每个技术工作者的必修课。
编码是信息技术的核心要素之一,贯穿于信息的存储、传输与展示全过程。本文从字符编码的历史沿革至现代Unicode体系的广泛应用,剖析了Python在字符串处理上的独特角色与内建支持。通过深入探讨计算机存储原理与编码标准 ,我们揭示了Python中字符串类型str与bytes的本质区别以及如何通过encode()与decode()方法进行相互转换。面对编码难题,介绍了诸如chardet、codecs等实用工具,以及在项目实践中处理编码不匹配、Mojibake乱码等问题的最佳策略。
编码问题的妥善解决关乎项目的稳定性和国际化水平 ,强调了明确编码规范、统一编码声明,以及在数据库连接、Web开发等环节注重字符集协商与配置的重要性。面对新兴编码标准与不断扩大的字符集多样性,与时俱进的学习态度和实战经验积累显得尤为重要。最后 ,我们推荐了一系列官方文档、社区资源以及专业教材,鼓励读者持续探索编码世界的深度与广度 ,以适应未来编码领域的挑战与变革。
天某同事问到如何把Excel单元格中的数字乱码恢复成正常显示?刚开始我还以为是不能恢复的,后来求助万能的度娘后终于帮她解决问题了,所以今天就跟大家分享几种将这个Excel数字太长乱码直接转文本格式恢复的方法。
首先普及一下什么是Excel数字太长乱码现象?熟悉Excel的用户可能都知道,在Excel单元格一般显示数字最长的长度是11位,超过11位以后就会变成科学计数法显示,很多人称它为乱码。
第一种情况:尚未输入长数字前(也就是未乱码前)
这种情况比较好解决,大体有两种比较简单的方法:
1、只需要我们在输入长数字前把该单元格或该列单元格都设置为文本格式,然后再输入长数字即可正常显示。
2、在输入长数字前先输入英文状态下的单引号,如’12345678910121212,这样也能够正常显示长数字。
第二种情况:长数字已经变成乱码
这种情况有点小复杂,也就是说我们拿到的excel表格时,里面的长数字已经变成了乱码,这个时候如果不懂方法的话,还是挺难折腾的。其实,这种情况也有三种方法轻松解决,具体如下:
1、直接设置该单元格格式为文本格式。重点来了,选择文本格式确定修改后它不会直接变成文本型,还需要再双击一下该单元格,看到这个单元格左上角出现一个绿色小三角的时候,说明已经改为文本型,此时数字就能够完全显示出来了。
2、通过分列功能批量修改为文本格式。直接选中所有需要修改的数据(如选中A1到A7),接着点Excel导航菜单中的【数据】 > 分列,连续点击两次“下一步”(直接默认即可),然后在列数据格式中选择“文本(T)”,点击【完成】即可把这些乱码数据全部显示出来。
3、通过TEXT函数将数值转换为文本格式。TEXT函数可以将数值强制转换为文本,并可使用户通过使用特殊格式字符串来指定显示格式。
该函数的语法为:TEXT(value,format_text)
其中value为需转换的数值,format_text为需转换的格式,如果format_text参数为0或#,则显示的格式不变。其他更多转换后的文本格式请参照Excel中帮助文件的介绍。
案例:本文中A1单元格实际的数字是120104090012(以显示为1.20104E+11),如转换后的文本数据也要求是120104090012,则公式为:=TEXT(A1,0)或=TEXT(A1,"#")。具体如下:
将通过公式转换得到的数据复制 > 选择性粘贴 > 选择“数值” > 确定后即可得到文本型数据,也就是说可以将乱码的长数字全部显示出来了。
小结
如果是第一种情况,建议先设置单元格为文本格式后再输入长数字会比较好。如果得到的Excel数据都是长数字乱码的,数据比较多的情况下,个人建议使用第三种方法。
原文地址:http://yigujin.wang/930.html
者 | 丁彦军
责编 | 仲培艺
近日,有位粉丝向我请教,在爬取某网站时,网页的源代码出现了中文乱码问题,本文就将与大家一起总结下关于网络爬虫的乱码处理。注意,这里不仅是中文乱码,还包括一些如日文、韩文 、俄文、藏文之类的乱码处理,因为他们的解决方式是一致的,故在此统一说明。
乱码问题的出现
就以爬取 51job 网站举例,讲讲为何会出现“乱码”问题,如何解决它以及其背后的机制。
代码示例:
import requests url="http://search.51job.com" res=requests.get(url) print(res.text)
显示结果:
打印 res.text 时,发现了什么?中文乱码!!!不过发现,网页的字符集类型采用的是 GBK 编码格式。
我们知道 Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当你访问 r.text 之时,Requests 会使用其推测的文本编码。你可以找出 Requests 使用了什么编码,并且能够使用 r.encoding 属性来改变它。
接下来,我们一起通过 Resquests 的一些用法,来看看 Requests 会基于 HTTP 头部对响应的编码方式。
print(res.encoding) #查看网页返回的字符集类型 print(res.apparent_encoding) #自动判断字符集类型
输出结果为:
可以发现 Requests 推测的文本编码(也就是网页返回即爬取下来后的编码转换)与源网页编码不一致,由此可知其正是导致乱码原因。
乱码背后的奥秘
当源网页编码和爬取下来后的编码转换不一致时,如源网页为 GBK 编码的字节流,而我们抓取下后程序直接使用 UTF-8 进行编码并输出到存储文件中,这必然会引起乱码,即当源网页编码和抓取下来后程序直接使用处理编码一致时,则不会出现乱码,此时再进行统一的字符编码也就不会出现乱码了。最终爬取的所有网页无论何种编码格式,都转化为 UTF-8 格式进行存储。
注意:区分源网编码 A-GBK、程序直接使用的编码 B-ISO-8859-1、统一转换字符的编码 C-UTF-8。
在此,我们拓展讲讲 Unicode、ISO-8859-1、GBK2312、GBK、UTF-8 等之间的区别联系,大概如下:
最早的编码是 ISO8859-1,和 ASCII 编码相似。但为了方便表示各种各样的语言,逐渐出现了很多标准编码。ISO8859-1 属于单字节编码,最多能表示的字符范围是 0-255,应用于英文系列。很明显,ISO8859-1 编码表示的字符范围很窄,无法表示中文字符。
1981 年中国人民通过对 ASCII 编码的中文扩充改造,产生了 GB2312 编码,可以表示 6000 多个常用汉字。但汉字实在是太多了,包括繁体和各种字符,于是产生了 GBK 编码,它包括了 GB2312 中的编码,同时扩充了很多。中国又是个多民族国家,各个民族几乎都有自己独立的语言系统,为了表示那些字符,继续把 GBK 编码扩充为 GB18030 编码。每个国家都像中国一样,把自己的语言编码,于是出现了各种各样的编码,如果你不安装相应的编码,就无法解释相应编码想表达的内容。终于,有个叫 ISO 的组织看不下去了。他们一起创造了一种编码 Unicode,这种编码非常大,大到可以容纳世界上任何一个文字和标志。所以只要电脑上有 Unicode 这种编码系统,无论是全球哪种文字,只需要保存文件的时候,保存成 Unicode 编码就可以被其他电脑正常解释。Unicode 在网络传输中,出现了两个标准 UTF-8 和 UTF-16,分别每次传输 8 个位和 16 个位。于是就会有人产生疑问,UTF-8 既然能保存那么多文字、符号,为什么国内还有这么多使用 GBK 等编码的人?因为 UTF-8 等编码体积比较大,占电脑空间比较多,如果面向的使用人群绝大部分都是中国人,用 GBK 等编码也可以。
也可以这样来理解:字符串是由字符构成,字符在计算机硬件中通过二进制形式存储,这种二进制形式就是编码。如果直接使用 “字符串??字符??二进制表示(编码)” ,会增加不同类型编码之间转换的复杂性。所以引入了一个抽象层,“字符串??字符??与存储无关的表示??二进制表示(编码)” ,这样,可以用一种与存储无关的形式表示字符,不同的编码之间转换时可以先转换到这个抽象层,然后再转换为其他编码形式。在这里,Unicode 就是 “与存储无关的表示”,UTF-8 就是 “二进制表示”。
乱码的解决方法
根据原因来找解决方法,就非常简单了。
方法一:直接指定 res.encoding
import requests url="http://search.51job.com" res=requests.get(url) res.encoding="gbk" html=res.text print(html)
方法二:通过 res.apparent_encoding 属性指定
import requests url="http://search.51job.com" res=requests.get(url) res.encoding=res.apparent_encoding html=res.text print(html)
方法三:通过编码、解码的方式
import requests url="http://search.51job.com" res=requests.get(url) html=res.text.encode('iso-8859-1').decode('gbk') print(html)
输出结果:
基本思路三步走:确定源网页的编码 A---GBK、程序通过编码 B---ISO-8859-1 对源网页数据还原、统一转换字符的编码 C-UTF-8。至于为啥出现统一转码这一步呢? 网络爬虫系统数据来源很多,不可能使用数据时,再转化为其原始的数据,这样做是很废事的。所以一般的爬虫系统都要对抓取下来的结果进行统一编码,从而在使用时做到一致对外,方便使用。
比如如果我们想讲网页数据保存下来,则会将起转为 UTF-8,代码如下:
with open("a.txt",'w',encoding='utf-8') as f: f.write(html)
总结
关于网络爬虫乱码问题,这里不仅给出了一个解决方案,还深入到其中的原理,由此问题引申出很多有意思的问题,如 UTF-8、GBK、GB2312 的编码方式怎样的?为什么这样转化就可以解决问题?
最后,多动脑,多思考,多总结,致每一位码农!
本文为作者投稿,版权归其所有。
*请认真填写需求信息,我们会在24小时内与您取得联系。