Usuwa HTML z ciągów w Pythonie

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

Podczas drukowania linii w pliku HTML staram się znaleźć sposób na pokazanie tylko zawartości każdego elementu HTML, a nie samego formatowania. Jeśli znajdzie '<a href="whatever.com">some text</a>', wyświetli tylko 'jakiś tekst', '<b>hello</b>' wyświetli 'hello', itd. Jak można to zrobić?

 226
Author: Peter Mortensen, 2009-04-15

20 answers

Zawsze używałem tej funkcji do usuwania znaczników HTML, ponieważ wymaga tylko pythonowego stdlib:

On 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()

Dla Pythona 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()

Uwaga : to działa tylko dla 3.1. W przypadku wersji 3.2 lub wyższej, należy wywołać funkcję INIT klasy nadrzędnej. Zobacz używanie Htmlparsera w Pythonie 3.2

 366
Author: Community,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:02

Nie myślałem zbyt wiele o przypadkach, które będzie brakować, ale możesz zrobić proste regex:

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

Dla tych, którzy nie rozumieją wyrażenia regularnego, to wyszukuje łańcuch <...>, Gdzie wewnętrzna zawartość składa się z jednego lub więcej (+) znaków, które nie są <. ? oznacza, że będzie pasował do najmniejszego ciągu, jaki może znaleźć. Na przykład podany <p>Hello</p>, będzie pasował <'p> i </p> oddzielnie z ?. Bez niego będzie pasował do całego ciągu <..Hello..>.

If non-tag < pojawia się w html (np. 2 < 3), powinna być zapisana jako sekwencja ucieczki &... tak czy inaczej ^< może być niepotrzebna.

 127
Author: mmmdreg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-05 14:55:49

Krótka wersja!

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)

Źródło Regex: MarkupSafe . Ich wersja obsługuje również encje HTML, podczas gdy ta szybka Nie.

Dlaczego nie mogę po prostu rozebrać metek i zostawić?

To jedna rzecz, aby trzymać ludzi z dala od rzeczy, nie zostawiając {5]}wokół. Ale to inna sprawa, aby wziąć dowolny wkład i uczynić go całkowicie nieszkodliwym. Większość technik na tej stronie pozostawi takie rzeczy jak komentarze (<!--) i nawiasy kątowe, które nie są częścią tagów (blah <<<><blah) w stanie nienaruszonym. Wersja HTMLParser może nawet pozostawić pełne tagi, jeśli znajdują się w komentarzu.

Co jeśli Twój szablon to {{ firstname }} {{ lastname }}? firstname = '<a' i lastname = 'href="http://evil.com/">' zostaną przepuszczone przez każdy znacznik na tej stronie (z wyjątkiem @Medeiros!), ponieważ same nie są kompletnymi znacznikami. Usuwanie zwykłych znaczników HTML nie wystarczy.

strip_tags Django, ulepszona (Zobacz następny nagłówek) wersja top odpowiedzi na to pytanie, daje następujące Ostrzeżenie:

Absolutnie nie ma gwarancji, że wynikowy ciąg znaków będzie bezpieczny dla HTML. Nigdy więc nie oznaczaj bezpiecznie wyniku wywołania strip_tags, nie uciekając przed nim wcześniej, na przykład za pomocą escape().

Postępuj zgodnie z ich radami!

Aby usunąć znaczniki za pomocą Htmlparsera, musisz uruchomić go wiele razy.

Łatwo obejść najlepszą odpowiedź na to pytanie.

Spójrz na ten ciąg (źródło i dyskusja):

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

Gdy HTMLParser widzi go po raz pierwszy, nie może powiedzieć, że <img...> jest znacznikiem. Wygląda na zepsuty, więc HTMLParser się go nie pozbywa. To tylko wyjmuje <!-- comments -->, zostawiając cię z

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

Ten problem został ujawniony projektowi Django w marcu 2014 roku. Ich stary strip_tags był zasadniczo taki sam, jak najlepsza odpowiedź na to pytanie. ich nowa wersja zasadniczo uruchamia ją w pętli, dopóki ponowne uruchomienie nie zmieni string:

# _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

Oczywiście, nic z tego nie jest problemem, jeśli zawsze unikasz wyniku strip_tags().

Aktualizacja 19 marzec, 2015: był błąd w wersjach Django przed 1.4.20, 1.6.11, 1.7.7 i 1.8c1. Wersje te mogą wejść w nieskończoną pętlę w funkcji strip_tags (). Poprawiona wersja jest przedstawiona powyżej. więcej szczegółów tutaj .

Dobre rzeczy do skopiowania lub użycia

Mój przykładowy kod nie obsługuje encji HTML-Django i Wersje pakowane MarkupSafe tak.

Mój przykładowy kod został pobrany z doskonałej bibliotekiMarkupSafe do zapobiegania skryptom krzyżowym. Jest wygodny i szybki (Z C przyspiesza do jego natywnej wersji Pythona). Jest on zawarty w Google App Engine i używany przez Jinja2 (2.7 i nowsze), Mako, pylony i inne. Działa łatwo z szablonami Django z Django 1.7.

Strip_tags Django i inne Narzędzia html z najnowszej wersji są dobre, ale uważam je za mniej wygodne niż MarkupSafe. Są dość samodzielne, możesz skopiować to, czego potrzebujesz z tego pliku .

Jeśli potrzebujesz rozebrać prawie wszystkie tagi, biblioteka Bleach jest dobra. Możesz go egzekwować zasady takie jak " moi użytkownicy mogą zaznaczać rzeczy kursywą, ale nie mogą tworzyć ramek iFrame."

Zrozum właściwości swojego striptizera tagów! Zróbcie na nim testy! oto kod {[22] } kiedyś robiłem badania dla tego odpowiedz.

Uwaga -samo pytanie dotyczy drukowania na konsoli, ale to jest najlepszy wynik Google dla "python strip html from string" , dlatego ta odpowiedź jest w 99% o sieci.

 28
Author: rescdsk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-08 14:46:48

Potrzebowałem sposobu na usunięcie znaczników i dekodowanie encji HTML do zwykłego tekstu. Poniższe rozwiązanie opiera się na odpowiedzi Eloffa (której nie mogłem użyć, ponieważ usuwa byty).

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()

Szybki test:

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

Wynik:

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

Obsługa błędów:

  • Nieprawidłowa struktura HTML może powodować HTMLParseError.
  • niepoprawne nazwane encje HTML (takie jak &#apos;, które są ważne w XML i XHTML, ale nie zwykły HTML) spowodują ValueError wyjątek.
  • Numeryczne encje HTML określające punkty kodu poza zakresem Unicode akceptowanym przez Pythona (np. w niektórych systemach znaki spoza podstawowej płaszczyzny wielojęzycznej ) spowodują wyjątekValueError.

Uwaga dotycząca bezpieczeństwa: nie należy mylić usuwania HTML (konwersja HTML na zwykły tekst) z odkażaniem HTML (konwersja zwykłego tekstu na HTML). Ta odpowiedź usunie HTML i dekoduje encje na zwykły tekst – co nie powoduje wyniku bezpieczny w użyciu w kontekście HTML.

Przykład: &lt;script&gt;alert("Hello");&lt;/script&gt; zostanie przekonwertowany na <script>alert("Hello");</script>, co jest w 100% poprawne, ale oczywiście nie wystarczające, jeśli wynikowy zwykły tekst zostanie wstawiony na stronę HTML.

Reguła nie jest trudna: za każdym razem wstawiasz zwykły tekst do wyjścia HTML, powinieneś zawsze HTML uciec od niego (używając cgi.escape(s, True)), nawet jeśli "wiesz", że nie zawiera HTML (np. dlatego, że pozbawiłeś go zawartości HTML).

(jednak OP poprosił o wydrukowaniu wyniku na konsoli, w którym to przypadku nie jest wymagana interpretacja HTML.)

 26
Author: Søren Løvborg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-09 13:29:22

Dlaczego wszyscy robicie to w trudny sposób? Możesz użyć funkcji 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)
 22
Author: Aminah Nuraini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-08 16:31:12

Jest na to prosty sposób:

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

Idea jest wyjaśniona tutaj: http://youtu.be/2tu9LTDujbw

Możesz zobaczyć to działa tutaj: http://youtu.be/HPkNPcYed9M?t=35s

PS-Jeśli interesuje Cię Klasa (o inteligentnym debugowaniu w Pythonie) podaję ci link: http://www.udacity.com/overview/Course/cs259/CourseRev/1 . to za darmo!

Nie ma za co! :)
 17
Author: Medeiros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-22 17:27:41

Jeśli chcesz zachować encje HTML (np. &amp;), dodałem metodę "handle_entityref" do odpowiedzi Eloffa.

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()
 16
Author: Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

Jeśli chcesz usunąć wszystkie znaczniki HTML najprostszym sposobem, jaki znalazłem, jest użycie 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)) 

Próbowałem kodu zaakceptowanej odpowiedzi, ale otrzymywałem "RuntimeError: maximum recursion depth exceeded", co nie stało się z powyższym blokiem kodu.

 12
Author: Vasilis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-21 14:11:27

An lxml.rozwiązanie oparte na html (lxml jest natywną biblioteką, a więc znacznie szybsze niż jakiekolwiek czyste rozwiązanie Pythona).

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

Zobacz też http://lxml.de/lxmlhtml.html#cleaning-up-html Po co dokładnie lxml.czyściciel ma.

Jeśli potrzebujesz większej kontroli nad tym, co dokładnie jest dezynfekowane przed konwersją na tekst, możesz użyć lxml Cleaner jawnie przekazując opcje, które chcesz w konstruktorze, np.:

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)
 9
Author: ccpizza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-11 06:33:34

Piękne opakowanie zupy robi to natychmiast za Ciebie.

from bs4 import BeautifulSoup

soup = BeautifulSoup(html)
text = soup.get_text()
print(text)
 5
Author: runawaykid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-25 07:35:13

Możesz użyć innego parsera HTML (Jak lxml, lub Beautiful Soup ) -- takiego, który oferuje funkcje do wyodrębniania tylko tekstu. Możesz też uruchomić Wyrażenie regularne na łańcuchu linii, który usuwa znaczniki. Zobacz http://www.amk.ca/python/howto/regex / Po Więcej.

 2
Author: Jason Coon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-29 00:50:07

Korzystałem z odpowiedzi Eloffa pomyślnie dla Pythona 3.1 [Wielkie dzięki!].

Uaktualniłem do Pythona 3.2.3 i napotkałem błędy.

Rozwiązaniem, podanym tutaj dzięki odpowiadającemu Tomaszowi K, jest wstawienie super().__init__() do następującego kodu:

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

... aby wyglądało to tak:

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

... i będzie działać dla Pythona 3.2.3.

Jeszcze raz dziękuję Thomasowi K za poprawkę i oryginalny kod eloffa podany powyżej!

 1
Author: MilesNielsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:48

Rozwiązania z PARSEREM HTML są łamliwe, jeśli działają tylko raz:

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

Wyniki w:

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

Co zamierzasz zapobiec. jeśli używasz HTML-parsera, policz znaczniki do zera:

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
 1
Author: user3232060,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-24 12:58:15

Jest to szybka poprawka i może być jeszcze bardziej zoptymalizowana, ale będzie działać dobrze. Ten kod zastąpi wszystkie niepuste znaczniki "" i usunie wszystkie znaczniki html z danego tekstu wejściowego .Możesz go uruchomić za pomocą ./file.py input output

    #!/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"
 1
Author: kiran Mohan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-07 03:51:25

Adaptacja Pythona 3 odpowiedzi søren-løvborga

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()
 1
Author: CpILL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-16 08:02:16

Do jednego projektu potrzebowałem więc strip HTML, ale także css i js. Tak więc zrobiłem odmianę odpowiedzi Eloffa:

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()
 1
Author: mousetail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-15 12:52:41

Możesz napisać własną funkcję:

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
 0
Author: Yuda Prawira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-20 21:39:52

Parsuję Github readmes i uważam, że następujące rzeczy naprawdę działają dobrze:

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 ''

A następnie

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))

Usuwa wszystkie znaczniki markdown i html poprawnie.

 0
Author: PascalVKooten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-02 10:10:52

Używając BeautifulSoup, html2text lub kodu z @Eloff, większość czasu pozostaje elementami html, kodem javascript...

Więc możesz użyć kombinacji tych bibliotek i usunąć formatowanie markdown (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
Dla mnie działa dobrze, ale można go oczywiście ulepszyć...
 0
Author: hayj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-27 14:41:49

Ta metoda działa dla mnie bezbłędnie i nie wymaga żadnych dodatkowych instalacji:

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).
 -1
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-02 01:23:05