Задача была разобрать произвольную веб-страницу на текст и ссылки.
Снчала для разбора html использовал lxml.html:
Теперь можно пройтись по дереву тэгов и извлечь, что нужно. Но вот с кодировками как всегда не всё ладно. На данном этапе все текстовые поля уже переведены в юникод, и повлиять на процесс декодирования довольно сложно. Есть пример, когда кодировка угадана парсером неверно. Морда сайта lenta.ru всегда распознаётся как cp1252.
Можно, конечно, сначала скачать страницу, запустить что-нибудь вроде chardet (он эту страницу распознаёт правильно), потом скормить получившуюся строку парсеру:
Здесь, очевидно, получим замедление работы.
А вот, что получилось с BeautifulSoup:
P.S.
Работа chardet немного напоминает результат первого из описанных выше подходов. А именно: первое русское слово на морде lenta.ru есть 'Главное'. На этом сайте кодировка 'cp1251', но в метатегах об этом не сказано. И если написать:
то будет сюрприз. Но вот стоит хотя бы изменить первую заглавную букву на строчную - и всё работает нормально.
Наверное html.parse определяет кодировку по первому текстовому полю.
Снчала для разбора html использовал lxml.html:
from lxml import html
from lxml.html import clean
url = 'http://ya.ru'
tree = html.parse(url)
root = tree.getroot()
root.make_links_absolute(url)
links = [l[2] for l in root.iterlinks()
if l[0].tag == 'a' and l[1] == 'href'
or l[0].tag == 'frame' and l[1] == 'src']
Теперь можно пройтись по дереву тэгов и извлечь, что нужно. Но вот с кодировками как всегда не всё ладно. На данном этапе все текстовые поля уже переведены в юникод, и повлиять на процесс декодирования довольно сложно. Есть пример, когда кодировка угадана парсером неверно. Морда сайта lenta.ru всегда распознаётся как cp1252.
Можно, конечно, сначала скачать страницу, запустить что-нибудь вроде chardet (он эту страницу распознаёт правильно), потом скормить получившуюся строку парсеру:
import urllib2
from lxml import html
import chardet
def convert(s):
encoding = chardet.detect(s)['encoding']
if encoding is None:
return unicode(s)
return unicode(s, encoding, 'ignore')
url = 'http://lenta.ru'
f = urllib2.urlopen(url)
text = convert(f.read())
root = html.fromstring(text)
Здесь, очевидно, получим замедление работы.
А вот, что получилось с BeautifulSoup:
from lxml import html
from BeautifulSoup import BeautifulSoup
import urllib2
def beautifulLinks(soup, transformFunc):
linkTypes = [('a', 'href'),
('frame', 'src'),
('iframe', 'src')]
return reduce(lambda x, y: x +
[transformFunc(a[y[1]])
for a in soup.findAll(y[0])
if a.has_key(y[1])], linkTypes, [])
url = 'http://lenta.ru'
f = urllib2.urlopen(url)
soup = BeautifulSoup(f, convertEntities='html')
links = beautifulLinks(
soup,
lambda x: html.urljoin(unicode(url), x))
Данный код быстрее, и кодиорвки распознаются правильно. (Неказистость функции beautifulLinks не в счёт)P.S.
Работа chardet немного напоминает результат первого из описанных выше подходов. А именно: первое русское слово на морде lenta.ru есть 'Главное'. На этом сайте кодировка 'cp1251', но в метатегах об этом не сказано. И если написать:
>>>chardet.detect(u'Главное'.encode('cp1251'))
{'confidence': 0.87767968407042096, 'encoding': 'MacCyrillic'}
то будет сюрприз. Но вот стоит хотя бы изменить первую заглавную букву на строчную - и всё работает нормально.
>>>chardet.detect(u'главное'.encode('cp1251'))
{'confidence': 0.98999999999999999, 'encoding': 'windows-1251'}
Наверное html.parse определяет кодировку по первому текстовому полю.
Комментариев нет:
Отправить комментарий