【已解决】BeautifulSoup已经获得了Unicode的Soup但是print出来却是乱码

【问题】

某人遇到的问题:

关于BeautifulSoup抓取表格及SAE数据库导入的问题(跪求大神帮忙)

简单说就是:

用如下代码:

?


1

2

3

4

5

6

7

import re,urllib2

from BeautifulSoup import BeautifulSoup

from urllib import urlopen

doc=urllib2.urlopen("http://www.w3school.com.cn/html/html_tables.asp")

soup = BeautifulSoup(doc,fromEncoding="GB2312")这里怎么改也没用

a=soup.findAll("td")

print a

但是得到的打印输出还是显示的是乱码:

【解决过程】

1. 此处专门通过实际测试,然后再去查证资料,最终,完整的代码和解释,如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

#!/usr/bin/python

# -*- coding: utf-8 -*-

"""

Function:

【已解决】BeautifulSoup已经获得了Unicode的Soup但是print出来却是乱码

http://www.crifan.com/beautifulsoup_already_got_unicode_soup_but_print_messy_code

Author:     Crifan Li

Version:    2013-05-30

Contact:    http://www.crifan.com/contact_me/

"""

     

import re,urllib2

from BeautifulSoup import BeautifulSoup

from urllib import urlopen

     

def scrapeW3school():

    html = urllib2.urlopen("http://www.w3school.com.cn/html/html_tables.asp");

    #soup = BeautifulSoup(html); #此句效果是一样的:

    #实测结果是:不加fromEncoding,也是可以自动正确(去判断原始的字符编码为GB2312,然后去)解析(出后来的Unicode的soup)的

    soup = BeautifulSoup(html, fromEncoding="GB2312");

    #print "soup=",soup;

    allTdSoup = soup.findAll("td");

    print "type(allTdSoup)=",type(allTdSoup); #type(allTdSoup)= <class ‘BeautifulSoup.ResultSet‘>,但是实际上算是个List

    print "len(allTdSoup)=",len(allTdSoup); #len(allTdSoup)= 32,此处List的长度是32

    print "allTdSoup=",allTdSoup;

    # allTdSoup= [<td>row 1, cell 1</td>, <td>row 1, cell 2</td>, <td>row 2, ......, <td><a href="/tags/tag_tfoot.asp">&lt;tfoot&gt;</a></td>

    # , <td>瀹氫箟琛ㄦ牸鐨勯〉鑴氥€?/td>, <td><a href="/tags/tag_col.asp">&lt;col&gt;</a></td>, <td>瀹氫箟鐢ㄤ簬琛ㄦ牸鍒楃殑灞

    # 炴€с€?/td>, <td><a href="/tags/tag_colgroup.asp">&lt;colgroup&gt;</a></td>, <td>瀹氫箟琛ㄦ牸鍒楃殑缁勩€?/td>]

 

    #此处,看起来是乱码,但是实际上,此处得到的allTdSoup是个列表,而其中的每个soup,虽然内部编码都是正常的unicode了

    #但还是会打印出来乱码,那是因为:

    #1.先看官网的解释:

    #http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html

    #"当你调用__str__,prettify或者renderContents时, 你可以指定输出的编码。默认的编码(str使用的)是UTF-8。"

    #所以:

    #此处,对于去打印allTdSoup,即去打印一个soup的List,所以,针对List中的每个soup(其本质是个对象),而将其输出为字符串的话,默认是调用其__str__属性

    #所以就相当于:

    #针对allTdSoup中的每个soup:

    #   调用该soup的__str__获得对应的字符串(表示的该soup的内容)

    #最终组合输出你所看到的["xxx", "xxx", ...]之类的结果,

    #其中,"xxx",就是对应的每个soup.__str__的结果

    #而此处的每个soup的__str__的值:

    #如官网所述,默认是UTF-8的编码

    #所以,此处获得的字符串是UTF-8编码的字符串,

    #所以print输出到此处cmd

    #而cmd是GBK编码

    #所以,将UTF-8编码的字符,在GBK的cmd中显示,就显示出乱码了

    #其中:

    #(1)如果对于cmd是GBK不了解,去看:

    #设置字符编码:简体中文GBK/英文

    #http://www.crifan.com/files/doc/docbook/soft_dev_basic/release/html/soft_dev_basic.html#cmd_encoding

    #(2)如果对于GBK,UTF-8本身不了解,去看:

    #字符编码详解

    #http://www.crifan.com/files/doc/docbook/char_encoding/release/html/char_encoding.html

    #(3)针对于soup本身,其实已经是Unicode编码,所以可以通过官网所说的,指定__str__输出时的编码为GBK,以使得此处正确显示非乱码的中文

    for eachTdSoup in allTdSoup:

        print "type(eachTdSoup)=",type(eachTdSoup); #type(eachTdSoup)= <type ‘instance‘>,说明类型是BeautifulSoup的实例instance

        print "eachTdSoup.string=",eachTdSoup.string; #输出soup的string属性,即该tag中的字符串内容部分,其本身已经是Unicode,所以可以正常输出非乱码的中文

        print "type(eachTdSoup.string)=",type(eachTdSoup.string); #但是要注意一下,此处不是Unicode类型,而是:type(eachTdSoup.string)= <class ‘BeautifulSoup.NavigableString‘>

        print "eachTdSoup=",eachTdSoup; #直接输出soup本身,所以相当于:eachTdSoup.__str__ == eachTdSoup.__str__("UTF-8"),所以遇到中文时是乱码

        print "eachTdSoup.renderContents()=",eachTdSoup.renderContents(); #直接输出内容本身,默认也是用的是UTF-8,所以遇到中文时也是乱码

        print "eachTdSoup.__str__(‘GBK‘)=",eachTdSoup.__str__(‘GBK‘);#专门指定了GBK编码,所以可以正常显示非乱码的中文

    #摘录其中部分输出:

    # type(eachTdSoup)= <type ‘instance‘>

    # eachTdSoup.string= row 1, cell 1

    # type(eachTdSoup.string)= <class ‘BeautifulSoup.NavigableString‘>

    # eachTdSoup= <td>row 1, cell 1</td>

    # eachTdSoup.renderContents()= row 1, cell 1

    # eachTdSoup.__str__(‘GBK‘)= <td>row 1, cell 1</td>

    # ......

    # type(eachTdSoup)= <type ‘instance‘>

    # eachTdSoup.string= 定义表格列的组。

    # type(eachTdSoup.string)= <class ‘BeautifulSoup.NavigableString‘>

    # eachTdSoup= <td>瀹氫箟琛ㄦ牸鍒楃殑缁勩€?/td>

    # eachTdSoup.renderContents()= 瀹氫箟琛ㄦ牸鍒楃殑缁勩€

    # eachTdSoup.__str__(‘GBK‘)= <td>定义表格列的组。</td>

    #

    #(4)另外,关于BeautifulSoup可以根据html中的charset猜测其编码的事情,不了解的去看:

    #【整理】关于HTML网页源码的字符编码(charset)格式(GB2312,GBK,UTF-8,ISO8859-1等)的解释

    #http://www.crifan.com/summary_explain_what_is_html_charset_and_common_value_of_gb2312_gbk_utf_8_iso8859_1

 

if __name__ == "__main__":

    scrapeW3school();

【总结】

所以说:

表面上看起来从BeautifulSoup解析后得到的soup,打印出来是乱码,但是实际上其本身已经是,正确的(从原始的GB2312编码)解析(为Unicode)后的了。

之所以乱码,那是因为,打印soup时,调用的是__str__,其默认是UTF-8,所以输出到GBK的cmd中,才显示是乱码。

总结下来就是:

非得搞懂了:

  • 各种编码本身的逻辑:啥是GBK,啥是UTF-8,啥是Unicode
  • BeautifulSoup的逻辑:可以通过fromEncoding去正确的解析html为Unicode编码的
  • print一个对象的逻辑:内部是调用对象的__str__得到对应的字符串的,此处对应的是soup的__str__
  • soup的__str__的逻辑:默认编码是UTF-8
  • cmd的逻辑:(中文的系统中)编码为GBK

然后才能明白此处的问题的根本的原因的。

【已解决】BeautifulSoup已经获得了Unicode的Soup但是print出来却是乱码,布布扣,bubuko.com

时间: 2024-10-11 03:29:30

【已解决】BeautifulSoup已经获得了Unicode的Soup但是print出来却是乱码的相关文章

【已解决】python中文字符乱码(GB2312,GBK,GB18030相关的问题)

http://againinput4.blog.163.com/blog/static/1727994912011111011432810/ [背景] 在玩wordpress的一个博客搬家工具BlogMover,其包含几个python脚本,其中有个是163博客搬家用的163-blog-mover.py,实现抓取网易博客的日志,然后导出xml. 但是其工具现在(2011-12-10)已经失效了.经过自己一点修改后,可以实现获得文章标题了. 用法还是原先的用法:  163-blog-mover.py

关于MySQL字符集问题【已解决】

关于MySQL字符集问题[已解决] 先来看看我的字符集设置 全都是utf8.这里没有什么问题 接下来我创建了一个数据表book.来看下我创建的表结构 当输入命令:mysql> insert into book(bookname,publisher,author,price,detail) values('PHP','电子工业出版社','武胜利','80.00','与PHP相关的图书');ERROR 1366 (HY000): Incorrect string value: '\xB5\xE7\x

可编辑ztree节点的增删改功能图标控制---已解决

<!DOCTYPE html> <HTML> <HEAD> <TITLE> ZTREE DEMO - beforeEditName / beforeRemove / onRemove / beforeRename / onRename</TITLE> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <l

服务器老是死机,重启后就可以了。。已解决

服务器没过多久又死机了,重启后又可以,开始以为是软件的问题,重装了干净的系统,结果没多久还是出现这个问题,在安装系统的时候非常缓慢,排除了软件问题,应该是硬件有问题了,内存.CPU经过替换法排查都没有问题,想到安装系统的时候非常缓慢,怀疑是硬盘有问题,下载了硬盘检测软件,结果一看,居然很多坏道,马上了一个新硬盘,后面再也没出现这种情况. 分析原因:硬盘有坏道,当系统读取到坏道的时候卡机或死机. 服务器老是死机,重启后就可以了..已解决,布布扣,bubuko.com

【已解决】Android微信开放平台,申请移动应用的 应用签名 如何获取

你看到的这个文章来自于http://www.cnblogs.com/ayanmw 在微信开放平台,申请移动应用的时候: https://open.weixin.qq.com/cgi-bin/appcreate?t=manage/createMobile&type=app&lang=zh_CN&token=60682ddfbd9106b1c4b1f9d70f56c98e5f728905 下一步后需要填写应用签名 这可难倒了我了..签名 keystore文件可没有这么简单. "

【已解决】java.lang.IllegalArgumentException: column &#39;_id&#39; does not exist

今天用到SimpleCursorAdapter来适配ListView的数据,依旧记得SimpleCursorAdapter必须匹配一个字段名为_id的主键列,一开始我用SQLiteDatabase的rawQuery方法拼sql查询,因为是用SELECT * FROM table_name,所以一切正常. 后来我用query方法就挂了,抛出了java.lang.IllegalArgumentException: column '_id' does not exist异常,然后我发现原来是参数col

启动httpd报错-已解决

[[email protected] ~]# service httpd startStarting httpd: (13)Permission denied: make_sock: could not bind to address 192.168.1.153:28080no listening sockets available, shutting downUnable to open logs [FAILED][[email protected] ~]# 临时办法: [[email pro

LigerUi-js中ajax前台调用后台Json格式转换!(已解决)

LigerUi-js中ajax前台调用后台Json格式转换!(已解决) success: function (data, status) { var aaa = JSON2.stringify(data); alert(aaa ); } LigerUi-js中ajax前台调用后台Json格式转换!(已解决),布布扣,bubuko.com

OpenCV 无法启动此程序,因为计算机中丢失opencv_core249.dll。请尝试重新安装改程序已解决此问题

换了64位的系统,配置好之后运行之前的程序,竟然给我抛出这个错误.应该是我的opencv没有安装对吧.系统报错 无法启动此程序,因为计算机中丢失opencv_core249.dll.请尝试重新安装改程序已解决此问题 那就是缺少opencv_core249.dll动态链接库了. [解决方法] 1 在安装目录下找到这个链接库 (但是不知道为什么我引用的库还是要x86下的才行,郁闷中) 2 复制到指定的目录下 64位系统 C:\Windows\SysWOW64 32位系统 C:\Windows\Sys