Стриптиз HTML из строк в Python

from mechanize import Browser
br = Browser()
br.open('http://somewebpage')
html = br.response().readlines()
for line in html:
  print line

При печати строки в файле HTML я пытаюсь найти способ показать содержимое только каждого элемента HTML, а не самого форматирования. Если он найдет '<a href="whatever.com">some text</a>', он будет печатать только "некоторый текст", '<b>hello</b>' печатает "привет" и т.д. Как это можно сделать?

Ответ 1

Я всегда использовал эту функцию для разметки тегов HTML, поскольку для этого требуется только Python stdlib:

В Python 2

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

Для Python 3

from html.parser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

Примечание: это работает только для 3.1. Для версии 3.2 или выше вам нужно вызвать родительский класс init. См. Использование HTMLParser в Python 3.2

Ответ 2

Я не очень много думал о случаях, которые он пропустит, но вы можете сделать простое регулярное выражение:

re.sub('<[^<]+?>', '', text)

Для тех, кто не понимает регулярное выражение, он ищет строку <...>, где внутренний контент состоит из одного или нескольких символов (+), который не является <. ? означает, что он будет соответствовать самой маленькой строке, которую он может найти. Например, с учетом <p>Hello</p> он будет соответствовать <'p> и </p> отдельно с помощью ?. Без него он будет соответствовать всей строке <..Hello..>.

Если в html (например, 2 < 3) появляется не тег <, он должен быть записан как escape-последовательность &..., поэтому ^< может быть ненужным.

Ответ 3

Почему все вы делаете это трудным путем? Вы можете использовать get_text() BeautifulSoup get_text().

from bs4 import BeautifulSoup

html_str = '''
<td><a href="http://www.fakewebsite.com">Please can you strip me?</a>
<br/><a href="http://www.fakewebsite.com">I am waiting....</a>
</td>
'''
soup = BeautifulSoup(html_str)

print(soup.get_text()) 
#or via attribute of Soup Object: print(soup.text)

Ответ 4

Краткая версия!

import re, cgi
tag_re = re.compile(r'(<!--.*?-->|<[^>]*>)')

# Remove well-formed tags, fixing mistakes by legitimate users
no_tags = tag_re.sub('', user_input)

# Clean up anything else by escaping
ready_for_web = cgi.escape(no_tags)

Источник регулярных выражений: MarkupSafe. Их версия также обрабатывает объекты HTML, в то время как этот быстрый не делает.

Почему я не могу просто удалить теги и оставить его?

Одно дело держать людей от <i>italicizing</i> вещей, не оставляя i плавающим. Но это другое, чтобы принять произвольный вклад и сделать его совершенно безвредным. Большинство методов на этой странице оставят такие вещи, как закрытые комментарии (<!--) и угловые скобки, которые не являются частью тегов (blah <<<><blah) неповрежденными. Версия HTMLParser может даже оставить полные теги, если они находятся в закрытом комментарии.

Что делать, если ваш шаблон {{ firstname }} {{ lastname }}? firstname = '<a' и lastname = 'href="http://evil.com/">' будут пропускаться каждым дескриптором тега на этой странице (кроме @Medeiros!), потому что они не являются полными тегами самостоятельно. Вырезать обычные теги HTML недостаточно.

Django strip_tags, улучшенная (см. следующий заголовок) версия верхнего ответа на этот вопрос дает следующее предупреждение:

Абсолютно БЕЗ гарантии о том, что полученная строка является безопасным для HTML. Поэтому НИКОГДА не маркируйте результат вызова strip_tags, не ускоряя его, например, с помощью escape().

Следуйте их советам!

Чтобы разбить теги с помощью HTMLParser, вы должны запускать его несколько раз.

Легко обойти верхний ответ на этот вопрос.

Посмотрите на эту строку (источник и обсуждение):

<img<!-- --> src=x onerror=alert(1);//><!-- -->

В первый раз, когда HTMLParser видит это, он не может сказать, что <img...> является тегом. Он выглядит сломанным, поэтому HTMLParser не избавляется от него. Он вынимает только <!-- comments -->, оставляя вас с

<img src=x onerror=alert(1);//>

Эта проблема была раскрыта проекту Django в марте 2014 года. Их старый strip_tags был по существу тем же самым, что и верхний ответ на этот вопрос. Их новая версия в основном запускает его в цикле до тех пор, пока не запустит его снова, не изменит строку:

# _strip_once runs HTMLParser once, pulling out just the text of all the nodes.

def strip_tags(value):
    """Returns the given HTML with all tags stripped."""
    # Note: in typical case this loop executes _strip_once once. Loop condition
    # is redundant, but helps to reduce number of executions of _strip_once.
    while '<' in value and '>' in value:
        new_value = _strip_once(value)
        if len(new_value) >= len(value):
            # _strip_once was not able to detect more tags
            break
        value = new_value
    return value

Конечно, ничто из этого не является проблемой, если вы всегда избегаете результата strip_tags().

Обновление 19 марта 2015 г.. В версиях Django произошла ошибка до 1.4.20, 1.6.11, 1.7.7 и 1.8c1. Эти версии могут вводить бесконечный цикл в функцию strip_tags(). Исправленная версия воспроизводится выше. Подробнее здесь.

Хорошие вещи для копирования или использования

Мой примерный код не обрабатывает HTML-объекты - пакеты с Django и MarkupSafe.

Мой примерный код извлекается из отличной библиотеки MarkupSafe для предотвращения межсайтовых скриптингов. Это удобно и быстро (с ускорением C к его родной версии Python). Он включен в Google App Engine и используется Jinja2 (2.7 и выше), Mako, Pylons и Больше. Он легко работает с шаблонами Django от Django 1.7.

Django strip_tags и другие утилиты html из последней версии хороши, но я считаю их менее удобными, чем MarkupSafe. Они довольно самодостаточны, вы можете скопировать то, что вам нужно от этого файла.

Если вам нужно снять почти все теги, библиотека Bleach хороша. Вы можете заставить его применять такие правила, как "мои пользователи могут выделять курсивом, но они не могут создавать iframes".

Поймите свойства вашего стриппера тегов! Запустите тесты Fuzz! Вот код, который я использовал для исследования для этого ответа.

sheepish note - сам вопрос заключается в печати на консоли, но это лучший результат Google для "python strip html from string", поэтому почему этот ответ составляет 99% в Интернете.

Ответ 5

Мне нужен был способ вырезать теги и декодировать HTML-объекты в обычный текст. Следующее решение основано на ответе Eloff (который я не смог использовать, потому что он удаляет сущности).

from HTMLParser import HTMLParser
import htmlentitydefs

class HTMLTextExtractor(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.result = [ ]

    def handle_data(self, d):
        self.result.append(d)

    def handle_charref(self, number):
        codepoint = int(number[1:], 16) if number[0] in (u'x', u'X') else int(number)
        self.result.append(unichr(codepoint))

    def handle_entityref(self, name):
        codepoint = htmlentitydefs.name2codepoint[name]
        self.result.append(unichr(codepoint))

    def get_text(self):
        return u''.join(self.result)

def html_to_text(html):
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

Быстрый тест:

html = u'<a href="#">Demo <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>'
print repr(html_to_text(html))

Результат:

u'Demo (\xac \u0394\u03b7\u03bc\u03ce)'

Обработка ошибок:

  • Неверная структура HTML может вызвать HTMLParseError.
  • Недопустимые именованные сущности HTML (такие как &#apos; допустимый в XML и XHTML, но не в обычном HTML) вызовут исключение ValueError.
  • Числовые объекты HTML, указывающие кодовые точки вне диапазона Unicode, приемлемого для Python (например, в некоторых системах символы вне базовой многоязычной плоскости), вызовут исключение ValueError.

Примечание по безопасности: Не путайте разметку HTML (преобразование HTML в простой текст) с очисткой HTML (преобразование обычного текста в HTML). Этот ответ удалит HTML и расшифрует объекты в обычный текст, что не делает результат безопасным для использования в контексте HTML.

Пример: &lt;script&gt;alert("Hello");&lt;/script&gt; будет преобразован в <script>alert("Hello");</script>, который на 100% корректен, но явно недостаточен, если полученный текстовый текст вставляется как есть на страницу HTML.

Правило не сложное: всякий раз, когда вы вставляете текстовую строку в вывод HTML, вы всегда должны избегать ее с помощью HTML (используя cgi.escape(s, True)), даже если вы "знаете", что она не содержит HTML (например, потому что вы удалили содержимое HTML).

(Однако OP спросил о выводе результата на консоль, и в этом случае экранирование HTML не требуется.)

Версия Python 3. 4+: (с doctest!)

import html.parser

class HTMLTextExtractor(html.parser.HTMLParser):
    def __init__(self):
        super(HTMLTextExtractor, self).__init__()
        self.result = [ ]

    def handle_data(self, d):
        self.result.append(d)

    def get_text(self):
        return ''.join(self.result)

def html_to_text(html):
    """Converts HTML to plain text (stripping tags and converting entities).
    >>> html_to_text('<a href="#">Demo<!--...--> <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>')
    'Demo (\xac \u0394\u03b7\u03bc\u03ce)'

    "Plain text" doesn't mean result can safely be used as-is in HTML.
    >>> html_to_text('&lt;script&gt;alert("Hello");&lt;/script&gt;')
    '<script>alert("Hello");</script>'

    Always use html.escape to sanitize text before using in an HTML context!

    HTMLParser will do its best to make sense of invalid HTML.
    >>> html_to_text('x < y &lt z <!--b')
    'x < y < z '

    Unrecognized named entities are included as-is. '&apos;' is recognized,
    despite being XML only.
    >>> html_to_text('&nosuchentity; &apos; ')
    "&nosuchentity; ' "
    """
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

Обратите внимание, что HTMLParser улучшился в Python 3 (что означает меньше кода и лучшую обработку ошибок).

Ответ 6

Простой способ:

def remove_html_markup(s):
    tag = False
    quote = False
    out = ""

    for c in s:
            if c == '<' and not quote:
                tag = True
            elif c == '>' and not quote:
                tag = False
            elif (c == '"' or c == "'") and tag:
                quote = not quote
            elif not tag:
                out = out + c

    return out

Идея объясняется здесь: http://youtu.be/2tu9LTDujbw

Вы можете увидеть, как он работает здесь: http://youtu.be/HPkNPcYed9M?t=35s

PS - Если вас интересует класс (о умной отладке с помощью python), я даю вам ссылку: http://www.udacity.com/overview/Course/cs259/CourseRev/1. Это бесплатно!

Добро пожаловать!:)

Ответ 7

Если вам нужно сохранить объекты HTML (т.е. &amp;), я добавил метод handle_entityref для ответа Eloff.

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def handle_entityref(self, name):
        self.fed.append('&%s;' % name)
    def get_data(self):
        return ''.join(self.fed)

def html_to_text(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

Ответ 8

Если вы хотите удалить все HTML-теги, я обнаружил, что проще всего использовать BeautifulSoup:

from bs4 import BeautifulSoup  # Or from BeautifulSoup import BeautifulSoup

def stripHtmlTags(htmlTxt):
    if htmlTxt is None:
            return None
        else:
            return ''.join(BeautifulSoup(htmlTxt).findAll(text=True)) 

Я попробовал код принятого ответа, но я получил "RuntimeError: превышена максимальная глубина рекурсии", чего не произошло с вышеуказанным блоком кода.

Ответ 9

Решение lxml.html -based (lxml является нативной библиотекой и поэтому намного быстрее, чем любое чистое решение на python).

from lxml import html
from lxml.html.clean import clean_html

tree = html.fromstring("""<span class="item-summary">
                            Detailed answers to any questions you might have
                        </span>""")

print(clean_html(tree).strip())

# >>> Detailed answers to any questions you might have

Также смотрите http://lxml.de/lxmlhtml.html#cleaning-up-html, что именно делает lxml.cleaner.

Если вам требуется больше контроля над тем, что именно очищается перед преобразованием в текст, тогда вы можете явно использовать lxml Cleaner, передавая нужные параметры в конструкторе, например:

cleaner = Cleaner(page_structure=True,
                  meta=True,
                  embedded=True,
                  links=True,
                  style=True,
                  processing_instructions=True,
                  inline_style=True,
                  scripts=True,
                  javascript=True,
                  comments=True,
                  frames=True,
                  forms=True,
                  annoying_tags=True,
                  remove_unknown_tags=True,
                  safe_attrs_only=True,
                  safe_attrs=frozenset(['src','color', 'href', 'title', 'class', 'name', 'id']),
                  remove_tags=('span', 'font', 'div')
                  )
sanitized_html = cleaner.clean_html(unsafe_html)

Ответ 10

Пакет Beautiful Soup делает это немедленно для вас.

from bs4 import BeautifulSoup

soup = BeautifulSoup(html)
text = soup.get_text()
print(text)

Ответ 11

Вы можете использовать либо другой парсер HTML (как lxml, либо Beautiful Soup) - тот, который предлагает функции для извлечения только текста. Или вы можете запустить регулярное выражение в строке строки, которая удаляет теги. Подробнее см. http://www.amk.ca/python/howto/regex/.

Ответ 12

Я успешно использовал Eloff для Python 3.1 [большое спасибо!].

Я обновился до Python 3.2.3 и столкнулся с ошибками.

Решение, предоставленное здесь благодаря ответчику Томасу К., должно вставить super().__init__() в следующий код:

def __init__(self):
    self.reset()
    self.fed = []

... чтобы он выглядел следующим образом:

def __init__(self):
    super().__init__()
    self.reset()
    self.fed = []

... и он будет работать для Python 3.2.3.

Опять же, благодаря Thomas K для исправления и исходного кода Eloff, приведенного выше!

Ответ 13

Решения с HTML-Parser все разрываются, если они запускаются только один раз:

html_to_text('<<b>script>alert("hacked")<</b>/script>

приводит к:

<script>alert("hacked")</script>

то, что вы намерены предотвратить. если вы используете HTML-Parser, считайте теги до тех пор, пока не будут заменены ноль:

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
        self.containstags = False

    def handle_starttag(self, tag, attrs):
       self.containstags = True

    def handle_data(self, d):
        self.fed.append(d)

    def has_tags(self):
        return self.containstags

    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    must_filtered = True
    while ( must_filtered ):
        s = MLStripper()
        s.feed(html)
        html = s.get_data()
        must_filtered = s.has_tags()
    return html

Ответ 14

Это быстрое исправление и может быть еще более оптимизировано, но оно будет работать нормально. Этот код заменит все непустые теги на "" и разделит все теги html на определенный входной текст. Вы можете запустить его с использованием входного ввода. /file.py

    #!/usr/bin/python
import sys

def replace(strng,replaceText):
    rpl = 0
    while rpl > -1:
        rpl = strng.find(replaceText)
        if rpl != -1:
            strng = strng[0:rpl] + strng[rpl + len(replaceText):]
    return strng


lessThanPos = -1
count = 0
listOf = []

try:
    #write File
    writeto = open(sys.argv[2],'w')

    #read file and store it in list
    f = open(sys.argv[1],'r')
    for readLine in f.readlines():
        listOf.append(readLine)         
    f.close()

    #remove all tags  
    for line in listOf:
        count = 0;  
        lessThanPos = -1  
        lineTemp =  line

            for char in lineTemp:

            if char == "<":
                lessThanPos = count
            if char == ">":
                if lessThanPos > -1:
                    if line[lessThanPos:count + 1] != '<>':
                        lineTemp = replace(lineTemp,line[lessThanPos:count + 1])
                        lessThanPos = -1
            count = count + 1
        lineTemp = lineTemp.replace("&lt","<")
        lineTemp = lineTemp.replace("&gt",">")                  
        writeto.write(lineTemp)  
    writeto.close() 
    print "Write To --- >" , sys.argv[2]
except:
    print "Help: invalid arguments or exception"
    print "Usage : ",sys.argv[0]," inputfile outputfile"

Ответ 15

Адаптация python 3 søren-løvborg

from html.parser import HTMLParser
from html.entities import html5

class HTMLTextExtractor(HTMLParser):
    """ Adaption of http://stackoverflow.com/a/7778368/196732 """
    def __init__(self):
        super().__init__()
        self.result = []

    def handle_data(self, d):
        self.result.append(d)

    def handle_charref(self, number):
        codepoint = int(number[1:], 16) if number[0] in (u'x', u'X') else int(number)
        self.result.append(unichr(codepoint))

    def handle_entityref(self, name):
        if name in html5:
            self.result.append(unichr(html5[name]))

    def get_text(self):
        return u''.join(self.result)

def html_to_text(html):
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

Ответ 16

Для одного проекта мне нужно было раздеть HTML, а также CSS и JS. Таким образом, я сделал вариант ответа Eloffs:

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.fed = []
        self.css = False
    def handle_starttag(self, tag, attrs):
        if tag == "style" or tag=="script":
            self.css = True
    def handle_endtag(self, tag):
        if tag=="style" or tag=="script":
            self.css=False
    def handle_data(self, d):
        if not self.css:
            self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

Ответ 17

Здесь решение, аналогичное принятому в настоящее время ответу (fooobar.com/questions/31753/...), за исключением того, что оно напрямую использует внутренний класс HTMLParser (т.е. не HTMLParser подклассы), тем самым делая его значительно более кратким:

def strip_html(text):
    parts = []                                                                      
    parser = HTMLParser()                                                           
    parser.handle_data = parts.append                                               
    parser.feed(text)                                                               
    return ''.join(parts)

Ответ 18

Вы можете написать свою собственную функцию:

def StripTags(text):
     finished = 0
     while not finished:
         finished = 1
         start = text.find("<")
         if start >= 0:
             stop = text[start:].find(">")
             if stop >= 0:
                 text = text[:start] + text[start+stop+1:]
                 finished = 0
     return text

Ответ 19

Я разбираю Github readmes, и я считаю, что следующее действительно хорошо работает:

import re
import lxml.html

def strip_markdown(x):
    links_sub = re.sub(r'\[(.+)\]\([^\)]+\)', r'\1', x)
    bold_sub = re.sub(r'\*\*([^*]+)\*\*', r'\1', links_sub)
    emph_sub = re.sub(r'\*([^*]+)\*', r'\1', bold_sub)
    return emph_sub

def strip_html(x):
    return lxml.html.fromstring(x).text_content() if x else ''

И затем

readme = """<img src="https://raw.githubusercontent.com/kootenpv/sky/master/resources/skylogo.png" />

            sky is a web scraping framework, implemented with the latest python versions in mind (3.4+). 
            It uses the asynchronous `asyncio` framework, as well as many popular modules 
            and extensions.

            Most importantly, it aims for **next generation** web crawling where machine intelligence 
            is used to speed up the development/maintainance/reliability of crawling.

            It mainly does this by considering the user to be interested in content 
            from *domains*, not just a collection of *single pages*
            ([templating approach](#templating-approach))."""

strip_markdown(strip_html(readme))

Удаляет все уценки и html правильно.

Ответ 20

Используя BeautifulSoup, html2text или код из @Eloff, в большинстве случаев остаются некоторые элементы html, код javascript...

Таким образом, вы можете использовать комбинацию этих библиотек и удалить форматирование уценки (Python 3):

import re
import html2text
from bs4 import BeautifulSoup
def html2Text(html):
    def removeMarkdown(text):
        for current in ["^[ #*]{2,30}", "^[ ]{0,30}\d\\\.", "^[ ]{0,30}\d\."]:
            markdown = re.compile(current, flags=re.MULTILINE)
            text = markdown.sub(" ", text)
        return text
    def removeAngular(text):
        angular = re.compile("[{][|].{2,40}[|][}]|[{][*].{2,40}[*][}]|[{][{].{2,40}[}][}]|\[\[.{2,40}\]\]")
        text = angular.sub(" ", text)
        return text
    h = html2text.HTML2Text()
    h.images_to_alt = True
    h.ignore_links = True
    h.ignore_emphasis = False
    h.skip_internal_links = True
    text = h.handle(html)
    soup = BeautifulSoup(text, "html.parser")
    text = soup.text
    text = removeAngular(text)
    text = removeMarkdown(text)
    return text

Это хорошо работает для меня, но может быть улучшено, конечно...

Ответ 21

Вот мое решение для Python 3.

import html
import re

def html_to_txt(html_text):
    ## unescape html
    txt = html.unescape(html_text)
    tags = re.findall("<[^>]+>",txt)
    print("found tags: ")
    print(tags)
    for tag in tags:
        txt=txt.replace(tag,'')
    return txt

Не уверен, что это идеально, но решил мой вариант использования и кажется простым.

Ответ 22

Простой код! Это удалит все виды тегов и содержимого внутри него.

def rm(s):
    start=False
    end=False
    s=' '+s
    for i in range(len(s)-1):
        if i<len(s):
            if start!=False:
                if s[i]=='>':
                    end=i
                    s=s[:start]+s[end+1:]
                    start=end=False
            else:
                if s[i]=='<':
                    start=i
    if s.count('<')>0:
        self.rm(s)
    else:
        s=s.replace('&nbsp;', ' ')
        return s

Но он не даст полного результата, если текст содержит символы <>.

Ответ 23

hext это пакет, который помимо всего прочего может лишить HTML. Это альтернатива beautifulsoup. Следующее было протестировано с hext==0.2.3.

Сохраните это в служебном модуле, например, util/hext.py:

import hext

_HTML_TEXT_RULE = hext.Rule('<html @text:text />')


def html_to_text(text: str) -> str:
    # Ref: https://stackoverflow.com/a/56894409/
    return _HTML_TEXT_RULE.extract(hext.Html(f'<html>{text}</html>'))[0]['text']

Примеры использования:

>>> from .util.hext import html_to_text

>>> html_to_text('<b>Hello world!</b>')
'Hello world!'

>>> html_to_text('<a href="google.com">some text</a>')
'some text'

>>> html_to_text('<span class="small-caps">l</span>-arginine minimizes immunosuppression and prothrombin time and enhances the genotoxicity of 5-fluorouracil in rats')
'l-arginine minimizes immunosuppression and prothrombin time and enhances the genotoxicity of 5-fluorouracil in rats'

>>> html_to_text('Attenuation of diabetic nephropathy by dietary fenugreek (<em>Trigonella foenum-graecum</em>) seeds and onion (<em>Allium cepa</em>) <em>via</em> suppression of glucose transporters and renin-angiotensin system')
'Attenuation of diabetic nephropathy by dietary fenugreek (Trigonella foenum-graecum) seeds and onion (Allium cepa) via suppression of glucose transporters and renin-angiotensin system'

Примеры использования с искаженным HTML:

>>> html_to_text('<b>Hello <i>world!')
'Hello world!'

>>> html_to_text('<a href="google.com">some <faketag>text')
'some text'

Ответ 24

Этот метод работает безупречно для меня и не требует дополнительных установок:

import re
import htmlentitydefs

def convertentity(m):
    if m.group(1)=='#':
        try:
            return unichr(int(m.group(2)))
        except ValueError:
            return '&#%s;' % m.group(2)
        try:
            return htmlentitydefs.entitydefs[m.group(2)]
        except KeyError:
            return '&%s;' % m.group(2)

def converthtml(s):
    return re.sub(r'&(#?)(.+?);',convertentity,s)

html =  converthtml(html)
html.replace("&nbsp;", " ") ## Get rid of the remnants of certain formatting(subscript,superscript,etc).