使用 Python 从字符串中去除 HTML

2024-12-06 08:39:00
admin
原创
97
摘要:问题描述:from mechanize import Browser br = Browser() br.open('http://somewebpage') html = br.response().readlines() for line in html: print line 在 HTML 文件中打...

问题描述:

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.example">some text</a>',它将仅打印“一些文本”,'<b>hello</b>'打印“你好”等。如何做到这一点?


解决方案 1:

我总是使用这个函数来删除 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()

解决方案 2:

如果您需要删除 HTML 标签以进行文本处理,那么一个简单的正则表达式就可以了。如果您希望清理用户生成的 HTML 以防止 XSS 攻击,请不要使用此方法。这不是删除所有<script>标签或跟踪的安全方法<img>以下正则表达式将相当可靠地删除大多数 HTML 标签:

import re

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

对于那些不懂正则表达式的人来说,这会搜索一个字符串<...>,其中内部内容由一个或多个+不是 的 ( ) 字符组成<。这?意味着它将匹配它能找到的最小字符串。例如,给定<p>Hello</p>,它将分别匹配 和<'p>。如果没有它,它将匹配整个字符串。</p>`?`<..Hello..>

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

解决方案 3:

您可以使用BeautifulSoupget_text()功能。

from bs4 import BeautifulSoup

html_str = '''
<td><a href="http://www.fakewebsite.example">Please can you strip me?</a>
<br/><a href="http://www.fakewebsite.example">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"),以使输出可重现。

解决方案 4:

简短版本!

import re, html
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 = html.escape(no_tags)

正则表达式来源:MarkupSafe。他们的版本也处理 HTML 实体,而这个快速版本则不能。

为什么我不能直接剥掉标签然后不管它呢?

<i>italicizing</i>阻止人们接触事物而不让s 四处飘荡是一回事i。但接受任意输入并使其完全无害则是另一回事。本页上的大多数技术都会保留未关闭的注释 ( <!--) 和不属于标签一部分的尖括号 ( blah <<<><blah) 等内容。如果它们位于未关闭的注释内,HTMLParser 版本甚至可以保留完整的标签。

如果您的模板是{{ firstname }} {{ lastname }}?,firstname = '<a'并且lastname = 'href="http://evil.example/">'将被此页面上的每个标签剥离器(@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 打包版本可以处理。

我的示例代码取自用于跨站点脚本预防的优秀MarkupSafe库。它方便快捷(C 语言速度比其原生 Python 版本快)。它包含在Google App Engine中,并被Jinja2(2.7 及更高版本) 、Mako、Pylons 等使用。它可轻松与 Django 1.7 中的 Django 模板配合使用。

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

如果您需要删除几乎所有标签,Bleach库就很不错。您可以让它强制执行规则,例如“我的用户可以将内容斜体化,但不能创建 iframe。”

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

羞怯的注释-问题本身是关于打印到控制台,但这是“python 从字符串中剥离 HTML”的 Google 搜索结果中的最佳结果,所以这就是为什么这个答案 99% 是关于网络的。

解决方案 5:

我需要一种方法来删除标签并将HTML 实体解码为纯文本。以下解决方案基于 Eloff 的答案(我无法使用它,因为它会删除实体)。

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 '

    Named entities are handled as per HTML 5.
    >>> html_to_text('&nosuchentity; &apos; ')
    "&nosuchentity; ' "
    """
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

快速测试:

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

结果:

'Demo (¬ Δημώ)'

安全注意事项:不要将 HTML剥离(将 HTML 转换为纯文本)与 HTML清理(将纯文本转换为 HTML)相混淆。此答案将删除 HTML 并将实体解码为纯文本 - 这不会使结果在 HTML 上下文中安全使用。

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

规则并不难:任何时候将纯文本字符串插入 HTML 输出时,总是使用HTML 转义它(使用html.escape(s)),即使您“知道”它不包含 HTML(例如,因为您剥离了 HTML 内容)。

但是,OP 询问是否将结果打印到控制台,在这种情况下不需要 HTML 转义。相反,您可能需要删除 ASCII 控制字符,因为它们可能会触发不必要的行为(尤其是在 Unix 系统上):

import re
text = html_to_text(untrusted_html_input)
clean_text = re.sub(r'[-x1fx7f]+', '', text)
# Alternatively, if you want to allow newlines:
# clean_text = re.sub(r'[-x09x0b-x1fx7f]+', '', text)
print(clean_text)

解决方案 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:

基于lxml.html的解决方案(lxml 是一个本机库,其性能比纯 python 解决方案更高)。

要安装lxml模块,请使用pip install lxml

删除所有标签


from lxml import html


## from file-like object or URL
tree = html.parse(file_like_object_or_url)

## from string
tree = html.fromstring('safe <script>unsafe</script> safe')

print(tree.text_content().strip())

### OUTPUT: 'safe unsafe safe'

使用预先清理的 HTML 删除所有标签(删除一些标签)

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

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

## text only
print(clean_html(tree).text_content().strip())

### OUTPUT: 'Detailed answers to any questions you might have'

另请参阅http://lxml.de/lxmlhtml.html#cleaning-up-html了解 lxml.cleaner 的具体功能。

如果您需要更好地控制在转换为文本之前应删除哪些特定标签,那么可以使用所需选项创建自定义lxml Cleaner,例如:

from lxml.html.clean import 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)

要自定义纯文本的生成方式,您可以lxml.etree.tostring使用text_content()

from lxml.etree import tostring

print(tostring(tree, method='text', encoding=str))

解决方案 8:

这是一个简单的解决方案,它基于速度惊人的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.

解决方案 9:

如果您需要保留 HTML 实体(即&amp;),我在Eloff 的答案中添加了“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()

解决方案 10:

如果你想删除所有 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:超出最大递归深度”的错误,而上面的代码块并没有发生这种情况。

解决方案 11:

Beautiful Soup 套餐可以立即为您完成此操作。

from bs4 import BeautifulSoup

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

解决方案 12:

这是一个与当前接受的答案(https://stackoverflow.com/a/925630/95989)类似的解决方案,不同之处在于它直接使用内部HTMLParser类(即没有子类化),从而使其更加简洁:

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

解决方案 13:

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

不确定它是否完美,但解决了我的用例并且看起来很简单。

解决方案 14:

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

解决方案 15:

您可以使用不同的 HTML 解析器(例如 lxml或Beautiful Soup)——提供仅提取文本的功能。或者,您可以在行字符串上运行正则表达式以删除标签。有关更多信息,请参阅Python 文档。

解决方案 16:

2020 年更新

使用Mozilla Bleach 库,它确实可以让您自定义要保留的标签和要保留的属性,还可以根据值过滤掉属性

以下举两个例子来说明

1)不允许任何 HTML 标签或属性

获取样本原始文本

raw_text = """
<p><img width="696" height="392" src="https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-768x432.jpg" class="attachment-medium_large size-medium_large wp-post-image" alt="Ethereum Classic 51% Attack: Okex Crypto Exchange Suffers $5.6 Million Loss, Contemplates Delisting ETC" style="float:left; margin:0 15px 15px 0;" srcset="https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-768x432.jpg 768w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-300x169.jpg 300w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-1024x576.jpg 1024w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-696x392.jpg 696w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-1068x601.jpg 1068w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-747x420.jpg 747w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-190x107.jpg 190w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-380x214.jpg 380w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-760x428.jpg 760w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc.jpg 1280w" sizes="(max-width: 696px) 100vw, 696px" />Cryptocurrency exchange Okex reveals it suffered the $5.6 million loss as a result of the double-spend carried out by the attacker(s) in Ethereum Classic 51% attack. Okex says it fully absorbed the loss as per its user-protection policy while insisting that the attack did not cause any loss to the platform&#8217;s users. Also as part [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://news.bitcoin.com/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc/">Ethereum Classic 51% Attack: Okex Crypto Exchange Suffers $5.6 Million Loss, Contemplates Delisting ETC</a> appeared first on <a rel="nofollow" href="https://news.bitcoin.com">Bitcoin News</a>.</p> 
"""

2)从原始文本中删除所有 HTML 标签和属性

# DO NOT ALLOW any tags or any attributes
from bleach.sanitizer import Cleaner
cleaner = Cleaner(tags=[], attributes={}, styles=[], protocols=[], strip=True, strip_comments=True, filters=None)
print(cleaner.clean(raw_text))

输出

Cryptocurrency exchange Okex reveals it suffered the $5.6 million loss as a result of the double-spend carried out by the attacker(s) in Ethereum Classic 51% attack. Okex says it fully absorbed the loss as per its user-protection policy while insisting that the attack did not cause any loss to the platform&#8217;s users. Also as part [&#8230;]
The post Ethereum Classic 51% Attack: Okex Crypto Exchange Suffers $5.6 Million Loss, Contemplates Delisting ETC appeared first on Bitcoin News. 

3 仅允许带有 srcset 属性的 img 标签

from bleach.sanitizer import Cleaner
# ALLOW ONLY img tags with src attribute
cleaner = Cleaner(tags=['img'], attributes={'img': ['srcset']}, styles=[], protocols=[], strip=True, strip_comments=True, filters=None)
print(cleaner.clean(raw_text))

输出

<img srcset="https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-768x432.jpg 768w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-300x169.jpg 300w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-1024x576.jpg 1024w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-696x392.jpg 696w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-1068x601.jpg 1068w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-747x420.jpg 747w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-190x107.jpg 190w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-380x214.jpg 380w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc-760x428.jpg 760w, https://news.bitcoin.com/wp-content/uploads/2020/08/ethereum-classic-51-attack-okex-crypto-exchange-suffers-5-6-million-loss-contemplates-delisting-etc.jpg 1280w">Cryptocurrency exchange Okex reveals it suffered the $5.6 million loss as a result of the double-spend carried out by the attacker(s) in Ethereum Classic 51% attack. Okex says it fully absorbed the loss as per its user-protection policy while insisting that the attack did not cause any loss to the platform&#8217;s users. Also as part [&#8230;]
The post Ethereum Classic 51% Attack: Okex Crypto Exchange Suffers $5.6 Million Loss, Contemplates Delisting ETC appeared first on Bitcoin News. 

解决方案 17:

我已经成功地将 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 的原始代码!

解决方案 18:

如果只运行一次,使用 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

解决方案 19:

这是一个快速修复,可以进一步优化,但效果很好。此代码将用“”替换所有非空标签,并从给定的输入文本中删除所有 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"

解决方案 20:

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

解决方案 21:

你可以编写自己的函数:

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

解决方案 22:

我正在解析 Github readme,发现以下内容确实很有效:

import re
import lxml.html

def strip_markdown(x):
    links_sub = re.sub(r'[(.+)]([^)]+)', r'', x)
    bold_sub = re.sub(r'**([^*]+)**', r'', links_sub)
    emph_sub = re.sub(r'*([^*]+)*', r'', 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。

解决方案 23:

使用 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

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

解决方案 24:

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

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

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

解决方案 25:

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

  return innerText.strip()

解决方案 26:

这是我的做法,但我不知道我在做什么。我通过删除 HTML 标签从 HTML 表中获取数据。

这将获取字符串“name”并返回不带 HTML 标签的字符串“name1”。

x = 0
anglebrackets = 0
name1 = ""
while x < len(name):
    
    if name[x] == "<":
        anglebrackets = anglebrackets + 1
    if name[x] == ">":
        anglebrackets = anglebrackets - 1
    if anglebrackets == 0:
        if name[x] != ">":
            name1 = name1 + name[x]
    x = x + 1

解决方案 27:

import re

def remove(text):
    clean = re.compile('<.*?>')
    return re.sub(clean, '', text)

解决方案 28:

nh3也应该有效:

>>> import nh3
>>> print(nh3.clean("<s><b>text</s></b>", tags={"b"}))
<b>text</b>
>>> print(nh3.clean("<s><b>text</s></b>", tags=set()))
text

性能应该不错,因为它是 rust 库的包装器

解决方案 29:

这种方法对我来说非常完美,并且不需要额外的安装:

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).
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1008  
  在项目管理中,变更是一个不可避免的现象。无论是客户需求的调整、市场环境的变化,还是技术方案的更新,都可能引发项目的变更。如果处理不当,这些变更可能会导致项目延期、成本超支,甚至项目失败。因此,如何有效地应对项目变更,成为项目管理中的核心挑战之一。IPD(集成产品开发)作为一种高效的项目管理方法,其流程图不仅能够帮助团队...
IPD流程中的charter   0  
  IPD(Integrated Product Development,集成产品开发)是华为在长期实践中总结出的一套高效产品开发管理体系。它不仅帮助华为在全球市场中脱颖而出,也成为许多企业提升产品开发效率的参考标杆。IPD的核心在于通过跨部门协作、流程优化和资源整合,实现从需求分析到产品交付的全生命周期管理。通过实施IP...
IPD开发流程管理   0  
  华为IPD(集成产品开发)流程是一种以客户需求为导向、跨部门协同的高效项目管理方法。它通过系统化的流程设计和严格的阶段控制,确保项目从概念到交付的每个环节都能高效运作。IPD流程的核心在于打破传统职能部门的壁垒,将产品开发、市场、销售、供应链等关键环节整合到一个统一的框架中,从而实现资源的优化配置和信息的无缝流动。这种...
IPD流程中TR   0  
  在项目管理的实践中,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节。通过这一评审,项目团队不仅能够验证其数据中心设计和运营的合规性,还能提升整体管理水平。为了确保评审的顺利进行,准备一系列关键文档是必不可少的。这些文档不仅是评审的依据,也是项目团队与评审专家...
华为IPD是什么   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用