Finding by ID, Class and Attribute
Most real scraping targets are styled or identified by attributes: an id for unique elements, a class for repeated elements, and data-* attributes added by the framework. find() and find_all() let you filter on any of them.
By ID
from bs4 import BeautifulSoup
html = "<div id="main"><p>content</p></div>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find(id="main").get_text()) # content
By Class
Use the class_ keyword argument (trailing underscore) because class is reserved in Python:
html = "<ul><li class="item">A</li><li class="item promo">B</li></ul>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find_all("li", class_="item")) # both li's (first class matches)
# match a specific class in a multi-class attribute:
print(soup.find("li", class_="promo")) # <li class="item promo">B</li>
By Arbitrary Attributes
Pass any attribute as a keyword; for attribute names that are not valid Python identifiers (dashes, dots), use the attrs dict:
html = "<a data-page="2" rel="next">next</a>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find("a", rel="next"))
print(soup.find(attrs={"data-page": "2"}))
print(soup.find("a", data_page="2")) # underscores map to data-page
Regex and Function Values
Attribute values can be regular expressions or functions:
import re
html = "<a href="https://x.com/a/1">1</a><a href="https://x.com/a/22">22</a>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find_all("a", href=re.compile(r"/a/\d+$"))) # both
def deep_link(tag):
return tag.has_attr("href") and tag["href"].startswith("https://x.com/a/2")
print(soup.find(deep_link))
Summary
Filter by id for unique elements, by class_ (with the underscore) for repeated classes, and by arbitrary attributes directly or through the attrs dict. Attribute values may be exact strings, regexes, or functions, which covers virtually any selection need a static page can present.