web-dev-qa-db-fra.com

TypeError: impossible d'utiliser un motif de chaîne sur un objet de type octet dans re.findall ()

J'essaie d'apprendre comment récupérer automatiquement les URL d'une page. Dans le code suivant, j'essaie d'obtenir le titre de la page Web:

import urllib.request
import re

url = "http://www.google.com"
regex = r'<title>(,+?)</title>'
pattern  = re.compile(regex)

with urllib.request.urlopen(url) as response:
   html = response.read()

title = re.findall(pattern, html)
print(title)

Et je reçois cette erreur inattendue:

Traceback (most recent call last):
  File "path\to\file\Crawler.py", line 11, in <module>
    title = re.findall(pattern, html)
  File "C:\Python33\lib\re.py", line 201, in findall
    return _compile(pattern, flags).findall(string)
TypeError: can't use a string pattern on a bytes-like object

Qu'est-ce que je fais mal?

82
Inspired_Blue

Vous voulez convertir le code HTML (un objet de type octet) en chaîne à l'aide de .decode, par exemple. html = response.read().decode('utf-8').

Voir Convertir des octets en chaîne Python String

130
rocky

Le problème est que votre expression rationnelle est une chaîne, mais html est octets :

>>> type(html)
<class 'bytes'>

Comme python ne sait pas comment ces octets sont codés, une exception est générée lorsque vous essayez d'utiliser une expression rationnelle sous forme de chaîne.

Vous pouvez soit decode les octets en chaîne:

html = html.decode('ISO-8859-1')  # encoding may vary!
title = re.findall(pattern, html)  # no more error

Ou utilisez une expression rationnelle d'octets:

regex = rb'<title>(,+?)</title>'
#        ^

Dans ce contexte particulier, vous pouvez obtenir le codage à partir des en-têtes de réponse:

with urllib.request.urlopen(url) as response:
    encoding = response.info().get_param('charset', 'utf8')
    html = response.read().decode(encoding)

Reportez-vous à la urlopen documentation pour plus de détails.

16
Aran-Fey