2010-06-27 44 views
21

Tôi đang thực sự mệt mỏi vì cố gắng tìm ra lý do tại sao mã này hoạt động trong Python 2 và không bằng Python 3. Tôi chỉ cố gắng lấy một trang json và sau đó phân tích cú pháp nó. Dưới đây là mã trong Python 2:Python 2 so với Python 3 - định dạng urllib

import urllib, json 
response = urllib.urlopen("http://reddit.com/.json") 
content = response.read() 
data = json.loads(content) 

tôi nghĩ mã tương đương bằng Python 3 sẽ là:

import urllib.request, json 
response = urllib.request.urlopen("http://reddit.com/.json") 
content = response.read() 
data = json.loads(content) 

Nhưng nó thổi lên trên khuôn mặt của tôi, bởi vì các dữ liệu trả về bởi đọc () là loại "byte". Tuy nhiên, tôi không thể cho cuộc sống của tôi có được nó để chuyển đổi sang một cái gì đó mà json sẽ có thể phân tích cú pháp. Tôi biết từ các tiêu đề mà reddit đang cố gắng gửi utf-8 lại cho tôi, nhưng tôi dường như không thể có được các byte để giải mã thành utf-8:

import urllib.request, json 
response = urllib.request.urlopen("http://reddit.com/.json") 
content = response.read() 
data = json.loads(content.decode("utf8")) 

Tôi đang làm gì sai?

Chỉnh sửa: vấn đề là tôi không thể đưa dữ liệu vào trạng thái có thể sử dụng được; mặc dù json tải dữ liệu, một phần của nó là không thể phát, và tôi muốn có thể in dữ liệu vào màn hình.

Chỉnh sửa lần hai: Vấn đề có liên quan nhiều đến việc in hơn phân tích cú pháp, có vẻ như vậy. Câu trả lời của Alex cung cấp một cách để kịch bản hoạt động trong Python 3, bằng cách thiết lập IO thành utf8. Nhưng vẫn còn một câu hỏi: tại sao mã đó hoạt động trong Python 2, nhưng không phải Python 3?

Trả lời

15

Mã bạn đăng có lẽ là do các thao tác cắt và dán sai vì rõ ràng là sai trong cả hai phiên bản (f.read() không thành công do không có tên mã vạch được xác định là f).

Trong Py3, ur = response.decode('utf8') hoạt động hoàn toàn tốt cho tôi, cũng như sau json.loads(ur). Có thể các bản sao và bản dán sai ảnh hưởng đến các nỗ lực chuyển đổi từ 2 đến 3 của bạn.

+0

Rất tiếc, tôi sẽ sửa các lỗi mã ... Tôi đã thử định dạng lại hiển thị nhưng đã sửa tất cả trong quá trình. : P Bất kể, tôi không thể xem dữ liệu sau khi phân tích cú pháp (bằng cách sử dụng "in (dữ liệu)" đơn giản) vì nó cho tôi lỗi charmap. –

+0

@Daniel, các vấn đề _after_ bạn đã nhận được dữ liệu dường như là một câu hỏi riêng biệt từ câu hỏi này về việc nhận dữ liệu (mà câu trả lời của tôi xuất hiện, phản hồi - mặc dù dường như bạn không đồng ý, vì bạn đã không làm như vậy t thậm chí upvote nó!). Nếu bởi 'dữ liệu' bạn có nghĩa là' json.loads (response) ', tôi có thể' in' nó mà không có bất kỳ vấn đề gì (trên Mac Terminal.app của tôi, hỗ trợ UTF-8). Sys.stdout.encoding của bạn là gì? Bạn đã đặt đúng biến môi trường 'PYTHONIOENCODING: Encoding [: errors] được sử dụng cho stdin/stdout/stderr' trước khi bắt đầu Python 3 chưa? Vv, vv - các vấn đề hoàn toàn khác nhau, xem. –

+0

Xin lỗi nếu tôi không rõ ràng lúc đầu. Vấn đề cốt lõi là tôi không thể sử dụng * dữ liệu sau khi phân tích cú pháp, vì lý do gì đó (bản in chỉ là khởi đầu của nó; nếu tôi không thể in nó, thì ở đâu đó xuống dòng tôi sẽ gặp rắc rối đọc dữ liệu). Tôi sẽ kiểm tra mã hóa, đủ để nói rằng nó không hoạt động trên máy W7 của tôi. –

0

Vui lòng xem câu hỏi that trong câu hỏi liên quan đến Unicode khác.

Bây giờ: Python 3 str (là loại Python 2 unicode) là một đối tượng lý tưởng, theo nghĩa là nó đề cập đến “ký tự” chứ không phải “byte”. Các ký tự này, để được sử dụng cho/từ dữ liệu ổ đĩa/mạng, cần phải được mã hóa thành/giải mã từ các byte bằng một "bảng chuyển đổi", a.k.a mã hóa a.k.a mã hóa. Do sự đa dạng của hệ điều hành, Python lịch sử tránh đoán xem mã hóa đó nên là gì; điều này đã thay đổi qua nhiều năm, nhưng vẫn là nguyên tắc “Đối mặt với sự mơ hồ, từ chối sự cám dỗ để đoán”.

Rất may, máy chủ web giúp công việc của bạn dễ dàng hơn. response của bạn trên nên cung cấp cho bạn tất cả các thông tin cần thêm:

>>> response.headers['content-type'] 
'application/json; charset=UTF-8' 

Vì vậy, mỗi khi bạn đưa ra một yêu cầu đến một máy chủ web, kiểm tra header Content-Type cho một giá trị charset, và giải mã dữ liệu của người yêu cầu thành Unicode (Python 3: bytes.decode(charset)str) bằng cách sử dụng bộ ký tự đó.

6

Phụ thuộc phiên bản python của bạn, bạn phải chọn đúng thư viện.

cho python 3,5

import urllib.request 
data = urllib.request.urlopen(url).read().decode('utf8') 

cho python 2.7

import urllib 
url = serviceurl + urllib.urlencode({'sensor':'false', 'address': address}) 
uh = urllib.urlopen(url) 
+0

Bạn có thể muốn cung cấp giải thích để làm rõ mã của bạn. – GabrielOshiro

Các vấn đề liên quan