之前介绍了有关的四个对象以及他们的属性, 但是一般情况下要在杂乱的html中提取我们所需的tag(tag中包含的信息)是比较复杂的, 现在我们可以来看看到底有些什么搜索的方法.
最主要的两个方法当然是find_all()和find(), 两者大致思路相同, 只不过一个前者返回符合条件的所有tags, 后者只返回一个tag. 我们先仔细看看find_all.
Signature: find_all(name, attrs, recursive, string, limit, **kwargs)
find_all()会自动寻找调用标签的所有子孙(文档中说的, 其实还包括自生)中符合条件的, 经过试验, 以下如果用正则表达式做过滤器那么都默认区别大小写...
第一个参数是name, 它指的其实是tag的name, 你可以传一个字符串, 那么他会寻找tag的名字等于该字符串的tag, 你也可以传一组字符串, 那么它会寻找符合其中任何一个字符串的tag; 你也可以传入一个函数, 但是这个函数必须只有一个唯一的一个参数tag, 同时返回值必须是True 或者 False, 然后所以结果为True的标签被选中, 甚至可以传正则表达式.
soup.find_all('b') # [<b>The Dormouse's story</b>] import re for tag in soup.find_all(re.compile("^b")): print(tag.name) # body # b soup.find_all(["a", "b"]) # [<b>The Dormouse's story</b>, # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] def has_class_but_no_id(tag): return tag.has_attr('class') and not tag.has_attr('id') soup.find_all(has_class_but_no_id) # [<p class="title"><b>The Dormouse's story</b></p>, # <p class="story">Once upon a time there were...</p>, # <p class="story">...</p>]
任何不被识别的参数都会被转化为对于tag的属性过滤器 (某些html5中的某些除外), 当然你也可以用字符串, 正则, 函数来过滤, 但是这里的函数必须要注意, 它的要求是唯一一个参数必须是你所要过滤的那个属性的值而不再是整个tag, 你也可以过滤tag的多个属性... 这就是所谓的keyword参数
1 soup.find_all(id='link2') 2 # [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] 3 4 soup.find_all(href=re.compile("elsie")) 5 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>] 6 7 data_soup = BeautifulSoup('<div data-foo="value">foo!</div>') 8 data_soup.find_all(data-foo="value") 9 # SyntaxError: keyword can't be an expression 10 11 soup.find_all(href=re.compile("elsie"), id='link1') 12 # [<a class="sister" href="http://example.com/elsie" id="link1">three</a>] 13 14 def not_lacie(href): 15 return href and not re.compile("lacie").search(href) 16 soup.find_all(href=not_lacie) 17 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, 18 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
当然过滤属性也可以用它的第二个参数attrs, 不像第一个参数,该参数必须是字典 :
data_soup.find_all(attrs={"data-foo": "value"}) # [<div data-foo="value">foo!</div>]
本来tag的属性中有一个属性很常见叫做class, 但是class是python的关键字, 所以改成了class_, 用法和keyword参数的用法相同, 值得一提的是如果一个tag的类有多个值(一个tag同时属于多个类是合理的), 那么只要其中一个属性匹配了该tag, 该tag就被返回, 但是如果你尝试着匹配多个value, 那么一定要按照顺序, 如果顺序和tag的class中不同, 那么将匹配失败, 需要使用select而不是find_all() :
1 soup.find_all(class_=re.compile("itl")) 2 # [<p class="title"><b>The Dormouse's story</b></p>] 3 4 def has_six_characters(css_class): 5 return css_class is not None and len(css_class) == 6 6 7 soup.find_all(class_=has_six_characters) 8 # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, 9 # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, 10 # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] 11 12 css_soup.find_all("p", class_="body") 13 # [<p class="body strikeout"></p>] 14 15 css_soup.find_all("p", class_="strikeout body") 16 # [] 17 18 css_soup.select("p.strikeout.body") 19 # [<p class="body strikeout"></p>]
第四个参数是string, 较老版本也叫作text... 单纯的使用该参数将寻找tag中的strings, 可以配合tag一起来用, 就能找到.string匹配这个条件的tag...
soup.find_all(string="Elsie") # [u'Elsie'] soup.find_all(string=["Tillie", "Elsie", "Lacie"]) # [u'Elsie', u'Lacie', u'Tillie'] soup.find_all(string=re.compile("Dormouse")) [u"The Dormouse's story", u"The Dormouse's story"] def is_the_only_string_within_a_tag(s): """Return True if this string is the only child of its parent tag.""" return (s == s.parent.string) soup.find_all(string=is_the_only_string_within_a_tag) # [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...'] soup.find_all("a", string="Elsie") # [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]
limit参数很简单, 就是给该方法一个寻找数量上限, 比如limit=2, 那么找到2个之后就返回, 不再寻找, 所以当limit=1时, find_all()和find()相同.
recursive参数默认为True, 此时函数会匹配包括自己以及子孙tag, 如果设为False, 那么只匹配自己和孩子...
因为find_all()实在是太常用了, 所以这里还提供了简写方式 .
soup.find_all("a") soup("a")
find()和find_all()除了上面提到的limit, 其他没区别, 这里就不重复了...