python - <class 'UnicodeDecodeError' > 仅出现在 Python 3 中,而不出现在 Python 2 中

标签 python python-3.x

我正在做一个项目,分析城市政策类(class)的推文。该脚本的目的是从同事下载的 JSON 文件中解析出某些信息。以下是我尝试解析的示例推文的链接:

https://www.dropbox.com/s/qf1e06601m2mrxr/5thWardChicago.0.json?dl=0

我让我的一个 friend 在某些版本的 Python 2 (Windows) 中测试了以下脚本,并且它有效。但是,我的机器(Windows 10)正在运行最新版本的 Python 3,但它对我不起作用。

import json
import collections
import sys, os
import glob
from datetime import datetime
import csv


def convert(input):
    if isinstance(input, dict):
        return {convert(key): convert(value) for key, value in input.iteritems()}
    elif isinstance(input, list):
        return [convert(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input

def to_ilan_csv(json_files):
    # write the column headers
    csv_writer = csv.writer(open("test.csv", "w"))
    headers = ["tweet_id", "handle", "username", "tweet_text", "has_image", "image_url", "created_at", "retweets", "hashtags", "mentions", "isRT", "isMT"]
    csv_writer.writerow(headers)

    # open the JSON files we stored and parse them into the CSV file we're working on
    try:
        #json_files = glob.glob(folder)
        print("Parsing %s files." % len(json_files))
        for file in json_files:
            f = open(file, 'r')
            if f != None:
                for line in f:
                    # hack to avoid the trailing \n at the end of the file - sitcking point LH 4/7/16
                    if len(line) > 3:
                        i = 0
                        tweets = convert(json.loads(line))
                        for tweet in tweets:
                            has_media = False
                            is_RT = False
                            is_MT = False
                            hashtags_list = []
                            mentions_list = []
                            media_list = []

                            entities = tweet["entities"]
                            # old tweets don't have key "media" so need a workaround
                            if entities.has_key("media"):
                                has_media = True
                                for item in entities["media"]:
                                    media_list.append(item["media_url"])

                            for hashtag in entities["hashtags"] :
                                hashtags_list.append(hashtag["text"])

                            for user in entities["user_mentions"]:
                                mentions_list.append(user["screen_name"])

                            if tweet["text"][:2] == "RT":
                                is_RT = True

                            if tweet["text"][:2] == "MT":
                                is_MT = True

                            values = [
                                tweet["id_str"],
                                tweet["user"]["id_str"],
                                tweet["user"]["screen_name"],
                                tweet["text"],
                                has_media,
                                ','.join(media_list) if len(media_list) > 0 else "",
                                datetime.strptime(tweet["created_at"], '%a %b %d %H:%M:%S +0000 %Y').strftime('%Y-%m-%d %H:%M:%S'),
                                tweet["retweet_count"],
                                ','.join(hashtags_list) if len(hashtags_list) > 0 else "",
                                ','.join(mentions_list) if len(mentions_list) > 0 else "",
                                is_RT,
                                is_MT
                            ]
                            csv_writer.writerow(values)
                    else:
                        continue
            f.close()

    except:
        print("Something went wrong. Quitting.")
        for i in sys.exc_info():
            print(i)

def parse_tweets():
    
    file_names = []
    file_names.append("C:\\Users\\Adam\\Downloads\\Test Code\\sample1.json")
    file_names.append("C:\\Users\\Adam\\Downloads\\Test Code\\sample2.json")
    to_ilan_csv(file_names)

然后我通过简单地执行来执行

parse_tweets()

但我收到以下错误:

Parsing 2 files.
Something went wrong. Quitting.
<class 'UnicodeDecodeError'>
'charmap' codec can't decode byte 0x9d in position 3338: character maps to <undefined>
<traceback object at 0x0000016CCFEE5648>

我向我的一位计算机科学 friend 寻求帮助,但他无法诊断问题。所以我就来这里了。

我的问题

这个错误是什么?为什么它只出现在 Python 3 而不是 Python 2 中?

对于那些想要尝试的人,所提供的代码应该能够使用 Jupyter 笔记本和我提供的投递箱链接中的文件副本运行。

最佳答案

Sooo,在聊天中进行了一些调试后,解决方案如下:

显然,OP 使用的文件未正确识别为 UTF-8,因此迭代该文件(使用 for line in f)导致了 UnicodeDecodeError cp1252 编码模块。我们通过明确将文件打开为 utf-8 来解决这个问题:

f = open(file, 'r', encoding='utf-8')

完成此操作后,文件可以正确打开,并且 OP 遇到了我们之前一直期待和看到的 Python 3 问题。出现了以下三个问题:

  1. “dict”对象没有属性“iteritems”

    dict.iteritems() 在 Python 3 中不再存在,因此我们在这里切换到 dict.items():

    return {convert(key): convert(value) for key, value in input.items()}
    
  2. 名称“unicode”未定义

    Unicode在Python 3中不再是一个单独的类型,普通的字符串类型已经能够支持unicode,所以我们只需删除这种情况:

    elif isinstance(input, unicode):
        return input.encode('utf-8')
    
  3. “dict”对象没有属性“has_key”

    要检查字典中是否存在某个键,我们使用 in 运算符,因此 if 检查如下:

    if "media" in entities:
    

之后,代码应该可以在 Python 3 上正常运行。

关于python - <class 'UnicodeDecodeError' > 仅出现在 Python 3 中,而不出现在 Python 2 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41824061/

相关文章:

python - 改变列表字典中的一个 python 列表会改变所有列表

python - 从另一个字典值分配字典值

python-3.x - 获取给定图像位置的 numpy 索引

python - 使用 like 和 python 和 mysql 连接器编写查询

python - 如何使用列表理解将二维列表中的值匹配到另一个二维列表?

python - 为什么 assertAlmostEqual(-inf,-inf) 会失败?

python - 使用 pandas 计算两个特定行之间的百分比变化

python - 职位描述句子的分类方法

python - 使用 conda (anaconda) 安装 geopandas 时出现问题

python - 哪种方法最适合在discord.py 中启动机器人?登录()和连接()与开始()与运行()