NavigableString Objects
Every piece of text in the document is a NavigableString. It behaves like a Python string (you can slice it, call .strip(), test with .startswith()), but it also knows its position in the tree, so you can navigate from a string the same way you navigate from a tag.
Creating and Using
from bs4 import BeautifulSoup
from bs4.element import NavigableString
s = NavigableString("some text")
print(type(s)) # <class 'bs4.element.NavigableString'>
print(isinstance(s, str)) # True
print(s.strip()) # some text
html = "<p>Hello, world</p>"
soup = BeautifulSoup(html, "html.parser")
txt = soup.p.string
print(repr(txt)) # 'Hello, world'
print(txt.upper()) # HELLO, WORLD
Converting to a Plain String
When you need a real str (for storage, comparison, or APIs), convert explicitly:
plain = str(soup.p.string)
print(type(plain)) # <class 'str'>
Strings in the Tree
A tag with exactly one text child exposes it as .string; a tag with mixed content returns None for .string, and you should use .get_text() instead:
html = "<p>only text</p><div><b>x</b> and text</div>"
soup = BeautifulSoup(html, "html.parser")
print(soup.p.string) # only text
print(soup.div.string) # None
print(soup.div.get_text()) # x and text
Finding Strings Directly
You can search for text nodes without going through tags at all:
for s in soup.find_all(string="Hello, world"):
print(s.parent.name) # p
Summary
NavigableString is a string subclass that lives in the tree: slice and strip it like a str, navigate from it with the same tree properties, and convert with str() when you need a plain string. Use tag.string only for single-text tags, and tag.get_text() for anything more complex.