2011-01-05 3 views
1

Я пытаюсь получить данные с использованием регулярных выражений из файла HTML, путем реализации следующего кода:Извлечение исходного кода из файла HTML, используя python3.1 urllib.request

import urllib.request 
def extract_words(wdict, urlname): 
    uf = urllib.request.urlopen(urlname) 
    text = uf.read() 
    print (text) 
    match = re.findall("<tr>\s*<td>([\w\s.;'(),-/]+)</td>\s+<td>([\w\s.,;'()-/]+)</td>\s*</tr>", text) 

который возвращает ошибку:

File "extract.py", line 33, in extract_words 
match = re.findall("<tr>\s*<td>([\w\s.;'(),-/]+)</td>\s+<td>([\w\s.,;'()-/]+)</td>\s*</tr>", text) 
File "/usr/lib/python3.1/re.py", line 192, in findall 
return _compile(pattern, flags).findall(string) 
TypeError: can't use a string pattern on a bytes-like object 

При повторном экспериментировании в IDLE я заметил, что uf.read() действительно возвращает исходный код html при первом вызове. Но затем он возвращает a-b ''. Есть ли способ обойти это?

ответ

2

uf.read() будет читать содержимое только один раз. Затем вам нужно закрыть его и снова открыть, чтобы прочитать его снова. Это верно для любого потока. Это, однако, не проблема.

Проблема в том, что чтение из любого типа двоичного источника, такого как файл или веб-страница, вернет данные как тип bytes, если только вы не указали кодировку. Но ваше регулярное выражение не указано как тип bytes, оно указано как unicode str.

Модуль re вполне разумно откажется использовать шаблоны юникода в байтовых данных, а наоборот.

Решение состоит в том, чтобы сделать шаблон регулярного выражения байтовой строкой, которую вы делаете, поставив перед ним букву b. Следовательно:

match = re.findall(b"<tr>\s*<td>([\w\s.;'(),-/]+)</td>\s+<td>([\w\s.,;'()-/]+)</td>\s*</tr>", text) 

Должно работать. Другим вариантом является, чтобы декодировать текст таким образом, он также является юникода str:

encoding = uf.headers.getparam('charset') 
text = text.decode(encoding) 
match = re.findall("<tr>\s*<td>([\w\s.;'(),-/]+)</td>\s+<td>([\w\s.,;'()-/]+)</td>\s*</tr>", text) 

(Кроме того, для извлечения данных из HTML, я бы сказал, что lxml это лучший вариант).