Beautiful Soup - 搜索树
Beautifulsoup 有很多方法,可以让我们搜索解析树。 两个最常见和使用的方法是 find() 和 find_all()。
在讨论 find() 和 find_all() 之前,让我们看一些可以传递给这些方法的不同过滤器的示例。
过滤器的种类
我们有不同的过滤器,我们可以将它们传递给这些方法,理解这些过滤器是至关重要的,因为这些过滤器在整个搜索 API 中一次又一次地使用。 我们可以根据标签的名称、标签的属性、字符串的文本或这些的混合来使用这些过滤器。
一个字符串
最简单的过滤器类型之一是字符串。 将字符串传递给搜索方法,Beautifulsoup 将针对该精确字符串执行匹配。
下面的代码会找到文档中所有的 <p> 标签 −
>>> markup = BeautifulSoup('<p>Top Three</p><p><pre>Programming Languages are:</pre></p><p><b>Java, Python, Cplusplus</b></p>') >>> markup.find_all('p') [<p>Top Three</p>, <p></p>, <p><b>Java, Python, Cplusplus</b></p>]
正则表达式
您可以查找所有以给定字符串/标签开头的标签。 在此之前我们需要导入 re 模块来使用正则表达式。
>>> import re >>> markup = BeautifulSoup('<p>Top Three</p><p><pre>Programming Languages are:</pre></p><p><b>Java, Python, Cplusplus</b></p>') >>> >>> markup.find_all(re.compile('^p')) [<p>Top Three</p>, <p></p>, <pre>Programming Languages are:</pre>, <p><b>Java, Python, Cplusplus</b></p>]
列表
您可以通过提供列表来传递多个标签以进行查找。 下面的代码找到所有的 <b> 和 <pre> 标签 −
>>> markup.find_all(['pre', 'b']) [<pre>Programming Languages are:</pre>, <b>Java, Python, Cplusplus</b>]
True
True 将返回它可以找到的所有标签,但不返回其自身的字符串 −
>>> markup.find_all(True) [<html><body><p>Top Three</p><p></p><pre>Programming Languages are:</pre> <p><b>Java, Python, Cplusplus</b> </p> </body></html>, <body><p>Top Three</p><p></p><pre> Programming Languages are:</pre><p><b>Java, Python, Cplusplus</b></p> </body>, <p>Top Three</p>, <p></p>, <pre>Programming Languages are:</pre>, <p><b>Java, Python, Cplusplus</b></p>, <b>Java, Python, Cplusplus</b>]
只返回上述 soup 中的标签 −
>>> for tag in markup.find_all(True): (tag.name) 'html' 'body' 'p' 'p' 'pre' 'p' 'b'
find_all()
您可以使用 find_all 从页面响应中提取所有出现的特定标记作为 −
语法
find_all(name, attrs, recursive, string, limit, **kwargs)
让我们从 IMDB 中提取一些有趣的数据——有史以来"Top rated movies"(评分最高的电影)。
>>> url="https://www.imdb.com/chart/top/?ref_=nv_mv_250" >>> content = requests.get(url) >>> soup = BeautifulSoup(content.text, 'html.parser') #Extract title Page >>> print(soup.find('title')) <title>IMDb Top 250 - IMDb</title> #Extracting main heading >>> for heading in soup.find_all('h1'): print(heading.text) Top Rated Movies #Extracting sub-heading >>> for heading in soup.find_all('h3'): print(heading.text) IMDb Charts You Have Seen IMDb Charts Top India Charts Top Rated Movies by Genre Recently Viewed
从上面,可以看到 find_all 会提供所有符合我们定义的搜索条件的项目。 我们可以与 find_all() 一起使用的所有过滤器都可以与 find() 和其他搜索方法一起使用,如 find_parents() 或 find_siblings()。
find()
我们在上面已经看到,find_all()是用来扫描整个文档,找到所有的内容,但有时,要求是只找到一个结果。 如果你知道文档只包含一个 <body> 标签,那么去搜索整个文档是浪费时间。 一种方法是每次都使用 limit=1 调用 find_all() 或者我们可以使用 find() 方法来做同样的事情 −
语法
find(name, attrs, recursive, string, **kwargs)
下面两种不同的方法给出相同的输出 −
>>> soup.find_all('title',limit=1) [<title>IMDb Top 250 - IMDb</title>] >>> >>> soup.find('title') <title>IMDb Top 250 - IMDb</title>
在以上输出中,我们可以看到 find_all() 方法返回一个包含单个项目的列表,而 find() 方法返回单个结果。
find() 和 find_all() 方法的另一个区别是 −
>>> soup.find_all('h2') [] >>> >>> soup.find('h2')
如果 soup.find_all() 方法找不到任何东西,它会返回空列表,而 find() 则返回 None。
find_parents() and find_parent()
不像 find_all() 和 find() 方法遍历树,查看标签的后代。find_parents() 和 find_parents 方法() 做相反的事情,它们向上遍历树并查看父标签(或字符串) 。
语法
find_parents(name, attrs, string, limit, **kwargs) find_parent(name, attrs, string, **kwargs) >>> a_string = soup.find(string="The Godfather") >>> a_string 'The Godfather' >>> a_string.find_parents('a') [<a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a>] >>> a_string.find_parent('a') <a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a> >>> a_string.find_parent('tr') <tr> <td class="posterColumn"> <span data-value="2" name="rk"></span> <span data-value="9.149038526210072" name="ir"></span> <span data-value="6.93792E10" name="us"></span> <span data-value="1485540" name="nv"></span> <span data-value="-1.850961473789928" name="ur"></span> <a href="/title/tt0068646/"> <img alt="The Godfather" height="67" src="https://m.media-amazon.com/images/M/MV5BM2MyNjYxNmUtYTAwNi00MTYxLWJmNWYtYzZlODY3ZTk3OTFlXkEyXkFqcGdeQXVyNzkwMjQ5NzM@._V1_UY67_CR1,0,45,67_AL_.jpg" width="45"/> </a> </td> <td class="titleColumn"> 2. <a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a> <span class="secondaryInfo">(1972)</span> </td> <td class="ratingColumn imdbRating"> <strong title="9.1 based on 1,485,540 user ratings">9.1</strong> </td> <td class="ratingColumn"> <div class="seen-widget seen-widget-tt0068646 pending" data-titleid="tt0068646"> <div class="boundary"> <div class="popover"> <span class="delete"> </span><ol><li>1<li>2<li>3<li>4<li>5<li>6<li>7<li>8<li>9<li>10</li>0</li></li></li></li&td;</li></li></li></li></li></ol> </div> </div> <div class="inline"> <div class="pending"></div> <div class="unseeable">NOT YET RELEASED</div> <div class="unseen"> </div> <div class="rating"></div> <div class="seen">Seen</div> </div> </div> </td> <td class="watchlistColumn"> <div class="wlb_ribbon" data-recordmetrics="true" data-tconst="tt0068646"></div> </td> </tr> >>> >>> a_string.find_parents('td') [<td class="titleColumn"> 2. <a href="/title/tt0068646/" title="Francis Ford Coppola (dir.), Marlon Brando, Al Pacino">The Godfather</a> <span class="secondaryInfo">(1972)</span> </td>]
类似的方法还有其他八种 −
find_next_siblings(name, attrs, string, limit, **kwargs) find_next_sibling(name, attrs, string, **kwargs) find_previous_siblings(name, attrs, string, limit, **kwargs) find_previous_sibling(name, attrs, string, **kwargs) find_all_next(name, attrs, string, limit, **kwargs) find_next(name, attrs, string, **kwargs) find_all_previous(name, attrs, string, limit, **kwargs) find_previous(name, attrs, string, **kwargs)
这里,
find_next_siblings() 和 find_next_sibling() 方法将遍历当前元素之后的所有兄弟元素。
find_previous_siblings() 和 find_previous_sibling() 方法将迭代当前元素之前的所有兄弟元素。
find_all_next() 和 find_next() 方法将遍历当前元素之后的所有标签和字符串。
find_all_previous 和 find_previous() 方法将遍历当前元素之前的所有标签和字符串。
CSS 选择器
BeautifulSoup 库支持最常用的 CSS 选择器。 您可以借助 select() 方法使用 CSS 选择器搜索元素。
这里有一些例子 −
>>> soup.select('title') [<title>IMDb Top 250 - IMDb</title>, <title>IMDb Top Rated Movies</title>] >>> >>> soup.select("p:nth-of-type(1)") [<p>The Top Rated Movie list only includes theatrical features.</p>, <p> class="imdb-footer__copyright _2-iNNCFskmr4l2OFN2DRsf">© 1990-2019 by IMDb.com, Inc.</p>] >>> len(soup.select("p:nth-of-type(1)")) 2 >>> len(soup.select("a")) 609 >>> len(soup.select("p")) 2 >>> soup.select("html head title") [<title>IMDb Top 250 - IMDb</title>, <title>IMDb Top Rated Movies</title>] >>> soup.select("head > title") [<title>IMDb Top 250 - IMDb</title>] #print HTML code of the tenth li elemnet >>> soup.select("li:nth-of-type(10)") [<li class="subnav_item_main"> <a href="/search/title?genres=film_noir&sort=user_rating,desc&title_type=feature&num_votes=25000,">Film-Noir </a> </li>]