从网站读取数据并尝试获取重音字符

时间:2015-08-19 00:34:06

标签: python utf-8

所以我正在阅读一个网站的json,这是我输出的一部分

{"objects": [{"first_name": "Pascale", "last_name": "D\u00e9ry",...

在搜索中我看到\ u00e9是与é相对应的unicode字符。好吧,我明白了。然而,当试图解决它时,我认为我应该在从网站上读取数据时使用.encode(),如下所示:

import urllib

i=0
j=250

while i<2000:
    with urllib.request.urlopen(r"https://represent.opennorth.ca/candidates/house-of-commons/?limit=250&offset={}".format(i)) as url:
        with open(r"F:\electoral_map\candidates_python\candidates{0}_to_{1}.js".format(i,j), "wb+") as f:
            f.write(url.read().encode('utf-8'))
    i+=250
    j=i+250

print("all done")

然后我才得到错误

AttributeError: 'bytes' object has no attribute 'encode'

我向后退了吗?我也试过.decode('utf-8'),但这也行不通。 (获取TypeError:'str'不支持缓冲区接口)

我应该提到我使用的是Python 3。

2 个答案:

答案 0 :(得分:0)

如果您的真正目标是将数据存储在电子表格中,请尝试以下程序:

import requests
import csv
import json

base_url="https://represent.opennorth.ca/candidates/house-of-commons/?limit=250&offset={}"
#base_filename=r"F:\electoral_map\candidates_python\candidates{0}_to_{1}.csv"
base_filename=r"candidates{0}_to_{1}.csv"
keys = [
    'name',
    'first_name',
    'last_name',
    'election_name',
    'elected_office',
    'district_name',
    'email',
    'incumbent',
    'party_name',
    'personal_url',
    'photo_url',
    'source_url',
    'url',
]

for i in range(0, 2000, 250):
    url = base_url.format(i)
    filename=base_filename.format(i, i+250)
    data = requests.get(url)
    data = data.text
    data = json.loads(data)
    data = data['objects']

    with open(filename, 'wt', encoding='utf-8') as f:
        w = csv.DictWriter(f, keys, extrasaction='ignore')
        w.writeheader()
        w.writerows(data)

注意:此程序需要Python3。如果您使用的是Python2,请告诉我,我会尝试为您提供适用于该版本的版本。

答案 1 :(得分:0)

在这种情况下,decode()对下载的JSON字符串是适当的。

考虑这个简化的示例,它将通过在URL中指定limit=1&offset=0来下载单个候选人的JSON:

>>> from urllib.request import urlopen
>>> url = urlopen('https://represent.opennorth.ca/candidates/house-of-commons/?limit=1&offset=0')
>>> content = url.read()
>>> print(type(content))
<class 'bytes'>
>>> print(url.getheader('Content-Type'))
application/json; charset=utf-8
>>> content
b'{"objects": [{"first_name": "Pascale", "last_name": "D\\u00e9ry", "election_name": "House of Commons", "name": "Pascale D\\u00e9ry", "elected_office": "candidate", "url": "", "gender": "", "extra": {}, "related": {"boundary_url": "/boundaries/federal-electoral-districts-next-election/24025/", "election_url": "/elections/house-of-commons/"}, "source_url": "http://www.conservative.ca/?member=candidates", "offices": [], "party_name": "Conservative", "incumbent": null, "district_name": "Drummond", "email": "", "personal_url": "http://www.conservative.ca/team/member/?fname=Pascale&lname=D\\u00e9ry&type=candidates", "photo_url": "http://www.conservative.ca/media/team/Pascale-Dery.jpg"}], "meta": {"next": "/candidates/house-of-commons/?limit=1&offset=1", "total_count": 1129, "previous": null, "limit": 1, "offset": 0}}'

由此我们看到内容是字节类型,即字节字符串。字节字符串没有encode()方法;假定它们已经在某些编码中,并且只能使用正确的编码解码为unicode。在这种情况下,数据是UTF-8编码的JSON,如Content-Type标题所示。

你可以在这里做很多事情:

  • 以二进制模式打开输出文件,只需编写JSON字符串即可 就像文件一样。因为传入的数据是UTF-8编码的 将导致UTF-8编码的JSON文件,这可能是什么 CSV转换器期望:

    with open('output.json', 'wb') as f:
        f.write(content)
    
  • 使用支持的编码以文本模式打开输出文件 CSV转换器,将来自UTF-8的传入JSON字符串解码为文本 string(unicode),并将解码后的字符串写入文件:

    with open('output.json', 'w', encoding='iso-8859-1') as f:
        f.write(content.decode('utf-8'))
    

    这里我选择了iso-8859-1编码作为示例,您也可以选择ASCII。请注意,如果编码为UTF-8,则会对数据进行解码,然后将数据重新编码为UTF-8,因此您也可以按原样编写数据。

  • 另一个选项,也就是我推荐的选项,是使用JSON解码器解码传入的数据,然后使用您的首选编码将其写入文件。这样做的好处是可以确保传入的数据实际上是JSON,并允许您在切换到CSV转换器之前发现任何错误:

    import json
    with open('output.json', 'w') as f:
        data = json.loads(content.decode('utf8'))
        json.dump(data, f)
    

您实际上可能会发现使用requests模块更容易。它具有内置的JSON解析和字符解码:

>>> import requests
>>> r = requests.get('https://represent.opennorth.ca/candidates/house-of-commons/?limit=1&offset=0')
>>> type(r.text)
>>> type(r.content)
>>> data = r.json()
>>> data
{'objects': [{'first_name': 'Pascale', 'extra': {}, 'url': '', 'last_name': 'Déry', 'district_name': 'Drummond', 'incumbent': None, 'offices': [], 'gender': '', 'personal_url': 'http://www.conservative.ca/team/member/?fname=Pascale&lname=Déry&type=candidates', 'elected_office': 'candidate', 'party_name': 'Conservative', 'source_url': 'http://www.conservative.ca/?member=candidates', 'election_name': 'House of Commons', 'email': '', 'name': 'Pascale Déry', 'photo_url': 'http://www.conservative.ca/media/team/Pascale-Dery.jpg', 'related': {'boundary_url': '/boundaries/federal-electoral-districts-next-election/24025/', 'election_url': '/elections/house-of-commons/'}}], 'meta': {'total_count': 1129, 'limit': 1, 'next': '/candidates/house-of-commons/?limit=1&offset=1', 'previous': None, 'offset': 0}}

此处r.content是以服务器发送数据的任何编码下载的原始内容。 r.text是解码为unicode字符串的相同原始内容。 r.json()为您提供解析后的JSON数据作为字典。将其写入文件就像这样简单:

with open('output.json', 'w') as f:
    json.dump(r.json(), f)