UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' - -when using urlib.request python3
Asked Answered
M

2

5

I'm writing a script that goes to a list of links and parses the information.

It works for most sites but It's choking on some with "UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 13: ordinal not in range(128)"

It stops on client.py which is part of urlib on python3

the exact link is: http://finance.yahoo.com/news/cafés-growing-faster-than-fast-food-peers-144512056.html

There are quite a few similar postings here but none of the answers seems to work for me.

my code is:

from urllib import request

def __request(link,debug=0):      

try:
    html = request.urlopen(link, timeout=35).read() #made this long as I was getting lots of timeouts
    unicode_html = html.decode('utf-8','ignore')

# NOTE the except HTTPError must come first, otherwise except URLError will also catch an HTTPError.
except HTTPError as e:
    if debug:
        print('The server couldn\'t fulfill the request for ' + link)
        print('Error code: ', e.code)
    return ''
except URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('timeout')
        return ''    
else:
    return unicode_html

this calls the request function

link = 'http://finance.yahoo.com/news/cafés-growing-faster-than-fast-food-peers-144512056.html' page = __request(link)

And the traceback is:

Traceback (most recent call last):
  File "<string>", line 250, in run_nodebug
  File "C:\reader\get_news.py", line 276, in <module>
    main()
  File "C:\reader\get_news.py", line 255, in main
    body = get_article_body(item['link'],debug=0)
  File "C:\reader\get_news.py", line 155, in get_article_body
    page = __request('na',url)
  File "C:\reader\get_news.py", line 50, in __request
    html = request.urlopen(link, timeout=35).read()
  File "C:\Python33\Lib\urllib\request.py", line 156, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Python33\Lib\urllib\request.py", line 469, in open
    response = self._open(req, data)
  File "C:\Python33\Lib\urllib\request.py", line 487, in _open
    '_open', req)
  File "C:\Python33\Lib\urllib\request.py", line 447, in _call_chain
    result = func(*args)
  File "C:\Python33\Lib\urllib\request.py", line 1268, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "C:\Python33\Lib\urllib\request.py", line 1248, in do_open
    h.request(req.get_method(), req.selector, req.data, headers)
  File "C:\Python33\Lib\http\client.py", line 1061, in request
    self._send_request(method, url, body, headers)
  File "C:\Python33\Lib\http\client.py", line 1089, in _send_request
    self.putrequest(method, url, **skips)
  File "C:\Python33\Lib\http\client.py", line 953, in putrequest
    self._output(request.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 13: ordinal not in range(128)

Any help appreciated It's driving me crazy , I think I've tried all combinations of x.decode and similar

(I could ignore the offending characters if that is possible.)

Maintop answered 29/3, 2014 at 17:38 Comment(3)
User Kenneth Reitz's requests library. I cannot recommend it highly enough. It will make all this code much simpler and will almost certainly take care of this issue.Upholster
@JackGibbs: requests indeed would handle URLs with non-ASCII characters in them by re-quoting the URL explicitly.Gautier
@JackGibbs: valid urls have characters that are subset of ascii.Shaneka
A
5

Use a percent-encoded URL:

link = 'http://finance.yahoo.com/news/caf%C3%A9s-growing-faster-than-fast-food-peers-144512056.html'

I found the above percent-encoded URL by pointing the browser at

http://finance.yahoo.com/news/cafés-growing-faster-than-fast-food-peers-144512056.html

going to the page, then copying-and-pasting the encoded url supplied by the browser back into the text editor. However, you can generate a percent-encoded URL programmatically using:

from urllib import parse

link = 'http://finance.yahoo.com/news/cafés-growing-faster-than-fast-food-peers-144512056.html'

scheme, netloc, path, query, fragment = parse.urlsplit(link)
path = parse.quote(path)
link = parse.urlunsplit((scheme, netloc, path, query, fragment))

which yields

http://finance.yahoo.com/news/caf%C3%A9s-growing-faster-than-fast-food-peers-144512056.html
Adamina answered 29/3, 2014 at 17:54 Comment(3)
If it is a part of an url then parse.quote() could be used instead of parse.quote_plus() (used for x-www-form-urlencoded)Shaneka
Thanks that worked I wasn't sure if that could be a problem in other parts of the URL so I split it and then rebuilt it url_tuple =parse.urlsplit(link) parse.quote_plus(url_tuple[2]) + url_tuple[3] + parse.quote_plus(url_tuple[4])) encoded_link ="%s://%s%s?%s%s"%(url_tuple[0] , url_tuple[1] , parse.quote(url_tuple[2]) , url_tuple[3] , parse.quote(url_tuple[4]))Maintop
I'm glad you got your solution to work. But use parse.urlunsplit to build the url. That's what it's for.Adamina
G
3

Your URL contains characters that cannot be represented as ASCII characters.

You'll have to ensure that all characters have been properly URL encoded; use urllib.parse.quote_plus for example; it'll use UTF-8 URL-encoded escaping to represent any non-ASCII characters.

Gautier answered 29/3, 2014 at 17:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.