Soup Find
Beautiful Soup 4.9.0 documentation – Crummy
Beautiful Soup is a
Python library for pulling data out of HTML and XML files. It works
with your favorite parser to provide idiomatic ways of navigating,
searching, and modifying the parse tree. It commonly saves programmers
hours or days of work.
These instructions illustrate all major features of Beautiful Soup 4,
with examples. I show you what the library is good for, how it works,
how to use it, how to make it do what you want, and what to do when it
violates your expectations.
This document covers Beautiful Soup version 4. 9. 3. The examples in
this documentation should work the same way in Python 2. 7 and Python
3. 8.
You might be looking for the documentation for Beautiful Soup 3.
If so, you should know that Beautiful Soup 3 is no longer being
developed and that support for it will be dropped on or after December
31, 2020. If you want to learn about the differences between Beautiful
Soup 3 and Beautiful Soup 4, see Porting code to BS4.
This documentation has been translated into other languages by
Beautiful Soup users:
这篇文档当然还有中文版.
このページは日本語で利用できます(外部リンク)
이 문서는 한국어 번역도 가능합니다.
Este documento também está disponível em Português do Brasil.
Эта документация доступна на русском языке.
Getting help¶
If you have questions about Beautiful Soup, or run into problems,
send mail to the discussion group. If
your problem involves parsing an HTML document, be sure to mention
what the diagnose() function says about
that document.
Here’s an HTML document I’ll be using as an example throughout this
document. It’s part of a story from Alice in Wonderland:
html_doc = “””
The Dormouse’s story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
…
“””
Running the “three sisters” document through Beautiful Soup gives us a
BeautifulSoup object, which represents the document as a nested
data structure:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, ”)
print(ettify())
#
#
#
# The Dormouse’s story
#
#
#
#
#
#
#
#
# Once upon a time there were three little sisters; and their names were
#
# Elsie
#
#,
#
# Lacie
# and
#
# Tillie
#; and they lived at the bottom of a well.
#…
#
#
Here are some simple ways to navigate that data structure:
#
# u’title’
# u’The Dormouse’s story’
# u’head’
soup. p
#
The Dormouse’s story
soup. p[‘class’]
soup. a
# Elsie
nd_all(‘a’)
# [Elsie,
# Lacie,
# Tillie]
(id=”link3″)
# Tillie
One common task is extracting all the URLs found within a page’s tags:
for link in nd_all(‘a’):
print((‘href’))
# # #
Another common task is extracting all the text from a page:
print(t_text())
#
# Elsie,
# Lacie and
# Tillie;
# and they lived at the bottom of a well.
Does this look like what you need? If so, read on.
If you’re using a recent version of Debian or Ubuntu Linux, you can
install Beautiful Soup with the system package manager:
$ apt-get install python-bs4 (for Python 2)
$ apt-get install python3-bs4 (for Python 3)
Beautiful Soup 4 is published through PyPi, so if you can’t install it
with the system packager, you can install it with easy_install or
pip. The package name is beautifulsoup4, and the same package
works on Python 2 and Python 3. Make sure you use the right version of
pip or easy_install for your Python version (these may be named
pip3 and easy_install3 respectively if you’re using Python 3).
$ easy_install beautifulsoup4
$ pip install beautifulsoup4
(The BeautifulSoup package is not what you want. That’s
the previous major release, Beautiful Soup 3. Lots of software uses
BS3, so it’s still available, but if you’re writing new code you
should install beautifulsoup4. )
If you don’t have easy_install or pip installed, you can
download the Beautiful Soup 4 source tarball and
install it with
$ python install
If all else fails, the license for Beautiful Soup allows you to
package the entire library with your application. You can download the
tarball, copy its bs4 directory into your application’s codebase,
and use Beautiful Soup without installing it at all.
I use Python 2. 7 and Python 3. 8 to develop Beautiful Soup, but it
should work with other recent versions.
Problems after installation¶
Beautiful Soup is packaged as Python 2 code. When you install it for
use with Python 3, it’s automatically converted to Python 3 code. If
you don’t install the package, the code won’t be converted. There have
also been reports on Windows machines of the wrong version being
installed.
If you get the ImportError “No module named HTMLParser”, your
problem is that you’re running the Python 2 version of the code under
Python 3.
If you get the ImportError “No module named ”, your
problem is that you’re running the Python 3 version of the code under
Python 2.
In both cases, your best bet is to completely remove the Beautiful
Soup installation from your system (including any directory created
when you unzipped the tarball) and try the installation again.
If you get the SyntaxError “Invalid syntax” on the line
ROOT_TAG_NAME = u'[document]’, you need to convert the Python 2
code to Python 3. You can do this either by installing the package:
$ python3 install
or by manually running Python’s 2to3 conversion script on the
bs4 directory:
$ 2to3-3. 2 -w bs4
Installing a parser¶
Beautiful Soup supports the HTML parser included in Python’s standard
library, but it also supports a number of third-party Python parsers.
One is the lxml parser. Depending on your setup,
you might install lxml with one of these commands:
$ apt-get install python-lxml
$ easy_install lxml
$ pip install lxml
Another alternative is the pure-Python html5lib parser, which parses HTML the way a
web browser does. Depending on your setup, you might install html5lib
with one of these commands:
$ apt-get install python-html5lib
$ easy_install html5lib
$ pip install html5lib
This table summarizes the advantages and disadvantages of each parser library:
Parser
Typical usage
Advantages
Disadvantages
Python’s
BeautifulSoup(markup, “”)
Batteries included
Decent speed
Lenient (As of Python 2. 7. 3
and 3. 2. )
Not as fast as lxml,
less lenient than
html5lib.
lxml’s HTML parser
BeautifulSoup(markup, “lxml”)
Very fast
Lenient
External C dependency
lxml’s XML parser
BeautifulSoup(markup, “lxml-xml”)
BeautifulSoup(markup, “xml”)
The only currently supported
XML parser
html5lib
BeautifulSoup(markup, “html5lib”)
Extremely lenient
Parses pages the same way a
web browser does
Creates valid HTML5
Very slow
External Python
dependency
If you can, I recommend you install and use lxml for speed. If you’re
using a very old version of Python – earlier than 2. 3 or 3. 2 –
it’s essential that you install lxml or html5lib. Python’s built-in
HTML parser is just not very good in those old versions.
Note that if a document is invalid, different parsers will generate
different Beautiful Soup trees for it. See Differences
between parsers for details.
To parse a document, pass it into the BeautifulSoup
constructor. You can pass in a string or an open filehandle:
with open(“”) as fp:
soup = BeautifulSoup(fp, ”)
soup = BeautifulSoup(“a web page“, ”)
First, the document is converted to Unicode, and HTML entities are
converted to Unicode characters:
print(BeautifulSoup(“Sacré bleu! “, “”))
# Sacré bleu!
Beautiful Soup then parses the document using the best available
parser. It will use an HTML parser unless you specifically tell it to
use an XML parser. (See Parsing XML. )
Beautiful Soup transforms a complex HTML document into a complex tree
of Python objects. But you’ll only ever have to deal with about four
kinds of objects: Tag, NavigableString, BeautifulSoup,
and Comment.
Tag¶
A Tag object corresponds to an XML or HTML tag in the original document:
soup = BeautifulSoup(‘Extremely bold‘, ”)
tag = soup. b
type(tag)
#
Tags have a lot of attributes and methods, and I’ll cover most of them
in Navigating the tree and Searching the tree. For now, the most
important features of a tag are its name and attributes.
Name¶
Every tag has a name, accessible as
If you change a tag’s name, the change will be reflected in any HTML
markup generated by Beautiful Soup:
= “blockquote”
tag
#
Extremely bold
Attributes¶
A tag may have any number of attributes. The tag has an attribute “id” whose value is
“boldest”. You can access a tag’s attributes by treating the tag like
a dictionary:
tag = BeautifulSoup(‘bold‘, ”). b
tag[‘id’]
# ‘boldest’
You can access that dictionary directly as
# {‘id’: ‘boldest’}
You can add, remove, and modify a tag’s attributes. Again, this is
done by treating the tag as a dictionary:
tag[‘id’] = ‘verybold’
tag[‘another-attribute’] = 1
#
del tag[‘id’]
del tag[‘another-attribute’]
# bold
# KeyError: ‘id’
(‘id’)
# None
Multi-valued attributes¶
HTML 4 defines a few attributes that can have multiple values. HTML 5
removes a couple of them, but defines a few more. The most common
multi-valued attribute is class (that is, a tag can have more than
one CSS class). Others include rel, rev, accept-charset,
headers, and accesskey. Beautiful Soup presents the value(s)
of a multi-valued attribute as a list:
css_soup = BeautifulSoup(‘
‘, ”)
css_soup. p[‘class’]
# [‘body’]
css_soup = BeautifulSoup(‘
‘, ”)
# [‘body’, ‘strikeout’]
If an attribute looks like it has more than one value, but it’s not
a multi-valued attribute as defined by any version of the HTML
standard, Beautiful Soup will leave the attribute alone:
id_soup = BeautifulSoup(‘
‘, ”)
id_soup. p[‘id’]
# ‘my id’
When you turn a tag back into a string, multiple attribute values are
consolidated:
rel_soup = BeautifulSoup(‘
Back to the homepage
‘, ”)
rel_soup. a[‘rel’]
# [‘index’]
rel_soup. a[‘rel’] = [‘index’, ‘contents’]
print(rel_soup. p)
#
Back to the homepage
You can disable this by passing multi_valued_attributes=None as a
keyword argument into the BeautifulSoup constructor:
no_list_soup = BeautifulSoup(‘
‘, ”, multi_valued_attributes=None)
no_list_soup. p[‘class’]
# ‘body strikeout’
You can use get_attribute_list to get a value that’s always a
list, whether or not it’s a multi-valued atribute:
t_attribute_list(‘id’)
# [“my id”]
If you parse a document as XML, there are no multi-valued attributes:
xml_soup = BeautifulSoup(‘
‘, ‘xml’)
xml_soup. p[‘class’]
Again, you can configure this using the multi_valued_attributes argument:
class_is_multi= { ‘*’: ‘class’}
xml_soup = BeautifulSoup(‘
‘, ‘xml’, multi_valued_attributes=class_is_multi) “, “xml”)
You probably won’t need to do this, but if you do, use the defaults as
a guide. They implement the rules described in the HTML specification:
from er import builder_registry
(‘html’). DEFAULT_CDATA_LIST_ATTRIBUTES
NavigableString¶
A string corresponds to a bit of text within a tag. Beautiful Soup
uses the NavigableString class to contain these bits of text:
# ‘Extremely bold’
type()
#
A NavigableString is just like a Python Unicode string, except
that it also supports some of the features described in Navigating
the tree and Searching the tree. You can convert a
NavigableString to a Unicode string with unicode() (in
Python 2) or str (in Python 3):
unicode_string = str()
unicode_string
type(unicode_string)
#
You can’t edit a string in place, but you can replace one string with
another, using replace_with():
(“No longer bold”)
# No longer bold
NavigableString supports most of the features described in
Navigating the tree and Searching the tree, but not all of
them. In particular, since a string can’t contain anything (the way a
tag may contain a string or another tag), strings don’t support the. contents or attributes, or the find() method.
If you want to use a NavigableString outside of Beautiful Soup,
you should call unicode() on it to turn it into a normal Python
Unicode string. If you don’t, your string will carry around a
reference to the entire Beautiful Soup parse tree, even when you’re
done using Beautiful Soup. This is a big waste of memory.
BeautifulSoup¶
The BeautifulSoup object represents the parsed document as a
whole. For most purposes, you can treat it as a Tag
object. This means it supports most of the methods described in
Navigating the tree and Searching the tree.
You can also pass a BeautifulSoup object into one of the methods
defined in Modifying the tree, just as you would a Tag. This
lets you do things like combine two parsed documents:
doc = BeautifulSoup(“
(text=”INSERT FOOTER HERE”). replace_with(footer)
# ‘INSERT FOOTER HERE’
print(doc)
# xml version="1. 0" encoding="utf-8"? >
#
Since the BeautifulSoup object doesn’t correspond to an actual
HTML or XML tag, it has no name and no attributes. But sometimes it’s
useful to look at its, so it’s been given the special
“[document]”:
Here’s the “Three sisters” HTML document again:
html_doc = “””
I’ll use this as an example to show you how to move from one part of
a document to another.
Going down¶
Tags may contain strings and other tags. These elements are the tag’s
children. Beautiful Soup provides a lot of different attributes for
navigating and iterating over a tag’s children.
Note that Beautiful Soup strings don’t support any of these
attributes, because a string can’t have children.
Navigating using tag names¶
The simplest way to navigate the parse tree is to say the name of the
tag you want. If you want the tag, just say
#
You can do use this trick again and again to zoom in on a certain part
of the parse tree. This code gets the first tag beneath the tag:
# The Dormouse’s story
Using a tag name as an attribute will give you only the first tag by that
name:
If you need to get all the tags, or anything more complicated
than the first tag with a certain name, you’ll need to use one of the
methods described in Searching the tree, such as find_all():
# Tillie]. contents and. children¶
A tag’s children are available in a list called. contents:
head_tag =
head_tag
ntents
# [
title_tag = ntents[0]
title_tag
# [‘The Dormouse’s story’]
The BeautifulSoup object itself has children. In this case, the
tag is the child of the BeautifulSoup object. :
len(ntents)
# 1
ntents[0]
# ‘html’
A string does not have. contents, because it can’t contain
anything:
text = ntents[0]
# AttributeError: ‘NavigableString’ object has no attribute ‘contents’
Instead of getting them as a list, you can iterate over a tag’s
children using the. children generator:
for child in ildren:
print(child)
# The Dormouse’s story. descendants¶
The. children attributes only consider a tag’s
direct children. For instance, the tag has a single direct
child–the
But the
story”. There’s a sense in which that string is also a child of the
tag. The. descendants attribute lets you iterate over all
of a tag’s children, recursively: its direct children, the children of
its direct children, and so on:
for child in scendants:
The tag has only one child, but it has two descendants: the
only has one direct child (the tag), but it has a whole lot of
descendants:
len(list(ildren))
len(list(scendants))
# 26
¶
If a tag has only one child, and that child is a NavigableString,
the child is made available as
# ‘The Dormouse’s story’
If a tag’s only child is another tag, and that tag has a, then the parent tag is considered to have the same
as its child:
If a tag contains more than one thing, then it’s not clear what
should refer to, so is defined to be
None:
print()
# None. strings and stripped_strings¶
If there’s more than one thing inside a tag, you can still look at
just the strings. Use the. strings generator:
for string in rings:
print(repr(string))
‘\n’
# “The Dormouse’s story”
# ‘\n’
# ‘Once upon a time there were three little sisters; and their names were\n’
# ‘Elsie’
# ‘, \n’
# ‘Lacie’
# ‘ and\n’
# ‘Tillie’
# ‘;\nand they lived at the bottom of a well. ‘
# ‘… ‘
These strings tend to have a lot of extra whitespace, which you can
remove by using the. stripped_strings generator instead:
for string in ripped_strings:
# ‘Once upon a time there were three little sisters; and their names were’
# ‘, ‘
# ‘and’
# ‘;\n and they lived at the bottom of a well. ‘
Here, strings consisting entirely of whitespace are ignored, and
whitespace at the beginning and end of strings is removed.
Going up¶
Continuing the “family tree” analogy, every tag and every string has a
parent: the tag that contains it.
You can access an element’s parent with the attribute. In
the example “three sisters” document, the tag is the parent
of the
title_tag =
The title string itself has a parent: the
it:
The parent of a top-level tag like is the BeautifulSoup object
itself:
html_tag =
#
And the of a BeautifulSoup object is defined as None:
# None. parents¶
You can iterate over all of an element’s parents with. parents. This example uses. parents to travel from an tag
buried deep within the document, to the very top of the document:
link = soup. a
link
for parent in rents:
# p
# body
# html
# [document]
Going sideways¶
Consider a simple document like this:
sibling_soup = BeautifulSoup(“text1
#
# text1
#
# text2
#
The tag and the
children of the same tag. We call them siblings. When a document is
pretty-printed, siblings show up at the same indentation level. You
can also use this relationship in the code you write.. next_sibling and. previous_sibling¶
You can use. previous_sibling to navigate
between page elements that are on the same level of the parse tree:
xt_sibling
#
evious_sibling
# text1
The tag has a. next_sibling, but no. previous_sibling,
because there’s nothing before the tag on the same level of the
tree. For the same reason, the
but no. next_sibling:
print(evious_sibling)
print(xt_sibling)
The strings “text1” and “text2” are not siblings, because they don’t
have the same parent:
# ‘text1’
In real documents, the. next_sibling or. previous_sibling of a
tag will usually be a string containing whitespace. Going back to the
“three sisters” document:
# Elsie
# Lacie
# Tillie
You might think that the. next_sibling of the first tag would
be the second tag. But actually, it’s a string: the comma and
newline that separate the first tag from the second:
# ‘, \n ‘
The second tag is actually the. next_sibling of the comma:
# Lacie. next_siblings and. previous_siblings¶
You can iterate over a tag’s siblings with. next_siblings or. previous_siblings:
for sibling in xt_siblings:
print(repr(sibling))
# Lacie
# ‘; and they lived at the bottom of a well. ‘
for sibling in (id=”link3″). previous_siblings:
Going back and forth¶
Take a look at the beginning of the “three sisters” document:
#
An HTML parser takes this string of characters and turns it into a
series of events: “open an tag”, “open a tag”, “open a
tag”, and so on. Beautiful Soup offers tools for reconstructing the
initial parse of the document.. next_element and. previous_element¶
The. next_element attribute of a string or tag points to whatever
was parsed immediately afterwards. It might be the same as. next_sibling, but it’s usually drastically different.
Here’s the final tag in the “three sisters” document. Its. next_sibling is a string: the conclusion of the sentence that was
interrupted by the start of the tag. :
last_a_tag = (“a”, id=”link3″)
last_a_tag
But the. next_element of that tag, the thing that was parsed
immediately after the tag, is not the rest of that sentence:
it’s the word “Tillie”:
xt_element
That’s because in the original markup, the word “Tillie” appeared
before that semicolon. The parser encountered an tag, then the
word “Tillie”, then the closing tag, then the semicolon and rest of
the sentence. The semicolon is on the same level as the tag, but the
word “Tillie” was encountered first.
The. previous_element attribute is the exact opposite of. next_element. It points to whatever element was parsed
immediately before this one:
evious_element
# Tillie. next_elements and. previous_elements¶
You should get the idea by now. You can use these iterators to move
forward or backward in the document as it was parsed:
for element in xt_elements:
print(repr(element))
#
…
Beautiful Soup defines a lot of methods for searching the parse tree,
but they’re all very similar. I’m going to spend a lot of time explaining
the two most popular methods: find() and find_all(). The other
methods take almost exactly the same arguments, so I’ll just cover
them briefly.
Once again, I’ll be using the “three sisters” document as an example:
By passing in a filter to an argument like find_all(), you can
zoom in on the parts of the document you’re interested in.
Kinds of filters¶
Before talking in detail about find_all() and similar methods, I
want to show examples of different filters you can pass into these
methods. These filters show up again and again, throughout the
search API. You can use them to filter based on a tag’s name,
on its attributes, on the text of a string, or on some combination of
these.
A string¶
The simplest filter is a string. Pass a string to a search method and
Beautiful Soup will perform a match against that exact string. This
code finds all the tags in the document:
nd_all(‘b’)
# [The Dormouse’s story]
If you pass in a byte string, Beautiful Soup will assume the string is
encoded as UTF-8. You can avoid this by passing in a Unicode string instead.
A regular expression¶
If you pass in a regular expression object, Beautiful Soup will filter
against that regular expression using its search() method. This code
finds all the tags whose names start with the letter “b”; in this
case, the tag and the tag:
import re
for tag in nd_all(mpile(“^b”)):
# b
This code finds all the tags whose names contain the letter ‘t’:
for tag in nd_all(mpile(“t”)):
# title
A list¶
If you pass in a list, Beautiful Soup will allow a string match
against any item in that list. This code finds all the tags
and all the tags:
nd_all([“a”, “b”])
# [The Dormouse’s story,
# Elsie,
True¶
The value True matches everything it can. This code finds all
the tags in the document, but none of the text strings:
for tag in nd_all(True):
# head
# a
A function¶
If none of the other matches work for you, define a function that
takes an element as its only argument. The function should return
True if the argument matches, and False otherwise.
Here’s a function that returns True if a tag defines the “class”
attribute but doesn’t define the “id” attribute:
def has_class_but_no_id(tag):
return tag. has_attr(‘class’) and not tag. has_attr(‘id’)
Pass this function into find_all() and you’ll pick up all the
tags:
nd_all(has_class_but_no_id)
# [
The Dormouse’s story
,
#
Once upon a time there were…bottom of a well.
,
#
…
]
This function only picks up the
The Dormouse’s story
]
nd_all(“a”)
nd_all(id=”link2″)
# [Lacie]
(mpile(“sisters”))
Some of these should look familiar, but others are new. What does it
mean to pass in a value for string, or id? Why does
find_all(“p”, “title”) find a
tag with the CSS class “title”?
Let’s look at the arguments to find_all().
The name argument¶
Pass in a value for name and you’ll tell Beautiful Soup to only
consider tags with certain names. Text strings will be ignored, as
will tags whose names that don’t match.
This is the simplest usage:
Recall from Kinds of filters that the value to name can be a
string, a regular expression, a list, a function, or the value
True.
The keyword arguments¶
Any argument that’s not recognized will be turned into a filter on one
of a tag’s attributes. If you pass in a value for an argument called id,
Beautiful Soup will filter against each tag’s ‘id’ attribute:
nd_all(id=’link2′)
If you pass in a value for href, Beautiful Soup will filter
against each tag’s ‘href’ attribute:
nd_all(mpile(“elsie”))
# [Elsie]
You can filter an attribute based on a string, a regular
expression, a list, a function, or the value True.
This code finds all tags whose id attribute has a value,
regardless of what the value is:
nd_all(id=True)
You can filter multiple attributes at once by passing in more than one
keyword argument:
nd_all(mpile(“elsie”), id=’link1′)
Some attributes, like the data-* attributes in HTML 5, have names that
can’t be used as the names of keyword arguments:
data_soup = BeautifulSoup(‘
‘, ”)
nd_all(data-foo=”value”)
# SyntaxError: keyword can’t be an expression
You can use these attributes in searches by putting them into a
dictionary and passing the dictionary into find_all() as the
attrs argument:
nd_all(attrs={“data-foo”: “value”})
# [
]
You can’t use a keyword argument to search for HTML’s ‘name’ element,
because Beautiful Soup uses the name argument to contain the name
of the tag itself. Instead, you can give a value to ‘name’ in the
name_soup = BeautifulSoup(‘‘, ”)
nd_all(name=”email”)
# []
nd_all(attrs={“name”: “email”})
# []
Searching by CSS class¶
It’s very useful to search for a tag that has a certain CSS class, but
the name of the CSS attribute, “class”, is a reserved word in
Python. Using class as a keyword argument will give you a syntax
error. As of Beautiful Soup 4. 1. 2, you can search by CSS class using
the keyword argument class_:
nd_all(“a”, class_=”sister”)
As with any keyword argument, you can pass class_ a string, a regular
expression, a function, or True:
nd_all(mpile(“itl”))
def has_six_characters(css_class):
return css_class is not None and len(css_class) == 6
nd_all(class_=has_six_characters)
Remember that a single tag can have multiple
values for its “class” attribute. When you search for a tag that
matches a certain CSS class, you’re matching against any of its CSS
classes:
nd_all(“p”, class_=”strikeout”)
# [
]
nd_all(“p”, class_=”body”)
You can also search for the exact string value of the class attribute:
nd_all(“p”, class_=”body strikeout”)
But searching for variants of the string value won’t work:
nd_all(“p”, class_=”strikeout body”)
If you want to search for tags that match two or more CSS classes, you
should use a CSS selector:
(“p. “)
In older versions of Beautiful Soup, which don’t have the class_
shortcut, you can use the attrs trick mentioned above. Create a
dictionary whose value for “class” is the string (or regular
expression, or whatever) you want to search for:
nd_all(“a”, attrs={“class”: “sister”})
The string argument¶
With string you can search for strings instead of tags. As with
name and the keyword arguments, you can pass in a string, a
regular expression, a list, a function, or the value True.
Here are some examples:
nd_all(string=”Elsie”)
# [‘Elsie’]
nd_all(string=[“Tillie”, “Elsie”, “Lacie”])
# [‘Elsie’, ‘Lacie’, ‘Tillie’]
nd_all(mpile(“Dormouse”))
# [“The Dormouse’s story”, “The Dormouse’s story”]
def is_the_only_string_within_a_tag(s):
“””Return True if this string is the only child of its parent tag. “””
return (s ==)
nd_all(string=is_the_only_string_within_a_tag)
# [“The Dormouse’s story”, “The Dormouse’s story”, ‘Elsie’, ‘Lacie’, ‘Tillie’, ‘… ‘]
Although string is for finding strings, you can combine it with
arguments that find tags: Beautiful Soup will find all tags whose
matches your value for string. This code finds the
tags whose is “Elsie”:
nd_all(“a”, string=”Elsie”)
# [Elsie]
The string argument is new in Beautiful Soup 4. 4. 0. In earlier
versions it was called text:
nd_all(“a”, text=”Elsie”)
The limit argument¶
find_all() returns all the tags and strings that match your
filters. This can take a while if the document is large. If you don’t
need all the results, you can pass in a number for limit. This
works just like the LIMIT keyword in SQL. It tells Beautiful Soup to
stop gathering results after it’s found a certain number.
There are three links in the “three sisters” document, but this code
only finds the first two:
nd_all(“a”, limit=2)
# Lacie]
The recursive argument¶
If you call nd_all(), Beautiful Soup will examine all the
descendants of mytag: its children, its children’s children, and
so on. If you only want Beautiful Soup to consider direct children,
you can pass in recursive=False. See the differe
Understand the Find() function in Beautiful Soup – Stack …
I know what I’m trying to do is simple but it’s causing me grief. I’d like pull data from HTML using BeautifulSoup. To do that I need to properly use the () function. Here’s the HTML I’m working with:
32, 452 Fake
Followers
Audit score
The values I want are 73599 from data-value=73599, 32352 from data-value=32452, and the 69% from percentage good.
Using past code and online examples, this is what I have so far:
RealValue = (“div”, {“class”:”real number”})[‘data-value’]
FakeValue = (“audit”, {“class”:”fake number”})[‘data-value’]
Both so far to no effect. I’m not sure how to craft the find in order to pull the 69% number.
asked Dec 16 ’15 at 0:09
(“div”, {“class”:”real number”})[‘data-value’]
Here you are searching for a div element, but the span has the “real number” class in your example HTML data, try instead:
(“span”, {“class”: “real number”, “data-value”: True})[‘data-value’]
Here we are also checking for presence of data-value attribute.
To find elements having “real number” or “fake number” classes, you can make a CSS selector:
for elm in (“, “):
print((“data-value”))
To get the 69% value:
(“div”, {“class”: “percentage good”}). get_text(strip=True)
Or, a CSS selector:
lect_one(“. “). get_text(strip=True)
lect_one(“. percentage”). get_text(strip=True)
Or, locating the h6 element having Audit score text and then getting the preceding sibling:
(“h6″, text=”Audit score”)t_text(strip=True)
answered Dec 16 ’15 at 0:14
alecxealecxe425k106 gold badges975 silver badges1112 bronze badges
2
Not the answer you’re looking for? Browse other questions tagged python html beautifulsoup or ask your own question.
Beautiful Soup Documentation — Beautiful Soup 4.4.0 …
Beautiful Soup
Beautiful Soup is a
Python library for pulling data out of HTML and XML files. It works
with your favorite parser to provide idiomatic ways of navigating,
searching, and modifying the parse tree. It commonly saves programmers
hours or days of work.
These instructions illustrate all major features of Beautiful Soup 4,
with examples. I show you what the library is good for, how it works,
how to use it, how to make it do what you want, and what to do when it
violates your expectations.
This document covers Beautiful Soup version 4. 8. 1. The examples in
this documentation should work the same way in Python 2. 7 and Python
3. 2.
You might be looking for the documentation for Beautiful Soup 3.
If so, you should know that Beautiful Soup 3 is no longer being
developed and that support for it will be dropped on or after December
31, 2020. If you want to learn about the differences between Beautiful
Soup 3 and Beautiful Soup 4, see Porting code to BS4.
This documentation has been translated into other languages by
Beautiful Soup users:
这篇文档当然还有中文版.
このページは日本語で利用できます(外部リンク)
이 문서는 한국어 번역도 가능합니다.
Este documento também está disponível em Português do Brasil.
Getting help¶
If you have questions about Beautiful Soup, or run into problems,
send mail to the discussion group. If
your problem involves parsing an HTML document, be sure to mention
what the diagnose() function says about
that document.
Here’s an HTML document I’ll be using as an example throughout this
document. It’s part of a story from Alice in Wonderland:
html_doc = “””
The Dormouse’s story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
…
“””
Running the “three sisters” document through Beautiful Soup gives us a
BeautifulSoup object, which represents the document as a nested
data structure:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, ”)
print(ettify())
#
#
#
# The Dormouse’s story
#
#
#
#
#
#
#
#
# Once upon a time there were three little sisters; and their names were
#
# Elsie
#
#,
#
# Lacie
# and
# Tillie
#; and they lived at the bottom of a well.
#…
#
#
Here are some simple ways to navigate that data structure:
#
# u’title’
# u’The Dormouse’s story’
# u’head’
soup. p
#
The Dormouse’s story
soup. p[‘class’]
soup. a
# Elsie
nd_all(‘a’)
# [Elsie,
# Lacie,
# Tillie]
(id=”link3″)
# Tillie
One common task is extracting all the URLs found within a page’s tags:
for link in nd_all(‘a’):
print((‘href’))
# # #
Another common task is extracting all the text from a page:
print(t_text())
#
# Elsie,
# Lacie and
# Tillie;
# and they lived at the bottom of a well.
Does this look like what you need? If so, read on.
If you’re using a recent version of Debian or Ubuntu Linux, you can
install Beautiful Soup with the system package manager:
$ apt-get install python-bs4 (for Python 2)
$ apt-get install python3-bs4 (for Python 3)
Beautiful Soup 4 is published through PyPi, so if you can’t install it
with the system packager, you can install it with easy_install or
pip. The package name is beautifulsoup4, and the same package
works on Python 2 and Python 3. Make sure you use the right version of
pip or easy_install for your Python version (these may be named
pip3 and easy_install3 respectively if you’re using Python 3).
$ easy_install beautifulsoup4
$ pip install beautifulsoup4
(The BeautifulSoup package is probably not what you want. That’s
the previous major release, Beautiful Soup 3. Lots of software uses
BS3, so it’s still available, but if you’re writing new code you
should install beautifulsoup4. )
If you don’t have easy_install or pip installed, you can
download the Beautiful Soup 4 source tarball and
install it with
$ python install
If all else fails, the license for Beautiful Soup allows you to
package the entire library with your application. You can download the
tarball, copy its bs4 directory into your application’s codebase,
and use Beautiful Soup without installing it at all.
I use Python 2. 7 and Python 3. 2 to develop Beautiful Soup, but it
should work with other recent versions.
Problems after installation¶
Beautiful Soup is packaged as Python 2 code. When you install it for
use with Python 3, it’s automatically converted to Python 3 code. If
you don’t install the package, the code won’t be converted. There have
also been reports on Windows machines of the wrong version being
installed.
If you get the ImportError “No module named HTMLParser”, your
problem is that you’re running the Python 2 version of the code under
Python 3.
If you get the ImportError “No module named ”, your
problem is that you’re running the Python 3 version of the code under
Python 2.
In both cases, your best bet is to completely remove the Beautiful
Soup installation from your system (including any directory created
when you unzipped the tarball) and try the installation again.
If you get the SyntaxError “Invalid syntax” on the line
ROOT_TAG_NAME = u'[document]’, you need to convert the Python 2
code to Python 3. You can do this either by installing the package:
$ python3 install
or by manually running Python’s 2to3 conversion script on the
bs4 directory:
$ 2to3-3. 2 -w bs4
Installing a parser¶
Beautiful Soup supports the HTML parser included in Python’s standard
library, but it also supports a number of third-party Python parsers.
One is the lxml parser. Depending on your setup,
you might install lxml with one of these commands:
$ apt-get install python-lxml
$ easy_install lxml
$ pip install lxml
Another alternative is the pure-Python html5lib parser, which parses HTML the way a
web browser does. Depending on your setup, you might install html5lib
with one of these commands:
$ apt-get install python-html5lib
$ easy_install html5lib
$ pip install html5lib
This table summarizes the advantages and disadvantages of each parser library:
Parser
Typical usage
Advantages
Disadvantages
Python’s
BeautifulSoup(markup, “”)
Batteries included
Decent speed
Lenient (As of Python 2. 7. 3
and 3. 2. )
Not as fast as lxml,
less lenient than
html5lib.
lxml’s HTML parser
BeautifulSoup(markup, “lxml”)
Very fast
Lenient
External C dependency
lxml’s XML parser
BeautifulSoup(markup, “lxml-xml”)
BeautifulSoup(markup, “xml”)
The only currently supported
XML parser
html5lib
BeautifulSoup(markup, “html5lib”)
Extremely lenient
Parses pages the same way a
web browser does
Creates valid HTML5
Very slow
External Python
dependency
If you can, I recommend you install and use lxml for speed. If you’re
using a version of Python 2 earlier than 2. 3, or a version of Python
3 earlier than 3. 2, it’s essential that you install lxml or
html5lib–Python’s built-in HTML parser is just not very good in older
versions.
Note that if a document is invalid, different parsers will generate
different Beautiful Soup trees for it. See Differences
between parsers for details.
To parse a document, pass it into the BeautifulSoup
constructor. You can pass in a string or an open filehandle:
with open(“”) as fp:
soup = BeautifulSoup(fp)
soup = BeautifulSoup(“data“)
First, the document is converted to Unicode, and HTML entities are
converted to Unicode characters:
BeautifulSoup(“Sacré bleu! “)
Sacré bleu!
Beautiful Soup then parses the document using the best available
parser. It will use an HTML parser unless you specifically tell it to
use an XML parser. (See Parsing XML. )
Beautiful Soup transforms a complex HTML document into a complex tree
of Python objects. But you’ll only ever have to deal with about four
kinds of objects: Tag, NavigableString, BeautifulSoup,
and Comment.
Tag¶
A Tag object corresponds to an XML or HTML tag in the original document:
soup = BeautifulSoup(‘Extremely bold‘)
tag = soup. b
type(tag)
#
Tags have a lot of attributes and methods, and I’ll cover most of them
in Navigating the tree and Searching the tree. For now, the most
important features of a tag are its name and attributes.
Name¶
Every tag has a name, accessible as
If you change a tag’s name, the change will be reflected in any HTML
markup generated by Beautiful Soup:
= “blockquote”
tag
#
Extremely bold
Attributes¶
A tag may have any number of attributes. The tag has an attribute “id” whose value is
“boldest”. You can access a tag’s attributes by treating the tag like
a dictionary:
You can access that dictionary directly as
# {u’id’: ‘boldest’}
You can add, remove, and modify a tag’s attributes. Again, this is
done by treating the tag as a dictionary:
tag[‘id’] = ‘verybold’
tag[‘another-attribute’] = 1
#
del tag[‘id’]
del tag[‘another-attribute’]
#
tag[‘id’]
# KeyError: ‘id’
print((‘id’))
# None
Multi-valued attributes¶
HTML 4 defines a few attributes that can have multiple values. HTML 5
removes a couple of them, but defines a few more. The most common
multi-valued attribute is class (that is, a tag can have more than
one CSS class). Others include rel, rev, accept-charset,
headers, and accesskey. Beautiful Soup presents the value(s)
of a multi-valued attribute as a list:
css_soup = BeautifulSoup(‘
‘)
css_soup. p[‘class’]
# [“body”]
css_soup = BeautifulSoup(‘
‘)
# [“body”, “strikeout”]
If an attribute looks like it has more than one value, but it’s not
a multi-valued attribute as defined by any version of the HTML
standard, Beautiful Soup will leave the attribute alone:
id_soup = BeautifulSoup(‘
‘)
id_soup. p[‘id’]
# ‘my id’
When you turn a tag back into a string, multiple attribute values are
consolidated:
rel_soup = BeautifulSoup(‘
Back to the homepage
‘)
rel_soup. a[‘rel’]
# [‘index’]
rel_soup. a[‘rel’] = [‘index’, ‘contents’]
print(rel_soup. p)
#
Back to the homepage
You can disable this by passing multi_valued_attributes=None as a
keyword argument into the BeautifulSoup constructor:
no_list_soup = BeautifulSoup(‘
‘, ‘html’, multi_valued_attributes=None)
no_list_soup. p[‘class’]
# u’body strikeout’
You can use `get_attribute_list to get a value that’s always a
list, whether or not it’s a multi-valued atribute:
t_attribute_list(‘id’)
# [“my id”]
If you parse a document as XML, there are no multi-valued attributes:
xml_soup = BeautifulSoup(‘
‘, ‘xml’)
xml_soup. p[‘class’]
Again, you can configure this using the multi_valued_attributes argument:
class_is_multi= { ‘*’: ‘class’}
xml_soup = BeautifulSoup(‘
‘, ‘xml’, multi_valued_attributes=class_is_multi)
# [u’body’, u’strikeout’]
You probably won’t need to do this, but if you do, use the defaults as
a guide. They implement the rules described in the HTML specification:
from er import builder_registry
(‘html’). DEFAULT_CDATA_LIST_ATTRIBUTES
NavigableString¶
A string corresponds to a bit of text within a tag. Beautiful Soup
uses the NavigableString class to contain these bits of text:
# u’Extremely bold’
type()
#
A NavigableString is just like a Python Unicode string, except
that it also supports some of the features described in Navigating
the tree and Searching the tree. You can convert a
NavigableString to a Unicode string with unicode():
unicode_string = unicode()
unicode_string
type(unicode_string)
#
You can’t edit a string in place, but you can replace one string with
another, using replace_with():
(“No longer bold”)
#
No longer bold
NavigableString supports most of the features described in
Navigating the tree and Searching the tree, but not all of
them. In particular, since a string can’t contain anything (the way a
tag may contain a string or another tag), strings don’t support the. contents or attributes, or the find() method.
If you want to use a NavigableString outside of Beautiful Soup,
you should call unicode() on it to turn it into a normal Python
Unicode string. If you don’t, your string will carry around a
reference to the entire Beautiful Soup parse tree, even when you’re
done using Beautiful Soup. This is a big waste of memory.
BeautifulSoup¶
The BeautifulSoup object represents the parsed document as a
whole. For most purposes, you can treat it as a Tag
object. This means it supports most of the methods described in
Navigating the tree and Searching the tree.
You can also pass a BeautifulSoup object into one of the methods
defined in Modifying the tree, just as you would a Tag. This
lets you do things like combine two parsed documents:
doc = BeautifulSoup(“
“, “xml”)
(text=”INSERT FOOTER HERE”). replace_with(footer)
# u’INSERT FOOTER HERE’
print(doc)
# xml version="1. 0" encoding="utf-8"? >
#
Since the BeautifulSoup object doesn’t correspond to an actual
HTML or XML tag, it has no name and no attributes. But sometimes it’s
useful to look at its, so it’s been given the special
“[document]”:
# u'[document]’
Here’s the “Three sisters” HTML document again:
I’ll use this as an example to show you how to move from one part of
a document to another.
Going down¶
Tags may contain strings and other tags. These elements are the tag’s
children. Beautiful Soup provides a lot of different attributes for
navigating and iterating over a tag’s children.
Note that Beautiful Soup strings don’t support any of these
attributes, because a string can’t have children.
Navigating using tag names¶
The simplest way to navigate the parse tree is to say the name of the
tag you want. If you want the
#
You can do use this trick again and again to zoom in on a certain part
of the parse tree. This code gets the first tag beneath the tag:
# The Dormouse’s story
Using a tag name as an attribute will give you only the first tag by that
name:
If you need to get all the tags, or anything more complicated
than the first tag with a certain name, you’ll need to use one of the
methods described in Searching the tree, such as find_all():
# Tillie]. contents and. children¶
A tag’s children are available in a list called. contents:
head_tag =
head_tag
ntents
[
title_tag = ntents[0]
title_tag
# [u’The Dormouse’s story’]
The BeautifulSoup object itself has children. In this case, the
tag is the child of the BeautifulSoup object. :
len(ntents)
# 1
ntents[0]
# u’html’
A string does not have. contents, because it can’t contain
anything:
text = ntents[0]
# AttributeError: ‘NavigableString’ object has no attribute ‘contents’
Instead of getting them as a list, you can iterate over a tag’s
children using the. children generator:
for child in ildren:
print(child)
# The Dormouse’s story. descendants¶
The. children attributes only consider a tag’s
direct children. For instance, the tag has a single direct
child–the
# [
But the
story”. There’s a sense in which that string is also a child of the
tag. The. descendants attribute lets you iterate over all
of a tag’s children, recursively: its direct children, the children of
its direct children, and so on:
for child in scendants:
The tag has only one child, but it has two descendants: the
only has one direct child (the tag), but it has a whole lot of
descendants:
len(list(ildren))
len(list(scendants))
# 25
¶
If a tag has only one child, and that child is a NavigableString,
the child is made available as
If a tag’s only child is another tag, and that tag has a, then the parent tag is considered to have the same
as its child:
If a tag contains more than one thing, then it’s not clear what
should refer to, so is defined to be
None:
print()
# None. strings and stripped_strings¶
If there’s more than one thing inside a tag, you can still look at
just the strings. Use the. strings generator:
for string in rings:
print(repr(string))
# u”The Dormouse’s story”
# u’\n\n’
# u’Once upon a time there were three little sisters; and their names were\n’
# u’Elsie’
# u’, \n’
# u’Lacie’
# u’ and\n’
# u’Tillie’
# u’;\nand they lived at the bottom of a well. ‘
# u’… ‘
# u’\n’
These strings tend to have a lot of extra whitespace, which you can
remove by using the. stripped_strings generator instead:
for string in ripped_strings:
# u’Once upon a time there were three little sisters; and their names were’
# u’, ‘
# u’and’
Here, strings consisting entirely of whitespace are ignored, and
whitespace at the beginning and end of strings is removed.
Going up¶
Continuing the “family tree” analogy, every tag and every string has a
parent: the tag that contains it.
You can access an element’s parent with the attribute. In
the example “three sisters” document, the tag is the parent
of the
title_tag =
The title string itself has a parent: the
it:
The parent of a top-level tag like is the BeautifulSoup object
itself:
html_tag =
#
And the of a BeautifulSoup object is defined as None:
# None. parents¶
You can iterate over all of an element’s parents with. parents. This example uses. parents to travel from an tag
buried deep within the document, to the very top of the document:
link = soup. a
link
for parent in rents:
if parent is None:
print(parent)
else:
# p
# body
# html
# [document]
Going sideways¶
Consider a simple document like this:
sibling_soup = BeautifulSoup(“text1
#
# text1
#
# text2
#
The tag and the
children of the same tag. We call them siblings. When a document is
pretty-printed, siblings show up at the same indentation level. You
can also use this relationship in the code you write.. next_sibling and. previous_sibling¶
You can use. previous_sibling to navigate
between page elements that are on the same level of the parse tree:
xt_sibling
#
evious_sibling
# text1
The tag has a. next_sibling, but no. previous_sibling,
because there’s nothing before the tag on the same level of the
tree. For the same reason, the
but no. next_sibling:
print(evious_sibling)
print(xt_sibling)
The strings “text1” and “text2” are not siblings, because they don’t
have the same parent:
# u’text1′
In real documents, the. next_sibling or. previous_sibling of a
tag will usually be a string containing whitespace. Going back to the
“three sisters” document:
Elsie
Lacie
Tillie
You might think that the. next_sibling of the first tag would
be the second tag. But actually, it’s a string: the comma and
newline that separate the first tag from the second:
The second tag is actually the. next_sibling of the comma:
# Lacie. next_siblings and. previous_siblings¶
You can iterate over a tag’s siblings with. next_siblings or. previous_siblings:
for sibling in xt_siblings:
print(repr(sibling))
# Lacie
# u’; and they lived at the bottom of a well. ‘
for sibling in (id=”link3″). previous_siblings:
# ‘ and\n’
Going back and forth¶
Take a look at the beginning of the “three sisters” document:
An HTML parser takes this string of characters and turns it into a
series of events: “open an tag”, “open a tag”, “open a
tag”, and so on. Beautiful Soup offers tools for reconstructing the
initial parse of the document.. next_element and. previous_element¶
The. next_element attribute of a string or tag points to whatever
was parsed immediately afterwards. It might be the same as. next_sibling, but it’s usually drastically different.
Here’s the final tag in the “three sisters” document. Its. next_sibling is a string: the conclusion of the sentence that was
interrupted by the start of the tag. :
last_a_tag = (“a”, id=”link3″)
last_a_tag
# ‘; and they lived at the bottom of a well. ‘
But the. next_element of that tag, the thing that was parsed
immediately after the tag, is not the rest of that sentence:
it’s the word “Tillie”:
xt_element
That’s because in the original markup, the word “Tillie” appeared
before that semicolon. The parser encountered an tag, then the
word “Tillie”, then the closing tag, then the semicolon and rest of
the sentence. The semicolon is on the same level as the tag, but the
word “Tillie” was encountered first.
The. previous_element attribute is the exact opposite of. next_element. It points to whatever element was parsed
immediately before this one:
evious_element
# Tillie. next_elements and. previous_elements¶
You should get the idea by now. You can use these iterators to move
forward or backward in the document as it was parsed:
for element in xt_elements:
print(repr(element))
#
…
Beautiful Soup defines a lot of methods for searching the parse tree,
but they’re all very similar. I’m going to spend a lot of time explaining
the two most popular methods: find() and find_all(). The other
methods take almost exactly the same arguments, so I’ll just cover
them briefly.
Once again, I’ll be using the “three sisters” document as an example:
By passing in a filter to an argument like find_all(), you can
zoom in on the parts of the document you’re interested in.
Kinds of filters¶
Before talking in detail about find_all() and similar methods, I
want to show examples of different filters you can pass into these
methods. These filters show up again and again, throughout the
search API. You can use them to filter based on a tag’s name,
on its attributes, on the text of a string, or on some combination of
these.
A string¶
The simplest filter is a string. Pass a string to a search method and
Beautiful Soup will perform a match against that exact string. This
code finds all the tags in the document:
nd_all(‘b’)
# [The Dormouse’s story]
If you pass in a byte string, Beautiful Soup will assume the string is
encoded as UTF-8. You can avoid this by passing in a Unicode string instead.
A regular expression¶
If you pass in a regular expression object, Beautiful Soup will filter
against that regular expression using its search() method. This code
finds all the tags whose names start with the letter “b”; in this
case, the tag and the tag:
import re
for tag in nd_all(mpile(“^b”)):
# b
This code finds all the tags whose names contain the letter ‘t’:
for tag in nd_all(mpile(“t”)):
# title
A list¶
If you pass in a list, Beautiful Soup will allow a string match
against any item in that list. This code finds all the tags
and all the tags:
nd_all([“a”, “b”])
# [The Dormouse’s story,
# Elsie,
True¶
The value True matches everything it can. This code finds all
the tags in the document, but none of the text strings:
for tag in nd_all(True):
# head
# a
A function¶
If none of the other matches work for you, define a function that
takes an element as its only argument. The function should return
True if the argument matches, and False otherwise.
Here’s a function that returns True if a tag defines the “class”
attribute but doesn’t define the “id” attribute:
def has_class_but_no_id(tag):
return tag. has_attr(‘class’) and not tag. has_attr(‘id’)
Pass this function into find_all() and you’ll pick up all the
tags:
nd_all(has_class_but_no_id)
# [
The Dormouse’s story
,
#
Once upon a time there were…
,
#
…
]
This function only picks up the
The Dormouse’s story
]
nd_all(“a”)
nd_all(id=”link2″)
# [Lacie]
(mpile(“sisters”))
Some of these should look familiar, but others are new. What does it
mean to pass in a value for string, or id? Why does
find_all(“p”, “title”) find a
tag with the CSS class “title”?
Let’s look at the arguments to find_all().
The name argument¶
Pass in a value for name and you’ll tell Beautiful Soup to only
consider tags with certain names. Text strings will be ignored, as
will tags whose names that don’t match.
This is the simplest usage:
Recall from Kinds of filters that the value to name can be a
string, a regular expression, a list, a function, or the value
True.
The keyword arguments¶
Any argument that’s not recognized will be turned into a filter on one
of a tag’s attributes. If you pass in a value for an argument called id,
Beautiful Soup will filter against each tag’s ‘id’ attribute:
nd_all(id=’link2′)
If you pass in a value for href, Beautiful Soup will filter
against each tag’s ‘href’ attribute:
nd_all(mpile(“elsie”))
# [Elsie]
You can filter an attribute based on a string, a regular
expression, a list, a function, or the value True.
This code finds all tags whose id attribute has a value,
regardless of what the value is:
nd_all(id=True)
You can filter multiple attributes at once by passing in more than one
keyword argument:
nd_all(mpile(“elsie”), id=’link1′)
# [three]
Some attributes, like the data-* attributes in HTML 5, have names that
can’t be used as the names of keyword arguments:
data_soup = BeautifulSoup(‘
‘)
nd_all(data-foo=”value”)
# SyntaxError: keyword can’t be an expression
You can use these attributes in searches by putting them into a
dictionary and passing the dictionary into find_all() as the
attrs argument:
nd_all(attrs={“data-foo”: “value”})
# [
]
You can’t use a keyword argument to search for HTML’s ‘name’ element,
because Beautiful Soup uses the name argument to contain the name
of the tag itself. Instead, you can give a value to ‘name’ in the
name_soup = BeautifulSoup(‘‘)
nd_all(name=”email”)
# []
nd_all(attrs={“name”: “email”})
# []
Searching by CSS class¶
It’s very useful to search for a tag that has a certain CSS class, but
the name of the CSS attribute, “class”, is a reserved word in
Python. Using class as a keyword argument will give you a syntax
error. As of Beautiful Soup 4. 2, you can search by CSS class using
the keyword argument class_:
nd_all(“a”, class_=”sister”)
As with any keyword argument, you can pass class_ a string, a regular
expression, a function, or True:
nd_all(mpile(“itl”))
def has_six_characters(css_class):
return css_class is not None and len(css_class) == 6
nd_all(class_=has_six_characters)
Remember that a single tag can have multiple
values for its “class” attribute. When you search for a tag that
matches a certain CSS class, you’re matching against any of its CSS
classes:
nd_all(“p”, class_=”strikeout”)
# [
]
nd_all(“p”, class_=”body”)
You can also search for the exact string value of the class attribute:
nd_all(“p”, class_=”body strikeout”)
But searching for variants of the string value won’t work:
nd_all(“p”, class_=”strikeout body”)
If you want to search for tags that match two or more CSS classes, you
should use a CSS selector:
(“p. “)
In older versions of Beautiful Soup, which don’t have the class_
shortcut, you can use the attrs trick mentioned above. Create a
dictionary whose value for “class” is the string (or regular
expression, or whatever) you want to search for:
nd_all(“a”, attrs={“class”: “sister”})
The string argument¶
With string you can search for strings instead of tags. As with
name and the keyword arguments, you can pass in a string, a
regular expression, a list, a function, or the value True.
Here are some examples:
nd_all(string=”Elsie”)
# [u’Elsie’]
nd_all(string=[“Tillie”, “Elsie”, “Lacie”])
# [u’Elsie’, u’Lacie’, u’Tillie’]
nd_all(mpile(“Dormouse”))
[u”The Dormouse’s story”, u”The Dormouse’s story”]
def is_the_only_string_within_a_tag(s):
“””Return True if this string is the only child of its parent tag. “””
return (s ==)
nd_all(string=is_the_only_string_within_a_tag)
# [u”The Dormouse’s story”, u”The Dormouse’s story”, u’Elsie’, u’Lacie’, u’Tillie’, u’… ‘]
Although string is for finding strings, you can combine it with
arguments that find tags: Beautiful Soup will find all tags whose
matches your value for string. This code finds the
tags whose is “Elsie”:
nd_all(“a”, string=”Elsie”)
# [Elsie]
The string argument is new in Beautiful Soup 4. 4. 0. In earlier
versions it was called text:
nd_all(“a”, text=”Elsie”)
The limit argument¶
find_all() returns all the tags and strings that match your
filters. This can take a while if the document is large. If you don’t
need all the results, you can pass in a number for limit. This
works just like the LIMIT keyword in SQL. It tells Beautiful Soup to
stop gathering results after it’s found a certain number.
There are three links in the “three sisters” document, but this code
only finds the first two:
nd_all(“a”, limit=2)
# Lacie]
The recursive argument¶
If you call nd_all(), Beautiful Soup will examine all the
descendants of mytag: its children, its children’s children, and
so on. If you only want Beautiful Soup to consider direct children,
you can pass in recursive=False. See the difference here:
(“title”)
(“title”, recursive=False)
Here’s that part of the document:
The Dormouse’s story
…
The
What is find in BeautifulSoup?
Syntax. In the above outputs, we can see the find_all() method returns a list containing single item whereas find() method returns single result. If soup. find_all() method can’t find anything, it returns empty list whereas find() returns None.
How do I find soup?
Import module. Parse the content into BeautifulSoup. Iterate the data by class name….Approach:Import module.Make requests instance and pass into URL.Pass the requests into a Beautifulsoup() function.Then we will iterate all tags and fetch class name.Nov 26, 2020
Why is it called BeautifulSoup?
It’s BeautifulSoup, and is named after so-called ‘tag soup’, which refers to “syntactically or structurally incorrect HTML written for a web page”, from the Wikipedia definition. jsoup is the Java version of Beautiful Soup.May 19, 2014