在Python中从字符串中剥离HTML


268
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>'打印“ hello”,等等。如何做到这一点?


16
一个重要的考虑因素是如何处理HTML实体(例如&amp;)。您可以1)连同标签一起删除它们(通常是不希望的,并且不必要,因为它们等效于纯文本),2)保留它们不变(如果剥离的文本直接回到HTML上下文,这是一个合适的解决方案)或3 )将其解码为纯文本(如果剥离的文本进入数据库或其他非HTML上下文,或者您的网络框架自动为您执行HTML文本转义)。
索伦Løvborg


2
上面的答案一直被 Django项目使用,直到2014年3月为止,但发现它对跨站点脚本是不安全的-请参阅该链接以了解实现该示例的示例。我建议使用Bleach.clean(),Markupsafe的striptags或RECENT Django的strip_tags。
rescdsk 2014年

Answers:


418

我一直使用此函数来剥离HTML标记,因为它仅需要Python stdlib:

对于Python 3:

from io import StringIO
from html.parser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        super().__init__()
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.text = StringIO()
    def handle_data(self, d):
        self.text.write(d)
    def get_data(self):
        return self.text.getvalue()

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

对于Python 2:

from HTMLParser import HTMLParser
from StringIO import StringIO

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.text = StringIO()
    def handle_data(self, d):
        self.text.write(d)
    def get_data(self):
        return self.text.getvalue()

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

3
两年多以后,面对相同的问题,这是一个更为优雅的解决方案。我所做的唯一更改是将self.fed作为列表返回,而不是加入列表,因此我可以逐步浏览元素内容。
指令

47
请注意,这会剥离HTML实体(例如&amp;)和标签。
索伦Løvborg

30
@surya我确定您已经看到了
tkone 2012年

8
感谢您的出色回答。使用较新版本的Python(3.2+)的用户要注意的一件事是,您需要调用父类的__init__函数。看到这里:stackoverflow.com/questions/11061058/…

10
为了保留html实体(转换为unicode),我在strip_tags函数的开头添加了两行:parser = HTMLParser()html = parser.unescape(html)
James Doepp-pihentagyu 2015年

156

我没有想太多会丢失的情况,但是您可以做一个简单的正则表达式:

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

对于不了解正则表达式的用户,这会搜索一个字符串<...>,其内部内容由一个或多个(+)而不是的字符组成<。该?意味着它会匹配它所能找到的最小字符串。例如<p>Hello</p>,它将与匹配<'p></p>分开?。没有它,它将匹配整个字符串<..Hello..>

如果非标记<出现在html中(例如2 < 3),则&...无论如何都应将其标记为转义序列,因此^<可能不必要。


10
这几乎就是Django的strip_tags的工作方式。
2011年

10
请注意,这会使HTML实体(例如&amp;)在输出中保持不变。
索伦Løvborg

35
仍然可以使用以下方法欺骗这种方法:<script <script >> alert(“ Hi!”)<< / script> / script>

19
不要这样做!正如@Julio Garcia所说,这并不安全!
rescdsk 2013年

18
人们,不要混淆HTML剥离和HTML清理。是的,对于损坏或恶意的输入,此答案可能会产生带有HTML标记的输出。剥离HTML标记仍然是一种非常有效的方法。但是,剥离HTML标记不是正确的HTML清理的有效替代。规则并不难:每当您在HTML输出中插入纯文本字符串时,即使您“知道”它不包含HTML(例如,因为剥离了HTML内容),也应始终使用()使用HTML转义它。cgi.escape(s, True)。但是,这不是OP要求的。
索伦Løvborg

76

您可以使用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)

建议明确指定解析器(例如)BeautifulSoup(html_str, features="html.parser"),以使输出可再现。


32

精简版!

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

该问题已在2014年3月的Django项目中披露。他们的旧时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()

2015年3月19日更新:1.4.20、1.6.11、1.7.7和1.8c1之前的Django版本中存在错误。这些版本可能会在strip_tags()函数中进入无限循环。固定版本如上复制。 更多细节在这里

复制或使用好东西

我的示例代码无法处理HTML实体-Django和MarkupSafe打包版本可以处理HTML实体。

我的示例代码是从出色的MarkupSafe库中提取的,以防止跨站点脚本编写。它既方便又快速(C加速到其本机Python版本)。它包含在Google App Engine中,并由Jinja2(2.7及更高版本),Mako,Pylons等使用。它可以轻松地与Django 1.7中的Django模板一起使用。

Django的strip_tags和最新版本的其他html实用程序都不错,但是我发现它们不如MarkupSafe方便。它们非常独立,您可以从此文件中复制所需内容。

如果您需要剥离几乎所有标签,则Bleach库很好。您可以让它强制执行诸如“我的用户可以将其斜体显示,但他们不能创建iframe”之类的规则。

了解标签剥离器的属性!对它进行模糊测试! 这是我用来对此答案进行研究的代码

令人毛骨悚然的注释 -问题本身是关于打印到控制台的问题,但这是Google针对“从字符串中提取python剥离html”的最高结果,所以这就是为什么网上答案是99%。


我的“备用最后一行”示例代码无法处理html实体-那有多糟?
rescdsk

我只解析一小段没有特殊标记的html,而您的简短版本做得很好。感谢分享!
tbolender

31

我需要一种剥离标签并将 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异常。
  • 指定代码点超出Python可接受的Unicode范围的数字HTML实体(例如,在某些系统上,基本多语言平面之外的字符)将导致ValueError异常。

安全说明:不要将HTML剥离(将HTML转换为纯文本)与HTML清理(将纯文本转换为HTML)混淆。此答案将删除HTML并将实体解码为纯文本-这不能确保在HTML上下文中安全使用结果。

示例:&lt;script&gt;alert("Hello");&lt;/script&gt;将转换为<script>alert("Hello");</script>,这是100%正确的行为,但是如果将生成的纯文本原样插入HTML页面,则显然不够。

规则并不难:每当您在HTML输出中插入纯文本字符串时,即使您“知道”它不包含HTML(例如,因为剥离了HTML内容),也应始终使用()使用HTML转义它。cgi.escape(s, True)

(但是,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中得到了改进(意味着更少的代码和更好的错误处理)。


18

有一个简单的方法:

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。免费!

别客气!:)


2
我不知道为什么这个答案被否决了。这是没有任何lib即可解决问题的简单方法。只是纯python,它的工作原理如链接所示。
Medeiros

2
人们可能更喜欢库来给他们安全。我对您的代码进行了测试并通过了测试,并且我总是更喜欢能理解的小代码,而不是使用lib并假设在出现错误之前它是可以的。对我来说,这就是我一直在寻找的东西,再次感谢。关于低票,不要陷入那种思维定势。这里的人们应该关心质量而不是选票。最近,SO已成为每个人都想表达而不是了解知识的地方。
2013年

2
该解决方案的问题是错误处理。例如,如果您提供<b class="o'>x</b>输入功能输出x。但实际上此输入无效。我认为这就是人们喜欢libs的原因。
laltin13年

1
它也适用于该输入。刚刚测试。只要意识到,在这些库中您会找到类似的代码。我知道这不是很pythonic。看起来像C或Java代码。我认为这是有效的,可以轻松移植到另一种语言。
Medeiros 2013年

1
简单,Python式,似乎比讨论的任何其他方法都好或更好。它可能不适用于某些格式错误的HTML,但是并不能克服这一点。
denson

16

如果您需要保留HTML实体(即&amp;),则在Eloff的answer中添加了“ handle_entityref ”方法。

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

13

如果要剥离所有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:超出最大递归深度”,上述代码块未发生这种情况。


1
我只是尝试了您的方法,因为它看起来更干净,更有效,有点...没有剥离输入标签!
kustomrtr

我发现BeautifulSoup的一个简单应用程序存在空格问题:''.join(BeautifulSoup('<em>he</em>llo<br>world').find_all(text=True))。这里的输出是“ helloworld”,而您可能希望它是“ hello world”。' '.join(BeautifulSoup('<em>he</em>llo<br>world').find_all(text=True))变成“自己的世界”无济于事。
FinnÅrupNielsen 2014年

@kustomrtr,对不起我的无知,我对自我论点有什么看法?NameError:名称“ self”未定义
Ian_De_Oliveira

@Ian_De_Oliveira您可以将其删除,我假设它在一个类内,但不需要。我也编辑了答案以删除它
Vasilis '18

@Ian_De_Oliveira您可以将其删除,我假设它在一个类内,但不需要。我也编辑了答案以删除它
Vasilis '18

9

一个基于lxml.html的解决方案(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)

1
我得到了AttributeError:'HtmlElement'对象没有属性'
strip'– aris

9

这是一个简单的解决方案,它基于惊人的快速lxml库剥离HTML标签并解码HTML实体:

from lxml import html

def strip_html(s):
    return str(html.fromstring(s).text_content())

strip_html('Ein <a href="">sch&ouml;ner</a> Text.')  # Output: Ein schöner Text.

3
截至2020年,这是剥离HTML内容的最快,最好的方法。加上处理解码的好处。非常适合语言检测!
dfabiano

text_content()返回,lxml.etree._ElementUnicodeResult因此您可能必须先将其转换为字符串
Suzana

1
@Suzana好点。它似乎已自动广播到str诸如+indexing的字符串操作[]。无论如何添加了一个很好的演员表。
罗宾·丁斯

7

Beautiful Soup包会立即为您执行此操作。

from bs4 import BeautifulSoup

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

3
在审核队列中:我可以要求您在答案周围添加更多背景信息。仅代码的答案很难理解。如果您可以在帖子中添加更多信息,它将对询问者和未来的读者都有帮助。
help-info.de

2

这是我对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

不知道它是否完美,但是解决了我的用例,看起来很简单。


2

您可以使用其他HTML解析器(例如lxmlBeautiful Soup),该解析器提供仅提取文本的功能。或者,您可以在行字符串上运行正则表达式以去除标记。有关更多信息,请参见Python文档


1
amk链接已死。有其他选择吗?

2
Python网站现在有不错的使用方法,这是regex的使用方法:docs.python.org/howto/regex
Jason Coon,2010年

5
在lxml中:lxml.html.fromstring(s).text_content()
2011年

1
Bluu使用lxml的示例将HTML实体(例如&amp;)解码为文本。
索伦Løvborg

1

我已经成功地将Eloff的答案用于Python 3.1 [非常感谢!]。

我升级到Python 3.2.3,并遇到错误。

感谢响应者Thomas K 提供的解决方案是将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原始代码!


1

您可以编写自己的函数:

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

1
追加到字符串是否会创建字符串的新副本?
杰里米L 2010年

1
@Nerdling -是它,这可能会导致在经常使用的功能有些让人印象非常深刻的低效(或,对于这个问题,不常用的功能是作用于文本的大斑点。)请参阅页面查看详细。:D
杰里米·桑德尔

是否针对带引号的字符串进行测试?号
吉米·凯恩

1

如果HTML-Parser的解决方案仅运行一次,则它们都是易碎的:

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

结果是:

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

您打算防止的事情。如果您使用HTML解析器,请对标签计数,直到替换为零为止:

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
如果您调用一个称为的函数,html_to_text并且将从该函数输出的文本嵌入到html中而不进行转义,那么缺少转义是安全漏洞,而不是html_to_text函数。该html_to_text函数从不向您保证输出将为文本。而且,无论您是从文本中获取文本html_to_text 还是从其他来源获取文本,都需要在不进行转义的情况下将文本插入html中,这是一个潜在的安全漏洞。
kasperd 2014年

在这种情况下,您是对的,没有逃脱,但问题是从给定的字符串中删除html而不逃脱给定的字符串。如果较早的答案由于删除了一些html而使用其解决方案构建了新的html,则使用此解决方案很危险。
Falk Nisius

1

这是一个快速修复,甚至可以进行优化,但是效果很好。这段代码将所有非空标签替换为“”,并将所有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"

1

søren-løvborg答案的python 3改编

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

对于一个项目,我需要剥离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()

1

这是一种与当前接受的答案(https://stackoverflow.com/a/925630/95989)类似的解决方案,除了它HTMLParser直接使用内部类(即没有子类),从而使其简洁得多:

def strip_html(文字):
    零件= []                                                                      
    解析器= HTMLParser()                                                           
    parser.handle_data = parts.append                                               
    parser.feed(文本)                                                               
    返回''.join(parts)

0

我正在解析Github自述文件,发现以下内容确实有效:

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

正确删除所有markdown和html。


0

大多数情况下,使用BeautifulSoup,html2text或@Eloff中的代码,它仍然保留一些html元素,javascript代码...

因此,您可以结合使用这些库并删除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

它对我来说效果很好,但是可以增强,当然...


0

简单的代码!这将删除其中的所有标记和内容。

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

但是,如果文本中包含<>符号,则不会给出完整的结果。


0
# This is a regex solution.
import re
def removeHtml(html):
  if not html: return html
  # Remove comments first
  innerText = re.compile('<!--[\s\S]*?-->').sub('',html)
  while innerText.find('>')>=0: # Loop through nested Tags
    text = re.compile('<[^<>]+?>').sub('',innerText)
    if text == innerText:
      break
    innerText = text

  return innerText.strip()

-2

此方法对我而言完美无缺,不需要其他安装:

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

3
这会将HTML实体解码为纯文本,但显然并没有剥离任何标签,这是最初的问题。(此外,第二个try-except块需要缩进以使代码执行同样的操作)。
索伦Løvborg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.