Python Requests and Unicode
Question:
I am using the requests library to query the Diffbot API to get contents of an article from a web page url. When I visit a request URL that I create in my browser, it returns a JSON object with the text in Unicode (right?) for example (I shortended the text somewhat):
{“icon”:”http://mexico.cnn.com/images/ico_mobile.jpg”,”text”:”CIUDAD
DE MÉXICO (CNNMéxico) u2014 Kassandra Guazo Cano tiene 32 años, pero
este domingo participó por primera vez en una elección.n”No había
sacado mi (credencial del) IFE (Instituto Federal Electoral) porque al
hacer el trámite hay mucha mofa cuando ven que tu nombre no coincide
con tu y otros documentos de acuerdo con su nueva identidad.nSánchez
dice que los solicitantes no son discriminados, pero la experiencia de
Kassanda es diferente: “hay que pagar un licenciado, dos peritos
(entre ellos un endocrinólogo). Además, el juez dicta sentencia para
el cambio de nombre y si no es favorable tienes que esperar otros
cuatro años para volver a demandar al registro civil”.nAnte esta
situación, el Consejo para Prevenir y Eliminar la sculina, los
transgénero votan – México: Voto 2012 –
Nacional”,”url”:”http://mexico.cnn.com/nacional/2012/07/02/con-apariencia-de-mujer-e-identidad-masculina-los-transexuales-votan”,”xpath”:”/HTML[1]/BODY[1]/SECTION[5]/DIV[1]/ARTICLE[1]/DIV[1]/DIV[6]”}
When I use the python request library as follows:
def get_article(self, params={}):
api_endpoint = 'http://www.diffbot.com/api/article'
params.update({
'token': self.dev_token,
'format': self.output_format,
})
req = requests.get(api_endpoint, params=params)
return json.loads(req.content)
It returns this (again note that I shortened the text somewhat):
{u’url’:
u’http://mexico.cnn.com/nacional/2012/07/02/con-apariencia-de-mujer-e-identidad-masculina-los-transexuales-votan’,
u’text’: u’CIUDAD DE Mxc9XICO (CNNMxe9xico) u2014 Kassandra Guazo
Cano tiene 32 axf1os, pero este domingo participxf3 por primera vez
en una eleccixf3n.n”No habxeda sacado mi (credencial del) IFE
(Instituto Federal Electoral) porque al hacOyuky Martxednez Colxedn,
tambixe9n transgxe9nero, y que estaba acompaxf1ada de sus dos hijos
y su mamxe1.nAmbas trabajan como activistas en el Centro de Apoyo a
las Identidades Trans, A.C., donde participan en una campaxf1a de
prevencixf3n de enfermedades sexuales.n”Quisixe9ramos que no solo
nos vean como trabajadoras sexuales o estilistas, sino que luchamos
por nuestros derechos”, dice Kassandra mientras sonrxede, sostiene su
credencial de elector y levanta su pulgar entintado.’, u’title’: u’Con
apariencia de mujer e identidad masculina, los transgxe9nero votan –
Mxe9xico: Voto 2012 – Nacional’, u’xpath’:
u’/HTML[1]/BODY[1]/SECTION[5]/DIV[1]/ARTICLE[1]/DIV[1]/DIV[6]’,
u’icon’: u’http://mexico.cnn.com/images/ico_mobile.jpg’}
I don’t quite understand Unicode. How to make sure that what I get with requests is still Unicode?
Answers:
Concerning the “I don’t quite understand unicode”, there’s an entertaining primer on Unicode by Joel Spolsky and the official Python Unicode HowTo which is a 10 minute read and covers everything Python specific.
The requests docs say that request will always return unicode, and the example content you posted is in fact unicode (notice the u''
string syntax? That’s Python’s syntax for unicode strings.), so there’s no problem. Note that if you view the JSON response in a web browser, the u''
will not be there because it’s a property of how Python stores a string.
If unicode is important to your application, please don’t try to cope without really knowing about unicode. You’re in for a world of pain, character set issues are extremely frustrating to debug if you don’t know what you’re doing. Reading both articles mentioned above maybe takes half an hour.
You can use req.text
instead of req.content
to ensure that you get Unicode. This is described in:
https://requests.readthedocs.io/en/latest/api/#requests.Response.text
Try response.content.decode('utf-8')
if response.text
doesn’t work.
According to the documentation, the main problem is that the encoding guessed by requests
is determined based solely on the HTTP headers. If you can take advantage of non-HTTP knowledge to make a better guess at the encoding, you can set response.encoding
before accessing response.text
.
Credit goes to Jay Taylor for commenting on TTT’s answer – I almost missed the comment and thought it deserved its own answer.
I am using the requests library to query the Diffbot API to get contents of an article from a web page url. When I visit a request URL that I create in my browser, it returns a JSON object with the text in Unicode (right?) for example (I shortended the text somewhat):
{“icon”:”http://mexico.cnn.com/images/ico_mobile.jpg”,”text”:”CIUDAD
DE MÉXICO (CNNMéxico) u2014 Kassandra Guazo Cano tiene 32 años, pero
este domingo participó por primera vez en una elección.n”No había
sacado mi (credencial del) IFE (Instituto Federal Electoral) porque al
hacer el trámite hay mucha mofa cuando ven que tu nombre no coincide
con tu y otros documentos de acuerdo con su nueva identidad.nSánchez
dice que los solicitantes no son discriminados, pero la experiencia de
Kassanda es diferente: “hay que pagar un licenciado, dos peritos
(entre ellos un endocrinólogo). Además, el juez dicta sentencia para
el cambio de nombre y si no es favorable tienes que esperar otros
cuatro años para volver a demandar al registro civil”.nAnte esta
situación, el Consejo para Prevenir y Eliminar la sculina, los
transgénero votan – México: Voto 2012 –
Nacional”,”url”:”http://mexico.cnn.com/nacional/2012/07/02/con-apariencia-de-mujer-e-identidad-masculina-los-transexuales-votan”,”xpath”:”/HTML[1]/BODY[1]/SECTION[5]/DIV[1]/ARTICLE[1]/DIV[1]/DIV[6]”}
When I use the python request library as follows:
def get_article(self, params={}):
api_endpoint = 'http://www.diffbot.com/api/article'
params.update({
'token': self.dev_token,
'format': self.output_format,
})
req = requests.get(api_endpoint, params=params)
return json.loads(req.content)
It returns this (again note that I shortened the text somewhat):
{u’url’:
u’http://mexico.cnn.com/nacional/2012/07/02/con-apariencia-de-mujer-e-identidad-masculina-los-transexuales-votan’,
u’text’: u’CIUDAD DE Mxc9XICO (CNNMxe9xico) u2014 Kassandra Guazo
Cano tiene 32 axf1os, pero este domingo participxf3 por primera vez
en una eleccixf3n.n”No habxeda sacado mi (credencial del) IFE
(Instituto Federal Electoral) porque al hacOyuky Martxednez Colxedn,
tambixe9n transgxe9nero, y que estaba acompaxf1ada de sus dos hijos
y su mamxe1.nAmbas trabajan como activistas en el Centro de Apoyo a
las Identidades Trans, A.C., donde participan en una campaxf1a de
prevencixf3n de enfermedades sexuales.n”Quisixe9ramos que no solo
nos vean como trabajadoras sexuales o estilistas, sino que luchamos
por nuestros derechos”, dice Kassandra mientras sonrxede, sostiene su
credencial de elector y levanta su pulgar entintado.’, u’title’: u’Con
apariencia de mujer e identidad masculina, los transgxe9nero votan –
Mxe9xico: Voto 2012 – Nacional’, u’xpath’:
u’/HTML[1]/BODY[1]/SECTION[5]/DIV[1]/ARTICLE[1]/DIV[1]/DIV[6]’,
u’icon’: u’http://mexico.cnn.com/images/ico_mobile.jpg’}
I don’t quite understand Unicode. How to make sure that what I get with requests is still Unicode?
Concerning the “I don’t quite understand unicode”, there’s an entertaining primer on Unicode by Joel Spolsky and the official Python Unicode HowTo which is a 10 minute read and covers everything Python specific.
The requests docs say that request will always return unicode, and the example content you posted is in fact unicode (notice the u''
string syntax? That’s Python’s syntax for unicode strings.), so there’s no problem. Note that if you view the JSON response in a web browser, the u''
will not be there because it’s a property of how Python stores a string.
If unicode is important to your application, please don’t try to cope without really knowing about unicode. You’re in for a world of pain, character set issues are extremely frustrating to debug if you don’t know what you’re doing. Reading both articles mentioned above maybe takes half an hour.
You can use req.text
instead of req.content
to ensure that you get Unicode. This is described in:
https://requests.readthedocs.io/en/latest/api/#requests.Response.text
Try response.content.decode('utf-8')
if response.text
doesn’t work.
According to the documentation, the main problem is that the encoding guessed by requests
is determined based solely on the HTTP headers. If you can take advantage of non-HTTP knowledge to make a better guess at the encoding, you can set response.encoding
before accessing response.text
.
Credit goes to Jay Taylor for commenting on TTT’s answer – I almost missed the comment and thought it deserved its own answer.