5 янв. 2009 г.

Краулер своими руками. Часть 6

Нормализация ссылок

Присмотревшись к логам, я заметил странные адреса, например:
INFO Opening http://pi-code.blogspot.com/2008/12/\"http://pi-code.blogspot.com/\"
Дешевый способ преобразовывать относительные адреса в абсолютные:

u = urlparse.urldefrag( # удаление фрагмента
urlparse.urljoin(base, tag['href'], allow_fragments=False)
)[0].encode('ascii')
явно ненадежен. Пришлось писать новый вариант:

def normalize_url(base, url):
"""
Нормализация URL. Используется для преобразования относительных адресов
в абсолютные.

base -- домен (напр. 'taxonomist.tripod.com'), вторая часть результата
urlparse.urlsplit result
url -- исходный URL, может быть относительным.
"""
parts = urlparse.urlsplit(url)
defaults = ('http', base, '/', parts[3], parts[4])
norm = [ p if p else defaults[i]
for i, p in enumerate(parts) ]
url = urlparse.urlunsplit(norm)
url = urlparse.urldefrag(url)[0] # удаление фрагмента
url = url.encode('ascii') # перекодировка из уникода в ascii
return url


def links_iterator(response, link_filter=None):
"""
Итератор по ссылкам, найденным в документе.
Аргументы:
response -- file-like object, возвращаемый
при открытии страницы библиотекой urllib2
filter -- функция, которая может быть использована для
отбора нужных ссылок. На входе: url, на выходе
True, если проверка прошла, иначе -- False
Если параметр 'filter' не задан, итератор возвращает
все найденные ссылки.
"""
if not link_filter:
link_filter = lambda x: True
base = response.geturl()

parser = html5lib.HTMLParser(
tree=treebuilders.getTreeBuilder('dom'),
tokenizer=sanitizer.HTMLSanitizer)
dom = parser.parse(response)
for elem in dom.getElementsByTagName('a'):
if elem.hasAttribute('href'):
href = elem.getAttribute('href')
u = normalize_url(base, href)
if link_filter(u):
yield u

dom.unlink()

Теперь относительные адреса стали преобразовываться в абсолютные по-человечески.

"Минздрав предупреждает"

Еще один неприятный момент: при импорте html5lib Python 2.6 выдавал DeprecationWarning:
C:\Python26\lib\site-packages\html5lib-0.11.1-py2.6.egg\html5lib\
inputstream.py:367:DeprecationWarning: object.__init__() takes no parameters
Эти предупреждения Минздрава ничего, кроме раздражения не вызывают. Чтобы избавиться от них, я добавил в parsers.py следующий код:
from html5lib import treebuilders, sanitizer
import warnings
warnings.simplefilter("ignore",DeprecationWarning)

Комментариев нет: