模式Web无法通过类名称找到元素

时间:2018-09-25 01:17:23

标签: python python-pattern

我正在尝试通过类名称标识DOM元素,但是我无法按照in the docs所述使用pattern.web(我也正在运行以前使用的代码,因此确实有工作)。

from pattern.web import DOM

html = """<html><head><title>pattern.web | CLiPS</title></head>
<body>
  <div class="class1 class2 class3">
    <form action="/pages/pattern-web"  accept-charset="UTF-8" method="post" id="search-block-form">
      <div>
        <label for="edit-search-block-form-1">Search this site: </label>
      </div>
    </form>
  </div>
</body></html>"""

dom = DOM(html)
print "Search Results by Method:"
print 'tag[attr="value"] Notation Results:'
print dom('div[class="class1 class2 class3"]')
print 
print 'tag.class Notation Results:'
print dom('div.class1')
print
print 'By class, no tag results:'
print dom.by_class('class1')
print 
print 'Looping through all divs and printing matching results:'
for i in dom('div'):
    if 'class' in i.attrs and i.attrs['class'] == 'class1 class2 class3':
        print i.attrs

请注意(ElementDOM函数是可互换的,并且给出相同的结果)。结果是这样的:

Search Results by Method:
tag[attr="value"] Notation Results:
[]

tag.class Notation Results:
[]

By class, no tag results:
[Element(tag='div')]

Looping through all divs and printing matching results:
{u'class': u'class1 class2 class3'}

如您所见,使用tag.class表示法和tag[attr="value"]表示法查找结果都是空的,但是by_class返回一个结果。显然,具有那些属性的元素存在。如何搜索具有全部3个类的所有div?

过去,我可以使用dom('div.class1.class2.class3')进行搜索,以识别所有3个类的div。这不仅行不通,而且还给我unicode错误(似乎第二个句点导致unicode错误):TypeError: descriptor 'lower' requires a 'str' object but received a 'unicode'

1 个答案:

答案 0 :(得分:0)

  

问题:过去,我可以使用dom('div.class1.class2.class3')进行搜索,以识别所有3个类的div。


  

阅读源代码github.com/clips/pattern/blob/master/pattern/web
  发现,它只是使用Beautiful Soup的包装器。

     
    

#Beautiful Soup被包装在DOM,Element和Text类中,类似于Javascript DOM。
    #美丽汤也可以直接使用

  

  

这是一个已知问题,请参见:   Beautiful soup find_all doesn't find CSS selector with multiple classes

解决方法是使用.select(...)代替.find_all(...)
.select(...)

中找不到pattern.web

例如:

from bs4 import BeautifulSoup

html = """<html><head><title>pattern.web | CLiPS</title></head>
  <body>
    <div class="class1 class4">
      <form action="/pages/pattern-web"  accept-charset="UTF-8" method="post" id="search-block-form">
        <div class="class1 class2 class3">
          <label for="edit-search-block-form-1">Search this site: </label>
        </div>
      </form>
    </div>
</body></html>
"""
soup = BeautifulSoup(html, 'html.parser')
div = soup.select('div.class1.class2')
print("{}".format(div))
  

输出

[<div class="class1 class2 class3">
<label for="edit-search-block-form-1">Search this site: </label>
</div>]

  

问题:这也给了我Unicode错误(似乎第二个句点引起了Unicode错误):

TypeError: descriptor 'lower' requires a 'str' object but received a 'unicode'

TypeError来自pattern.web还是Beautiful Soup,是未知的。
根据此SO:descriptor-join-requires-a-unicode-object-but-received-a-str,这是一条标准的Python消息。


使用来自GitHub的pattern.web,结果符合预期:

from pattern.web import Element

elements = Element(html)
print("Search Results by Method:")
print('tag[attr="value"] Notation\tResults:{}'
    .format(elements('div[class="class1 class2 class3"]')))

print('tag.class Notation \t\t\tResults:{}'
    .format(elements('div.class1.class2.class3')))

print('By class, no tag \t\t\tResults:{}'
    .format(elements.by_class('class1 class2 class3')))

print('Looping through all divs and printing matching results:')
for i in elements('div'):
    if 'class' in i.attrs:
        if " ".join(i.attrs['class']) == 'class1 class2 class3':
            print("\tmatch:{}".format(i.attrs))
  

输出

Search Results by Method:
tag[attr="value"] Notation  Results:{'class': ['class1', 'class2', 'class3']}
tag.class Notation          Results:{'class': ['class1', 'class2', 'class3']}
By class, no tag            Results:{'class': ['class1', 'class2', 'class3']}
Looping through all divs and printing matching results:
    match:{'class': ['class1', 'class2', 'class3']}

使用Python:3.5.3-pattern.web:3.6-bs4:4.5.3

进行了测试