I am trying to get clean text from some web pages. I have read a lot of tutorials and finally ended up with python lxml + beautifulsoup + requests modules . The reason for using lxml for such a task is that it cleans html files better than beautiful soup do.
I ended up with test script like this:
from bs4 import UnicodeDammit import re import requests import lxml import lxml.html from time import sleep urls = [ "http://mathprofi.ru/zadachi_po_kombinatorike_primery_reshenij.html", "http://ru.onlinemschool.com/math/assistance/statistician/", "http://mathprofi.ru/zadachi_po_kombinatorike_primery_reshenij.html", "http://universarium.org/courses/info/332", "http://compsciclub.ru/course/wordscombinatorics", "http://ru.onlinemschool.com/math/assistance/statistician/", "http://lectoriy.mipt.ru/course/Maths-Combinatorics-AMR-Lects/", "http://www.youtube.com/watch?v=SLPrGWQBX0I" ] def check(url): print "That is url {}".format(url) r = requests.get(url) ud = UnicodeDammit(r.content, is_html=True) content = ud.unicode_markup.encode(ud.original_encoding, "ignore") root = lxml.html.fromstring(content) lxml.html.etree.strip_elements(root, lxml.etree.Comment, "script", "style") text = lxml.html.tostring(root, method="text", encoding=unicode) text = re.sub('\s+', ' ', text) print "Text type is {}!".format(type(text)) print text[:200] sleep(1) if __name__ == '__main__': for url in urls: check(url) Inetrmediate de- and reencoding to the original encoding is needed because the html page could contain some characters that are encoded differently from the most others. Such an occasion breaks further lxml tostring method.
However my code is not working properly with all tests. Sometimes (especially with last two urls) it outputs the mess:
... That is url http://ru.onlinemschool.com/math/assistance/statistician/ Text type is <type 'unicode'>! Онлайн решение задач по математике. Комбинаторика. Теория вероятности. Close Авторизация на сайте Введите логин: Введите пароль: Запомнить меня Регистрация Изучение математики онлайн.Изучайте математ That is url http://lectoriy.mipt.ru/course/Maths-Combinatorics-AMR-Lects/ Text type is <type 'unicode'>! ÐаÑемаÑика. ÐÑÐ½Ð¾Ð²Ñ ÐºÐ¾Ð¼Ð±Ð¸Ð½Ð°ÑоÑики и ÑеоÑии ÑиÑел / ÐидеолекÑии ФизÑеÑа: ÐекÑоÑий ÐФТР- видеолекÑии по Ñизике, That is url http://www.youtube.com/watch?v=SLPrGWQBX0I Text type is <type 'unicode'>! ÐÑновнÑе ÑоÑмÑÐ»Ñ ÐºÐ¾Ð¼Ð±Ð¸Ð½Ð°ÑоÑики - bezbotvy - YouTube ÐÑопÑÑÑиÑÑ RU ÐобавиÑÑ Ð²Ð¸Ð´ÐµÐ¾ÐойÑиÐоиÑк ÐагÑÑзка... ÐÑбеÑиÑе ÑзÑк. This mess is somehow connected with encoding ISO-8859-1, but i cannot find out how. For each of two last urls i get:
In [319]: r = requests.get(urls[-1]) In [320]: chardet.detect(r.content) Out[320]: {'confidence': 0.99, 'encoding': 'utf-8'} In [321]: UnicodeDammit(r.content, is_html=True).original_encoding Out[321]: 'utf-8' In [322]: r = requests.get(urls[-2]) In [323]: chardet.detect(r.content) Out[323]: {'confidence': 0.99, 'encoding': 'utf-8'} In [324]: UnicodeDammit(r.content, is_html=True).original_encoding Out[324]: u'utf-8' So i guess lxml makes internal decoding based on the wrong assumptions of an input string. I think that it don't even try to make guess about input string encoding. It seems that in the core of lxml happens something like this :
In [339]: print unicode_string.encode('utf-8').decode("ISO-8859-1", "ignore") ÑÑÑока How could i resolve my issue and clean all urls from html tags ? Maybe i should use another python modules or do it another way ? Please, give me your suggestions.
UnicodeDammitallows to guess charset of a web page according to http headers,metatag and contents.r.contentis notunicode, it is simple sequence of bytes from server.r.textconvertsr.contenttounicodeassuming it is inr.encoding. Howeverr.encodingis not always right and i could not user.textmethod, because i get an error fromlxml:UnicodeDecodeError: 'utf8' codec can't decode byte 0x.. in position ..: invalid continuation byte