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

当在HTML文件中打印一行时,我试图找到一种方法,只显示每个HTML元素的内容,而不是格式本身。如果它发现'<a href="等等。例如">some text</a>',它只会打印'some text', '<b>hello</b>'打印'hello',等等。该怎么做呢?


当前回答

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

这对我来说很有效,但当然还可以增强……

其他回答

基于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. xml的具体内容。清洁。

如果你需要更多的控制哪些特定的标签应该在转换为文本之前删除,然后创建一个自定义的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)

要自定义如何生成纯文本,您可以使用lxml.etree.tostring而不是text_content():

from lxml.etree import tostring

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

你可以使用BeautifulSoup get_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"),以便输出可重现。

你可以编写自己的函数:

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

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

import re

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

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

如果非标签<出现在html(例如。2 < 3),它应该被写成转义序列&…总之,^<可能是不必要的。

短版!

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)

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

为什么我不能把标签撕掉,然后留下?

这是一件事,让人们远离<i>斜体</i>的东西,而不留下浮动。但任意输入并使其完全无害是另一回事。本页上的大多数技术都将保留未关闭的注释(<!——)和不是标签一部分的尖括号(blah <<<><blah)。HTMLParser版本甚至可以保留完整的标记,如果它们在未关闭的注释中。

如果你的模板是{{firstname}} {{lastname}}呢?Firstname = '<a' and lastname = 'href="http://evil。example/">'将被该页上的每个标签剥离器通过(除了@Medeiros!),因为它们本身不是完整的标签。除去普通的HTML标记是不够的。

Django的strip_tags是这个问题顶部答案的改进版本(见下一个标题),给出了以下警告:

绝对不能保证得到的字符串是HTML安全的。因此,永远不要在没有转义的情况下将strip_tags调用的结果标记为安全,例如使用escape()。

听从他们的建议!

要用HTMLParser去除标签,你必须运行它多次。

绕过这个问题最上面的答案很容易。

看看这个字符串(来源和讨论):

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

HTMLParser第一次看到它时,它不能告诉<img…>是一个标签。它看起来坏了,所以HTMLParser不会去掉它。它只去掉<!——评论——>,留给你

<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版本)。它包含在谷歌应用程序引擎中,并被Jinja2(2.7及以上),Mako, Pylons等使用。它可以很容易地与Django 1.7的模板一起工作。

Django最新版本的strip_tags和其他HTML实用程序都不错,但我发现它们不如MarkupSafe方便。它们非常独立,你可以从这个文件中复制你需要的东西。

如果你需要去除几乎所有的标签,Bleach库是很好的选择。你可以让它强制执行这样的规则:“我的用户可以用斜体,但他们不能创建iframe。”

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

这个问题本身是关于打印到控制台的,但这是“python从字符串中剥离HTML”的排名第一的谷歌结果,所以这就是为什么这个答案99%是关于web的。