Python BeautifulSoup从find_all()返回错误的输入列表

时间:2017-04-07 20:23:54

标签: python html beautifulsoup

我有Python 2.7.3和bs。版本是4.4.1

由于某种原因,此代码

from bs4 import BeautifulSoup # parsing

html = """
<html>
<head id="Head1"><title>Title</title></head>
<body>
    <form id="form" action="login.php" method="post">
        <input type="text" name="fname">
        <input type="text" name="email" >
        <input type="button" name="Submit" value="submit">
    </form>
</body>

</html>
"""

html_proc = BeautifulSoup(html, 'html.parser')

for form in  html_proc.find_all('form'):
    for input in form.find_all('input'):
        print "input:" + str(input)

返回错误的输入列表:

input:<input name="fname" type="text">
<input name="email" type="text">
<input name="Submit" type="button" value="submit">
</input></input></input>
input:<input name="email" type="text">
<input name="Submit" type="button" value="submit">
</input></input>
input:<input name="Submit" type="button" value="submit">
</input>

它应该返回

input: <input name="fname" type="text">
input: <input type="text" name="email">
input: <input type="button" name="Submit" value="submit">

发生什么事了?

2 个答案:

答案 0 :(得分:2)

对我而言,这看起来像是html解析器的工件。将'lxml'用于解析器而不是'html.parser'似乎可以使其正常工作。这样做的缺点是您(或您的用户)需要安装lxml - 好处是lxml是更好/更快的解析器; - )。

至于为什么 'html.parser'在这种情况下似乎无法正常工作,我认为它与input标签是自我的事实有关-closing。如果明确关闭输入,则可以正常工作:

<input type="text" name="fname" ></input>
<input type="text" name="email" ></input>
<input type="button" name="Submit" value="submit" ></input>

我很想知道我们是否可以修改源代码来处理这种情况......对猴子补丁bs4做一点实验表明我们可以这样做:

from bs4 import BeautifulSoup

from bs4.builder import _htmlparser

# Monkey-patch the Beautiful soup HTML parser to close input tags automatically.
BeautifulSoupHTMLParser = _htmlparser.BeautifulSoupHTMLParser
class FixedParser(BeautifulSoupHTMLParser):
    def handle_starttag(self, name, attrs):
        # Old-style class... No super :-(
        result = BeautifulSoupHTMLParser.handle_starttag(self, name, attrs)
        if name.lower() == 'input':
            self.handle_endtag(name)
        return result

_htmlparser.BeautifulSoupHTMLParser = FixedParser


html = """
<html>
<head id="Head1"><title>Title</title></head>
<body>
    <form id="form" action="login.php" method="post">
        <input type="text" name="fname" >
        <input type="text" name="email" >
        <input type="button" name="Submit" value="submit" >
    </form>
</body>

</html>
"""

html_proc = BeautifulSoup(html, 'html.parser')

for form in  html_proc.find_all('form'):
    for input in form.find_all('input'):
        print "input:" + str(input)

显然,这不是真正的修复(我不会将其作为补丁提交给BS4人员),但它确实证明了这个问题。由于没有结束标记,因此永远不会调用handle_endtag方法。如果我们自己调用它,事情往往会解决(只要html不 也有关闭输入标记......)。

我不确定这个bug的责任应该是什么,但我想你可以先将它提交给bs4 - 然后他们可能会转发你报告python跟踪器上的错误,我&#39 ;我不确定......

答案 1 :(得分:0)

不要使用嵌套循环并使用lxml,将代码更改为:

inp = []
html_proc = BeautifulSoup(html, 'lxml')

for form in  html_proc.find_all('form'):
    inp.extend(form.find_all('input'))

for item in inp:    
    print "input:" + str(item)