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',等等。该怎么做呢?


当前回答

如果你想去掉所有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:最大递归深度超出”,这没有发生在上面的代码块。

其他回答

这是一个快速修复,甚至可以更优化,但它将工作良好。这段代码将用""替换所有非空标记,并从给定的输入文本中剥离所有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"

短版!

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的。

如果你需要保留HTML实体(即&),我在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()

对于一个项目,我需要这样剥离HTML,但也css和js。因此,我对eloff的回答做了一个变化:

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

美丽的汤包立即为您做到这一点。

from bs4 import BeautifulSoup

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