2011-03-26 15 views
31

Acabo de actualizar de python 3.1 a python 3.2 (HD formateado) y uno de mis scripts dejó de funcionar. Me da el error en el título.TypeError: los datos POST deben ser bytes o un iterable de bytes. No puede ser str

Lo arreglaría yo mismo, pero ni siquiera sé lo que es un iterable de bytes lol. Intenté encasillar bytes (datos) pero tampoco funcionó. TypeError: argumento de cadena sin una codificación

url = "http://example.com/index.php?app=core&module=global&section=login&do=process" 
values = {"username" : USERNAME, 
      "password" : PASSWORD} 
data = urllib.parse.urlencode(values) 
req = urllib.request.Request(url, data) 
urllib.request.urlopen(req) 

Se bloquea en la última línea.

Obras en 3.1, pero no 3.2

Respuesta

43

Hiciste básicamente correcto al tratar de convertir la cadena en bytes, pero lo hizo de manera incorrecta. Python no tiene encasillamiento (así que lo que hiciste no fue encasillar).

La manera de hacerlo es para codificar los datos de texto en datos de bytes, lo que usted hace con la función de codificación:

binary_data = data.encode('encoding') 

Lo 'codificación' debe ser depende. Probablemente deberías usar 'ascii' aquí. Si tiene caracteres que no son ASCII, entonces necesita usar otra codificación, típicamente 'utf8', pero luego también debe decirle al servidor web receptor que es UTF-8. Es posible que tampoco quiera UTF8, pero debe preguntarlo, y se está complicando. :-)

+14

Esta es una buena respuesta, pero creo que podría mejorarse, incluyendo el corregida código. No está exactamente claro de dónde provienen los datos y dónde suministrar los datos binarios. –

+1

@rodarmor: 'data' es la variable' data' en el ejemplo anterior. 'binary_data' se proporciona donde necesita los datos convertidos. –

+1

Agregué la línea que haría que el ejemplo de OP funcionara, ¿puede verificarlo para asegurarse de que lo hice bien? –

7

@Enders, sé que esta es una vieja pregunta, pero me gustaría explicar algunas cosas más para alguien que está luchando con este problema.

Es específicamente con esta línea de código aquí:

data = urllib.parse.urlencode(values) 

que usted está teniendo problemas, ya que usted está tratando de codificar los datos: los valores (urlencode).

Si se refiere a la documentación de desplazamiento urllib.parse a la parte inferior para encontrar lo que hace urlencode: https://docs.python.org/3/library/urllib.parse.html < ~ verá que usted está tratando de codificar el usuario/contraseña en una cadena de datos:

Convert a mapping object or a sequence of two-element tuples, which may contain str or bytes objects, to a percent-encoded ASCII text string. If the resultant string is to be used as a data for POST operation with the urlopen() function, then it should be encoded to bytes, otherwise it would result in a TypeError.

Quizás lo que estás tratando de hacer aquí es hacer algún tipo de encriptación de tu usuario/contraseña, pero realmente no creo que este sea el camino correcto. Si es así, entonces probablemente deba asegurarse de que el extremo receptor (el destino de su url) sepa que está codificando su usuario/pase con esto.

Un enfoque más actualizado es utilizar la potente biblioteca de solicitudes. Ellos tienen compatibilidad con los protocolos de autenticación muy comunes: http://docs.python-requests.org/en/master/user/authentication/

En este caso, me gustaría hacer algo como esto:

requests.get(url, auth=('user', 'pass')) 
Cuestiones relacionadas