Navigating the DOM Tree with BeautifulSoup
Tag inspection in BeautifulSoup means accessing the individual components of a Tag object: its attributes (via get() or attrs), its text content (via contents or get_text()), and its child elements (via contents).
Try it: Parsing HTML with BeautifulSoup
How BeautifulSoup(html, 'html.parser') turns raw HTML text into a tree of Tag objects, tolerating unclosed and mis-nested tags, and how soup('a'), find() and find_all() with class_ / attrs filters pick tags out of it so .get('href', None), tag['href'], .attrs, .contents, .get_text() and .string can extract their data.
How it works
- html.parser reads the text left to right and reports start tags (with their attributes), end tags, text, comments and declarations.
- Each start tag becomes a Tag inside the tag that is currently open; void elements such as <br> and <img> are closed at once; class and rel values are split into lists.
- An end tag closes the most recently opened tag of that name, and every tag still open inside it; an end tag with no matching open tag is ignored. Tags still open at the end are closed then. Whitespace-only text becomes a single '\n' or ' ' string.
- soup('a') is the same call as soup.find_all('a'): it walks every tag in document order and keeps those whose name matches and whose attributes pass the filter (a class_ value matches any one class). find() stops at the first match and returns None when nothing matches.
- Each result is a Tag: .get('href', None) returns the value or None, tag['href'] raises KeyError when it is missing, .attrs is the attribute dict, .contents the list of children, .get_text() all the text inside, .string the single string child (or None).
Default run (69 steps): Raw HTML: 356 characters of plain text. BeautifulSoup(html, 'html.parser') will turn it into a tree. … [tag.get('href', None) for tag in soup('a')] → ['https://www.py4e.com/', '/lessons', '#top', None]
Simplified: A from-scratch port of Python 3.12's html.parser and BeautifulSoup 4.15's html.parser tree builder, checked against the real libraries on 330+ documents and 12,000+ queries. Documents are limited to 1,500 characters; named character references are limited to about 50 common names (others stay literal text); searches take one tag name and at most one attribute filter (no regular expressions, lists, functions, string= or CSS select()). Other parsers (lxml, html5lib) build different trees for broken HTML.
Loading the simulation…
From HTML Text to a Navigable Tree
BeautifulSoup does not leave parsed HTML as an undifferentiated string. The html.parser reads the HTML, recognizes tag boundaries, extracts attributes, and builds a navigable tree. The result contains Tag objects that can be inspected one component at a time.
An anchor element is represented as a Tag object. That object has a tag name, attributes such as href, inner content, and a position among parent, child, and sibling elements in the document tree. To retrieve every anchor, use the parsed document's search operation for the anchor tag name, then inspect each returned Tag.
An Anchor as a Structured Object
Tag inspection means accessing the individual components of a BeautifulSoup Tag: its attributes through get() or attrs, its text through contents or get_text(), and its child elements through contents.
For an anchor Tag, the URL is normally stored in the href attribute. The visible wording can be obtained from the tag's text content. The complete set of attributes can be inspected through attrs, while contents exposes the items between the opening and closing tags. Those items may be text or nested Tag objects.
| Inspection target | BeautifulSoup access | What it exposes |
|---|---|---|
| One optional attribute | get('href', None) | The attribute value, or a safe fallback when the attribute is missing |
| All attributes | attrs | The tag's complete attribute collection |
| Direct contents | contents | A list containing text and child Tag objects |
| Clean text | get_text().strip() | Text with surrounding whitespace removed |
Common ways to inspect an anchor Tag
Reading One Anchor Step by Step
Inspecting a Link with Nested Content
Suppose one parsed anchor Tag represents a link with an href attribute, visible wording, and possible whitespace or nested content. Which parts should you inspect?
- 1Retrieve the destination
Read the href attribute with
get('href', None). This avoids an error if the anchor does not contain href. - 2Read the complete attribute collection
Inspect attrs when you need to examine href together with other attributes such as class or id.
- 3Inspect direct contents
Use contents to see the list of text and child elements between the opening and closing anchor tags.
- 4Extract clean visible text
Use
get_text().strip() so surrounding whitespace, including source formatting whitespace, does not remain in the extracted text.
The anchor is treated as a structured Tag: its URL, full attributes, direct contents, and cleaned text are inspected separately.
Contents and visible text are related but not identical. contents preserves a list of direct items, so that list may include a newline character or another child tag. get_text() focuses on rendered text, and strip() removes surrounding whitespace. This distinction matters when the original HTML is formatted across multiple lines.
URL Forms in Real Documents
The href value is not guaranteed to have one uniform form. Real web pages contain absolute URLs, relative paths, and in-page references. An absolute URL identifies a complete web destination. A relative path is interpreted in relation to the document being processed. An in-page reference points to a location within the page. These values should not be treated as interchangeable.
Inspect the href value before using it. Filter and validate URLs so that a collection of links does not assume every value is a usable external destination.
Common mistake Assuming every href is an absolute URL
What it looks likeA parsed page may contain absolute URLs, relative paths, and in-page references.
Why it failsThese forms represent different kinds of destinations and may require different handling.
Do this insteadClassify, filter, and validate href values before using them.
Common mistake Treating contents as already-clean text
What it looks likecontents may include a newline character before the visible wording.
Why it failscontents is a list of direct text and child elements, not a cleaned text field.
Do this insteadUse get_text().strip() when clean text is required.
Common mistake Reading a missing attribute with direct dictionary-style access
What it looks likeAn anchor without href is accessed as though href must exist.
Why it failsDirect access raises a
KeyErrorwhen the attribute is missing.Do this insteadUse get('href', None) when the attribute may be absent.
Inspection Practice
A parsed document contains several anchor Tags. For each anchor, plan an inspection record containing its href value, complete attrs collection, direct contents list, and cleaned visible text. Then decide whether each href is an absolute URL, a relative path, or an in-page reference, and mark values that require filtering or validation.
Hints
- Use
get('href', None)for the optional URL attribute. - Use attrs when you need the complete attribute collection.
- Use contents to inspect direct text and child Tag objects.
- Use
get_text().strip() for clean visible text. - Do not assume every href has the same URL form.
A useful mental sequence is: locate every anchor Tag, inspect its href safely, inspect all attributes when needed, examine contents when structure matters, and extract cleaned text for display or analysis. Keeping these steps separate prevents the Tag's string representation from hiding the information you actually need.
Key Takeaways
- 1BeautifulSoup parses HTML into a navigable tree containing structured Tag objects.
- 2Search the parsed document for anchor tags, then inspect each returned Tag separately.
- 3Use
get('href', None)for safe optional-attribute access, attrs for the full attribute collection, contents for direct items, andget_text().strip() for clean text. - 4contents may include whitespace and child Tags, so it is not always equivalent to clean visible text.
- 5Real href values can be absolute URLs, relative paths, or in-page references; filter and validate them before use.
At a glance
- BeautifulSoup represents parsed HTML elements as structured Tag objects rather than plain strings.
- Anchor inspection separates URL attributes, complete attributes, direct contents, and cleaned text.
- The safe default for a possibly missing href is
get('href', None). - contents preserves direct text and child elements, including formatting whitespace.
- URL values must be classified, filtered, and validated because real pages mix absolute, relative, and in-page destinations.