TypeError: нельзя использовать строковый шаблон для байтового объекта в re.findall ()

112

Я пытаюсь узнать, как автоматически получать URL-адреса со страницы. В следующем коде я пытаюсь получить название веб-страницы:

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)

И я получаю эту неожиданную ошибку:

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

Что я делаю не так?

Inspired_Blue
источник
1
возможный дубликат Convert bytes to a Python string
gnat

Ответы:

162

Вы хотите преобразовать html (байтовый объект) в строку .decode, например, используя html = response.read().decode('utf-8').

См. Раздел Преобразование байтов в строку Python

скалистый
источник
Это решило ошибку, TypeError: cannot use a string pattern on a bytes-like objectно потом я получил такие ошибки, как UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 1: invalid start byte. Я исправил это с помощью .decode("utf-8", "ignore"): stackoverflow.com/questions/62170614/…
baptx
"игнорировать" игнорирует. Если это то, чего вы хотите, тогда все хорошо. Однако иногда такая проблема противоречит более глубокой проблеме, например, что то, что вы хотите декодировать, на самом деле не декодируется или не предназначено, например, сжатый или зашифрованный текст. Или может потребоваться другая кодировка, например utf-16. Пусть покупатель будет бдителен.
каменистый
29

Проблема заключается в том, что ваше регулярное выражение является строкой, но htmlэто байт :

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

Поскольку python не знает, как кодируются эти байты, он выдает исключение, когда вы пытаетесь использовать для них строковое регулярное выражение.

Вы можете преобразовать decodeбайты в строку:

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

Или используйте байтовое регулярное выражение:

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

В этом конкретном контексте вы можете получить кодировку из заголовков ответов:

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

Смотрите urlopenдокументацию для более подробной информации.

Аран-Фей
источник