The find Method
.find() searches the parse tree and returns the first tag that matches your filter, or None if nothing matches. It accepts a tag name, an attribute filter, a function, or a combination, making it the most versatile single search method in Beautiful Soup.
By Tag Name
from bs4 import BeautifulSoup
html = "<div><p>first</p><section><p>nested</p></section></div>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find("p")) # <p>first</p>
print(soup.find("nosuch")) # None
By Attributes
Pass attributes as keyword arguments. The class attribute is written class_ because class is a Python keyword:
html = "<ul><li id="a">x</li><li class="hot">y</li></ul>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find("li", id="a")) # <li id="a">x</li>
print(soup.find("li", class_="hot")) # <li class="hot">y</li>
print(soup.find(attrs={"data-x": "1"})) # any tag with data-x="1"
limit and recursive
limit bounds the number of matches scanned (find always returns at most one tag, but limit can stop the search early), and recursive=False restricts the search to direct children:
html = "<div><p>direct</p><span><p>indirect</p></span></div>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find("p")) # <p>direct</p>
print(soup.find("p", recursive=False)) # None (no direct <p> child of soup? it has <div>)
Function Filters
For logic that is awkward to express as attributes, pass a function that receives a tag and returns True or False:
def is_big_heading(tag):
return tag.name == "h2" and tag.get("class") and "big" in tag.get("class")
print(soup.find(is_big_heading))
Summary
find() returns the first matching tag or None. Filter by name, by attributes (class_ for the class attribute, attrs=dict for arbitrary names), by a custom function, and control scope with limit and recursive=False. Always guard against None before reading the result.