Beautifulsoup Tutorial Python 2_7


Tutorial: Web Scraping with Python Using Beautiful Soup

Tutorial: Web Scraping with Python Using Beautiful Soup

Published: March 30, 2021 Learn how to scrape the web with Python! The internet is an absolutely massive source of data — data that we can access using web scraping and Python! In fact, web scraping is often the only way we can access data. There is a lot of information out there that isn’t available in convenient CSV exports or easy-to-connect APIs. And websites themselves are often valuable sources of data — consider, for example, the kinds of analysis you could do if you could download every post on a web access those sorts of on-page datasets, we’ll have to use web scraping. Don’t worry if you’re still a total beginner! In this tutorial we’re going to cover how to do web scraping with Python from scratch, starting with some answers to frequently-asked, we’ll work through an actual web scraping project, focusing on weather ‘ll work together to scrape weather data from the web to support a weather before we start writing any Python, we’ve got to cover the basics! If you’re already familiar with the concept of web scraping, feel free to scroll past these questions and jump right into the tutorial! The Fundamentals of Web Scraping:What is Web Scraping in Python? Some websites offer data sets that are downloadable in CSV format, or accessible via an Application Programming Interface (API). But many websites with useful data don’t offer these convenient nsider, for example, the National Weather Service’s website. It contains up-to-date weather forecasts for every location in the US, but that weather data isn’t accessible as a CSV or via API. It has to be viewed on the NWS site:If we wanted to analyze this data, or download it for use in some other app, we wouldn’t want to painstakingly copy-paste everything. Web scraping is a technique that lets us use programming to do the heavy lifting. We’ll write some code that looks at the NWS site, grabs just the data we want to work with, and outputs it in the format we this tutorial, we’ll show you how to perform web scraping using Python 3 and the Beautiful Soup library. We’ll be scraping weather forecasts from the National Weather Service, and then analyzing them using the Pandas to be clear, lots of programming languages can be used to scrape the web! We also teach web scraping in R, for example. For this tutorial, though, we’ll be sticking with Does Web Scraping Work? When we scrape the web, we write code that sends a request to the server that’s hosting the page we specified. The server will return the source code — HTML, mostly — for the page (or pages) we far, we’re essentially doing the same thing a web browser does — sending a server request with a specific URL and asking the server to return the code for that unlike a web browser, our web scraping code won’t interpret the page’s source code and display the page visually. Instead, we’ll write some custom code that filters through the page’s source code looking for specific elements we’ve specified, and extracting whatever content we’ve instructed it to example, if we wanted to get all of the data from inside a table that was displayed on a web page, our code would be written to go through these steps in sequence:1Request the content (source code) of a specific URL from the server2Download the content that is returned3Identify the elements of the page that are part of the table we want4Extract and (if necessary) reformat those elements into a dataset we can analyze or use in whatever way we that all sounds very complicated, don’t worry! Python and Beautiful Soup have built-in features designed to make this relatively straightforward. One thing that’s important to note: from a server’s perspective, requesting a page via web scraping is the same as loading it in a web browser. When we use code to submit these requests, we might be “loading” pages much faster than a regular user, and thus quickly eating up the website owner’s server Use Python for Web Scraping? As previously mentioned, it’s possible to do web scraping with many programming ever, one of the most popular approaches is to use Python and the Beautiful Soup library, as we’ll do in this tutorial. Learning to do this with Python will mean that there are lots of tutorials, how-to videos, and bits of example code out there to help you deepen your knowledge once you’ve mastered the Beautiful Soup Web Scraping Legal? Unfortunately, there’s not a cut-and-dry answer here. Some websites explicitly allow web scraping. Others explicitly forbid it. Many websites don’t offer any clear guidance one way or the scraping any website, we should look for a terms and conditions page to see if there are explicit rules about scraping. If there are, we should follow them. If there are not, then it becomes more of a judgement member, though, that web scraping consumes server resources for the host website. If we’re just scraping one page once, that isn’t going to cause a problem. But if our code is scraping 1, 000 pages once every ten minutes, that could quickly get expensive for the website, in addition to following any and all explicit rules about web scraping posted on the site, it’s also a good idea to follow these best practices:Web Scraping Best Practices:Never scrape more frequently than you need nsider caching the content you scrape so that it’s only downloaded pauses into your code using functions like () to keep from overwhelming servers with too many requests too our case for this tutorial, the NWS’s data is public domain and its terms do not forbid web scraping, so we’re in the clear to to scrape the web with Python, right in your browser! Our interactive APIs and Web Scraping in Python skill path will help you learn the skills you need to unlock new worlds of data with Python. (No credit card required! ) The Components of a Web PageBefore we start writing code, we need to understand a little bit about the structure of a web page. We’ll use the site’s structure to write code that gets us the data we want to scrape, so understanding that structure is an important first step for any web scraping we visit a web page, our web browser makes a request to a web server. This request is called a GET request, since we’re getting files from the server. The server then sends back files that tell our browser how to render the page for us. These files will typically include:HTML — the main content of the — used to add styling to make the page look — Javascript files add interactivity to web — image formats, such as JPG and PNG, allow web pages to show our browser receives all the files, it renders the page and displays it to ’s a lot that happens behind the scenes to render a page nicely, but we don’t need to worry about most of it when we’re web scraping. When we perform web scraping, we’re interested in the main content of the web page, so we look primarily at the MLHyperText Markup Language (HTML) is the language that web pages are created in. HTML isn’t a programming language, like Python, though. It’s a markup language that tells a browser how to display content. HTML has many functions that are similar to what you might find in a word processor like Microsoft Word — it can make text bold, create paragraphs, and so you’re already familiar with HTML, feel free to jump to the next section of this tutorial. Otherwise, let’s take a quick tour through HTML so we know enough to scrape consists of elements called tags. The most basic tag is the tag. This tag tells the web browser that everything inside of it is HTML. We can make a simple HTML document just using this tag:We haven’t added any content to our page yet, so if we viewed our HTML document in a web browser, we wouldn’t see anything:Right inside an html tag, we can put two other tags: the head tag, and the body main content of the web page goes into the body tag. The head tag contains data about the title of the page, and other information that generally isn’t useful in web scraping:We still haven’t added any content to our page (that goes inside the body tag), so if we open this HTML file in a browser, we still won’t see anything:You may have noticed above that we put the head and body tags inside the html tag. In HTML, tags are nested, and can go inside other ’ll now add our first content to the page, inside a p tag. The p tag defines a paragraph, and any text inside the tag is shown as a separate paragraph:

Here’s a paragraph of text!

Here’s a second paragraph of text!

Rendered in a browser, that HTML file will look like this: Here’s a paragraph of text! Here’s a second paragraph of text! Tags have commonly used names that depend on their position in relation to other tags:child — a child is a tag inside another tag. So the two p tags above are both children of the body — a parent is the tag another tag is inside. Above, the html tag is the parent of the body biling — a sibiling is a tag that is nested inside the same parent as another tag. For example, head and body are siblings, since they’re both inside html. Both p tags are siblings, since they’re both inside can also add properties to HTML tags that change their behavior. Below, we’ll add some extra text and hyperlinks using the a tag.

Here’s a paragraph of text! Python

Here’s how this will look:In the above example, we added two a tags. a tags are links, and tell the browser to render a link to another web page. The href property of the tag determines where the link goes. a and p are extremely common html tags. Here are a few others:div — indicates a division, or area, of the page. b — bolds any text inside. i — italicizes any text — creates a — creates an input a full list of tags, look we move into actual web scraping, let’s learn about the class and id properties. These special properties give HTML elements names, and make them easier to interact with when we’re element can have multiple classes, and a class can be shared between elements. Each element can only have one id, and an id can only be used once on a page. Classes and ids are optional, and not all elements will have can add classes and ids to our example:

Here’s a paragraph of text! Learn Data Science Online

Here’s a second paragraph of text! Python

Here’s how this will look:As you can see, adding classes and ids doesn’t change how the tags are rendered at requests libraryNow that we understand the structure of a web page, it’s time to get into the fun part: scraping the content we want! The first thing we’ll need to do to scrape a web page is to download the page. We can download pages using the Python requests requests library will make a GET request to a web server, which will download the HTML contents of a given web page for us. There are several different types of requests we can make using requests, of which GET is just one. If you want to learn more, check out our API ’s try downloading a simple sample website, ll need to first import the requests library, and then download the page using the method:import requests
page = (“)
After running our request, we get a Response object. This object has a status_code property, which indicates if the page was downloaded successfully:A status_code of 200 means that the page downloaded successfully. We won’t fully dive into status codes here, but a status code starting with a 2 generally indicates success, and a code starting with a 4 or a 5 indicates an can print out the HTML content of the page using the content ntent

A simple example page

Here is some simple content for this page.

Parsing a page with BeautifulSoupAs you can see above, we now have downloaded an HTML can use the BeautifulSoup library to parse this document, and extract the text from the p first have to import the library, and create an instance of the BeautifulSoup class to parse our document:from bs4 import BeautifulSoup
soup = BeautifulSoup(ntent, ”)We can now print out the HTML content of the page, formatted nicely, using the prettify method on the BeautifulSoup object.
This step isn’t strictly necessary, and we won’t always bother with it, but it can be helpful to look at prettified HTML to make the structure of the and where tags are nested easier to all the tags are nested, we can move through the structure one level at a time. We can first select all the elements at the top level of the page using the children property of soup. Note that children returns a list generator, so we need to call the list function on it:list(ildren)
[‘html’, ‘n’, A simple example page

Here is some simple content for this page.

]The above tells us that there are two tags at the top level of the page — the initial tag, and the tag. There is a newline character (n) in the list as well. Let’s see what the type of each element in the list is:[type(item) for item in list(ildren)]
[ctype, vigableString, ]As we can see, all of the items are BeautifulSoup objects:The first is a Doctype object, which contains information about the type of the second is a NavigableString, which represents text found in the HTML final item is a Tag object, which contains other nested most important object type, and the one we’ll deal with most often, is the Tag Tag object allows us to navigate through an HTML document, and extract other tags and text. You can learn more about the various BeautifulSoup objects can now select the html tag and its children by taking the third item in the list:html = list(ildren)[2]Each item in the list returned by the children property is also a BeautifulSoup object, so we can also call the children method on, we can find the children inside the html tag:list(ildren)
[‘n’, A simple example page , ‘n’,

Here is some simple content for this page.

, ‘n’]As we can see above, there are two tags here, head, and body. We want to extract the text inside the p tag, so we’ll dive into the body:body = list(ildren)[3]Now, we can get the p tag by finding the children of the body tag:list(ildren)

Here is some simple content for this page.

, ‘n’]We can now isolate the p tag:p = list(ildren)[1]Once we’ve isolated the tag, we can use the get_text method to extract all of the text inside the t_text()
‘Here is some simple content for this page. ‘Finding all instances of a tag at onceWhat we did above was useful for figuring out how to navigate a page, but it took a lot of commands to do something fairly simple. If we want to extract a single tag, we can instead use the find_all method, which will find all the instances of a tag on a = BeautifulSoup(ntent, ”)

Here is some simple content for this page.

]Note that find_all returns a list, so we’ll have to loop through, or use list indexing, it to extract nd_all(‘p’)[0]. get_text()
‘Here is some simple content for this page. ‘f you instead only want to find the first instance of a tag, you can use the find method, which will return a single BeautifulSoup (‘p’)

Here is some simple content for this page.

Searching for tags by class and idWe introduced classes and ids earlier, but it probably wasn’t clear why they were asses and ids are used by CSS to determine which HTML elements to apply certain styles to. But when we’re scraping, we can also use them to specify the elements we want to illustrate this principle, we’ll work with the following page:

First paragraph.

Second paragraph.

First outer paragraph.

Second outer paragraph.
We can access the above document at the URL. Let’s first download the page and create a BeautifulSoup object:page = (“)
soup = BeautifulSoup(ntent, ”)
A simple example page<br />

Now, we can use the find_all method to search for items by class or by id. In the below example, we’ll search for any p tag that has the class nd_all(‘p’, class_=’outer-text’)

First outer paragraph.


Second outer paragraph.

]In the below example, we’ll look for any tag that has the class nd_all(class_=”outer-text”)


]We can also search for elements by nd_all(id=”first”)

]Using CSS SelectorsWe can also search for items using CSS selectors. These selectors are how the CSS language allows developers to specify HTML tags to style. Here are some examples:p a — finds all a tags inside of a p p a — finds all a tags inside of a p tag inside of a body body — finds all body tags inside of an html — finds all p tags with a class of outer-text. p#first — finds all p tags with an id of — finds any p tags with a class of outer-text inside of a body can learn more about CSS selectors autifulSoup objects support searching a page via CSS selectors using the select method. We can use CSS selectors to find all the p tags in our page that are inside of a div like (“div p”)


]Note that the select method above returns a list of BeautifulSoup objects, just like find and wnloading weather dataWe now know enough to proceed with extracting information about the local weather from the National Weather Service website! The first step is to find the page we want to scrape. We’ll extract weather information about downtown San Francisco from this page. Specifically, let’s extract data about the extended we can see from the image, the page has information about the extended forecast for the next week, including time of day, temperature, and a brief description of the conditions. Exploring page structure with Chrome DevToolsThe first thing we’ll need to do is inspect the page using Chrome Devtools. If you’re using another browser, Firefox and Safari have can start the developer tools in Chrome by clicking View -> Developer -> Developer Tools. You should end up with a panel at the bottom of the browser like what you see below. Make sure the Elements panel is highlighted:Chrome Developer ToolsThe elements panel will show you all the HTML tags on the page, and let you navigate through them. It’s a really handy feature! By right clicking on the page near where it says “Extended Forecast”, then clicking “Inspect”, we’ll open up the tag that contains the text “Extended Forecast” in the elements panel:The extended forecast textWe can then scroll up in the elements panel to find the “outermost” element that contains all of the text that corresponds to the extended forecasts. In this case, it’s a div tag with the id seven-day-forecast:The div that contains the extended forecast we click around on the console, and explore the div, we’ll discover that each forecast item (like “Tonight”, “Thursday”, and “Thursday Night”) is contained in a div with the class to Start Scraping! We now know enough to download the page and start parsing it. In the below code, we will:Download the web page containing the a BeautifulSoup class to parse the the div with id seven-day-forecast, and assign to seven_dayInside seven_day, find each individual forecast item. Extract and print the first forecast = (“)
seven_day = (id=”seven-day-forecast”)
forecast_items = nd_all(class_=”tombstone-container”)
tonight = forecast_items[0]


Tonight: Mostly clear, with a low around 49. West northwest wind 12 to 17 mph decreasing to 6 to 11 mph after midnight. Winds could gust as high as 23 mph.

Mostly Clear

Low: 49 °F

Extracting information from the pageAs we can see, inside the forecast item tonight is all the information we want. There are four pieces of information we can extract:The name of the forecast item — in this case, description of the conditions — this is stored in the title property of img. A short description of the conditions — in this case, Mostly temperature low — in this case, 49 ’ll extract the name of the forecast item, the short description, and the temperature first, since they’re all similar:period = (class_=”period-name”). get_text()
short_desc = (class_=”short-desc”). get_text()
temp = (class_=”temp”). get_text()
Low: 49 °FNow, we can extract the title attribute from the img tag. To do this, we just treat the BeautifulSoup object like a dictionary, and pass in the attribute we want as a key:img = (“img”)
desc = img[‘title’]
Tonight: Mostly clear, with a low around 49. Extracting all the information from the pageNow that we know how to extract each individual piece of information, we can combine our knowledge with CSS selectors and list comprehensions to extract everything at the below code, we will:Select all items with the class period-name inside an item with the class tombstone-container in a list comprehension to call the get_text method on each BeautifulSoup riod_tags = (“. tombstone-container “)
periods = [t_text() for pt in period_tags]
‘SundayNight’]As we can see above, our technique gets us each of the period names, in order. We can apply the same technique to get the other three fields:short_descs = [t_text() for sd in (“. tombstone-container “)]
temps = [t_text() for t in (“. tombstone-container “)]
descs = [d[“title”] for d in (“. tombstone-container img”)]print(short_descs)print(temps)print(descs)
[‘Mostly Clear’, ‘Sunny’, ‘Mostly Clear’, ‘Sunny’, ‘Slight ChanceRain’, ‘Rain Likely’, ‘Rain Likely’, ‘Rain Likely’, ‘Chance Rain’]
[‘Low: 49 °F’, ‘High: 63 °F’, ‘Low: 50 °F’, ‘High: 67 °F’, ‘Low: 57 °F’, ‘High: 64 °F’, ‘Low: 57 °F’, ‘High: 64 °F’, ‘Low: 55 °F’]
[‘Tonight: Mostly clear, with a low around 49. ‘, ‘Thursday: Sunny, with a high near 63. North wind 3 to 5 mph. ‘, ‘Thursday Night: Mostly clear, with a low around 50. Light and variable wind becoming east southeast 5 to 8 mph after midnight. ‘, ‘Friday: Sunny, with a high near 67. Southeast wind around 9 mph. ‘, ‘Friday Night: A 20 percent chance of rain after 11pm. Partly cloudy, with a low around 57. South southeast wind 13 to 15 mph, with gusts as high as 20 mph. New precipitation amounts of less than a tenth of an inch possible. ‘, ‘Saturday: Rain likely. Cloudy, with a high near 64. Chance of precipitation is 70%. New precipitation amounts between a quarter and half of an inch possible. ‘, ‘Saturday Night: Rain likely. Cloudy, with a low around 57. Chance of precipitation is 60%. ‘, ‘Sunday: Rain likely. ‘, ‘Sunday Night: A chance of rain. Mostly cloudy, with a low around 55. ‘]Combining our data into a Pandas DataframeWe can now combine the data into a Pandas DataFrame and analyze it. A DataFrame is an object that can store tabular data, making data analysis easy. If you want to learn more about Pandas, check out our free to start course order to do this, we’ll call the DataFrame class, and pass in each list of items that we have. We pass them in as part of a dictionary key will become a column in the DataFrame, and each list will become the values in the column:import pandas as pd
weather = Frame({
“period”: periods,
“short_desc”: short_descs,
“temp”: temps,
Tonight: Mostly clear, with a low around 49. W…
Thursday: Sunny, with a high near 63. North wi…
High: 63 °F
Thursday Night: Mostly clear, with a low aroun…
Low: 50 °F
Friday: Sunny, with a high near 67. Southeast …
High: 67 °F
Friday Night: A 20 percent chance of rain afte…
Slight ChanceRain
Low: 57 °F
Saturday: Rain likely. Cloudy, with a high ne…
Rain Likely
High: 64 °F
Saturday Night: Rain likely. Cloudy, with a l…
Sunday: Rain likely. Cloudy, with a high near…
Sunday Night: A chance of rain. Mostly cloudy…
Chance Rain
Low: 55 °F
We can now do some analysis on the data. For example, we can use a regular expression and the method to pull out the numeric temperature values:temp_nums = weather[“temp”](“(? Pd+)”, expand=False)
weather[“temp_num”] = (‘int’)
0 49
1 63
2 50
3 67
4 57
5 64
6 57
7 64
8 55
Name: temp_num, dtype: objectWe could then find the mean of all the high and low temperatures:weather[“temp_num”]()
58. 444444444444443We could also only select the rows that happen at night:is_night = weather[“temp”](“Low”)
weather[“is_night”] = is_night
0 True
1 False
2 True
3 False
4 True
5 False
6 True
7 False
8 True
Name: temp, dtype: boolweather[is_night]
Name: temp, dtype: bool
Next Steps For This Web Scraping ProjectIf you’ve made it this far, congratulations! You should now have a good understanding of how to scrape web pages and extract data. Of course, there’s still a lot more to learn! If you want to go further, a good next step would be to pick a site and try some web scraping on your own. Some good examples of data to scrape are:News articlesSports scoresWeather forecastsStock pricesOnline retailer pricesYou may also want to keep scraping the National Weather Service, and see what other data you can extract from the page, or about your own ternatively, if you want to take your web scraping skills to the next level, you can check out our interactive course, which covers both the basics of web scraping and using Python to connect to APIs. With those two skills under your belt, you’ll be able to collect lots of unique and interesting datasets from sites all over the web! Learn to scrape the web with Python, right in your browser! Our interactive APIs and Web Scraping in Python skill path will help you learn the skills you need to unlock new worlds of data with Python. (No credit card required! )beginner, data mining, python, python tutorials, scraping, tutorial, Tutorials, web scraping
Beautiful Soup 4.9.0 documentation - Crummy

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

The Dormouse’s story

Once upon a time there were three little sisters; and their names were
Lacie and
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, ”)
# <br /> # The Dormouse’s story<br /> #




# 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:
# The Dormouse’s story
# u’title’
# u’The Dormouse’s story’
# u’head’
soup. p

The Dormouse’s story

soup. p[‘class’]
soup. a
# [Elsie,
# Lacie,
# Tillie]
# Tillie
One common task is extracting all the URLs found within a page’s tags:
for link in nd_all(‘a’):
# # #
Another common task is extracting all the text from a page:
# 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
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:
Typical usage
BeautifulSoup(markup, “”)
Batteries included
Decent speed
Lenient (As of Python 2. 7. 3
and 3. 2. )
Not as fast as lxml,
less lenient than
lxml’s HTML parser
BeautifulSoup(markup, “lxml”)
Very fast
External C dependency
lxml’s XML parser
BeautifulSoup(markup, “lxml-xml”)
BeautifulSoup(markup, “xml”)
The only currently supported
XML parser
BeautifulSoup(markup, “html5lib”)
Extremely lenient
Parses pages the same way a
web browser does
Creates valid HTML5
Very slow
External Python
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.
A Tag object corresponds to an XML or HTML tag in the original document:
soup = BeautifulSoup(‘Extremely bold‘, ”)
tag = soup. b
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.
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”

Extremely bold

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
# ‘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’
# 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
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:
# [“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)
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
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’
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()
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.
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(“INSERT FOOTER HEREHere’s the footer

“, “xml”)
(text=”INSERT FOOTER HERE”). replace_with(footer)

Here’s the footer

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
Here’s the “Three sisters” HTML document again:
html_doc = “””
The Dormouse’s story
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
# The Dormouse’s story
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
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 =
# [The Dormouse’s story]
title_tag = ntents[0]
# [‘The Dormouse’s story’]
The BeautifulSoup object itself has children. In this case, the
tag is the child of the BeautifulSoup object. :
# 1
# ‘html’
A string does not have. contents, because it can’t contain
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:
# 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 tag:<br /> But the <title> tag itself has a child: the string “The Dormouse’s<br /> story”. There’s a sense in which that string is also a child of the<br /> <head> tag. The. descendants attribute lets you iterate over all<br /> of a tag’s children, recursively: its direct children, the children of<br /> its direct children, and so on:<br /> for child in scendants:<br /> The <head> tag has only one child, but it has two descendants: the<br /> <title> tag and the <title> tag’s child. The BeautifulSoup object<br /> only has one direct child (the <html> tag), but it has a whole lot of<br /> descendants:<br /> len(list(ildren))<br /> len(list(scendants))<br /> # 26<br /> ¶<br /> If a tag has only one child, and that child is a NavigableString,<br /> the child is made available as<br /> # ‘The Dormouse’s story’<br /> If a tag’s only child is another tag, and that tag has a, then the parent tag is considered to have the same<br /> as its child:<br /> If a tag contains more than one thing, then it’s not clear what<br /> should refer to, so is defined to be<br /> None:<br /> print()<br /> # None. strings and stripped_strings¶<br /> If there’s more than one thing inside a tag, you can still look at<br /> just the strings. Use the. strings generator:<br /> for string in rings:<br /> print(repr(string))<br /> ‘\n’<br /> # “The Dormouse’s story”<br /> # ‘\n’<br /> # ‘Once upon a time there were three little sisters; and their names were\n’<br /> # ‘Elsie’<br /> # ‘, \n’<br /> # ‘Lacie’<br /> # ‘ and\n’<br /> # ‘Tillie’<br /> # ‘;\nand they lived at the bottom of a well. ‘<br /> # ‘… ‘<br /> These strings tend to have a lot of extra whitespace, which you can<br /> remove by using the. stripped_strings generator instead:<br /> for string in ripped_strings:<br /> # ‘Once upon a time there were three little sisters; and their names were’<br /> # ‘, ‘<br /> # ‘and’<br /> # ‘;\n and they lived at the bottom of a well. ‘<br /> Here, strings consisting entirely of whitespace are ignored, and<br /> whitespace at the beginning and end of strings is removed.<br /> Going up¶<br /> Continuing the “family tree” analogy, every tag and every string has a<br /> parent: the tag that contains it.<br /> You can access an element’s parent with the attribute. In<br /> the example “three sisters” document, the <head> tag is the parent<br /> of the <title> tag:<br /> title_tag =<br /> The title string itself has a parent: the <title> tag that contains<br /> it:<br /> The parent of a top-level tag like <html> is the BeautifulSoup object<br /> itself:<br /> html_tag =<br /> # <class 'autifulSoup'><br /> And the of a BeautifulSoup object is defined as None:<br /> # None. parents¶<br /> You can iterate over all of an element’s parents with. parents. This example uses. parents to travel from an <a> tag<br /> buried deep within the document, to the very top of the document:<br /> link = soup. a<br /> link<br /> for parent in rents:<br /> # p<br /> # body<br /> # html<br /> # [document]<br /> Going sideways¶<br /> Consider a simple document like this:<br /> sibling_soup = BeautifulSoup(“<a><b>text1</b><c>text2</c></b></a>“, ”)<br /> # <a><br /> # text1<br /> # <c><br /> # text2<br /> # </c><br /> The <b> tag and the <c> tag are at the same level: they’re both direct<br /> children of the same tag. We call them siblings. When a document is<br /> pretty-printed, siblings show up at the same indentation level. You<br /> can also use this relationship in the code you write.. next_sibling and. previous_sibling¶<br /> You can use. previous_sibling to navigate<br /> between page elements that are on the same level of the parse tree:<br /> xt_sibling<br /> # <c>text2</c><br /> evious_sibling<br /> # <b>text1</b><br /> The <b> tag has a. next_sibling, but no. previous_sibling,<br /> because there’s nothing before the <b> tag on the same level of the<br /> tree. For the same reason, the <c> tag has a. previous_sibling<br /> but no. next_sibling:<br /> print(evious_sibling)<br /> print(xt_sibling)<br /> The strings “text1” and “text2” are not siblings, because they don’t<br /> have the same parent:<br /> # ‘text1’<br /> In real documents, the. next_sibling or. previous_sibling of a<br /> tag will usually be a string containing whitespace. Going back to the<br /> “three sisters” document:<br /> # <a href=" class="sister" id="link1">Elsie</a><br /> # <a href=" class="sister" id="link2">Lacie</a><br /> # <a href=" class="sister" id="link3">Tillie</a><br /> You might think that the. next_sibling of the first <a> tag would<br /> be the second <a> tag. But actually, it’s a string: the comma and<br /> newline that separate the first <a> tag from the second:<br /> # ‘, \n ‘<br /> The second <a> tag is actually the. next_sibling of the comma:<br /> # <a class="sister" href=" id="link2">Lacie</a>. next_siblings and. previous_siblings¶<br /> You can iterate over a tag’s siblings with. next_siblings or. previous_siblings:<br /> for sibling in xt_siblings:<br /> print(repr(sibling))<br /> # <a class="sister" href=" id="link2">Lacie</a><br /> # ‘; and they lived at the bottom of a well. ‘<br /> for sibling in (id=”link3″). previous_siblings:<br /> Going back and forth¶<br /> Take a look at the beginning of the “three sisters” document:<br /> # <html><head><title>The Dormouse’s story
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”, “add a string”, “close the <title> tag”, “open a </p> <p> tag”, and so on. Beautiful Soup offers tools for reconstructing the<br /> initial parse of the document.. next_element and. previous_element¶<br /> The. next_element attribute of a string or tag points to whatever<br /> was parsed immediately afterwards. It might be the same as. next_sibling, but it’s usually drastically different.<br /> Here’s the final <a> tag in the “three sisters” document. Its. next_sibling is a string: the conclusion of the sentence that was<br /> interrupted by the start of the <a> tag. :<br /> last_a_tag = (“a”, id=”link3″)<br /> last_a_tag<br /> But the. next_element of that <a> tag, the thing that was parsed<br /> immediately after the <a> tag, is not the rest of that sentence:<br /> it’s the word “Tillie”:<br /> xt_element<br /> That’s because in the original markup, the word “Tillie” appeared<br /> before that semicolon. The parser encountered an <a> tag, then the<br /> word “Tillie”, then the closing </a> tag, then the semicolon and rest of<br /> the sentence. The semicolon is on the same level as the <a> tag, but the<br /> word “Tillie” was encountered first.<br /> The. previous_element attribute is the exact opposite of. next_element. It points to whatever element was parsed<br /> immediately before this one:<br /> evious_element<br /> # <a class="sister" href=" id="link3">Tillie</a>. next_elements and. previous_elements¶<br /> You should get the idea by now. You can use these iterators to move<br /> forward or backward in the document as it was parsed:<br /> for element in xt_elements:<br /> print(repr(element))<br /> # </p> <p class="story">… </p> <p>Beautiful Soup defines a lot of methods for searching the parse tree,<br /> but they’re all very similar. I’m going to spend a lot of time explaining<br /> the two most popular methods: find() and find_all(). The other<br /> methods take almost exactly the same arguments, so I’ll just cover<br /> them briefly.<br /> Once again, I’ll be using the “three sisters” document as an example:<br /> By passing in a filter to an argument like find_all(), you can<br /> zoom in on the parts of the document you’re interested in.<br /> Kinds of filters¶<br /> Before talking in detail about find_all() and similar methods, I<br /> want to show examples of different filters you can pass into these<br /> methods. These filters show up again and again, throughout the<br /> search API. You can use them to filter based on a tag’s name,<br /> on its attributes, on the text of a string, or on some combination of<br /> these.<br /> A string¶<br /> The simplest filter is a string. Pass a string to a search method and<br /> Beautiful Soup will perform a match against that exact string. This<br /> code finds all the <b> tags in the document:<br /> nd_all(‘b’)<br /> # [<b>The Dormouse’s story</b>]<br /> If you pass in a byte string, Beautiful Soup will assume the string is<br /> encoded as UTF-8. You can avoid this by passing in a Unicode string instead.<br /> A regular expression¶<br /> If you pass in a regular expression object, Beautiful Soup will filter<br /> against that regular expression using its search() method. This code<br /> finds all the tags whose names start with the letter “b”; in this<br /> case, the <body> tag and the <b> tag:<br /> import re<br /> for tag in nd_all(mpile(“^b”)):<br /> # b<br /> This code finds all the tags whose names contain the letter ‘t’:<br /> for tag in nd_all(mpile(“t”)):<br /> # title<br /> A list¶<br /> If you pass in a list, Beautiful Soup will allow a string match<br /> against any item in that list. This code finds all the <a> tags<br /> and all the <b> tags:<br /> nd_all([“a”, “b”])<br /> # [<b>The Dormouse’s story</b>,<br /> # <a class="sister" href=" id="link1">Elsie</a>,<br /> True¶<br /> The value True matches everything it can. This code finds all<br /> the tags in the document, but none of the text strings:<br /> for tag in nd_all(True):<br /> # head<br /> # a<br /> A function¶<br /> If none of the other matches work for you, define a function that<br /> takes an element as its only argument. The function should return<br /> True if the argument matches, and False otherwise.<br /> Here’s a function that returns True if a tag defines the “class”<br /> attribute but doesn’t define the “id” attribute:<br /> def has_class_but_no_id(tag):<br /> return tag. has_attr(‘class’) and not tag. has_attr(‘id’)<br /> Pass this function into find_all() and you’ll pick up all the </p> <p> tags:<br /> nd_all(has_class_but_no_id)<br /> # [</p> <p class="title"><b>The Dormouse’s story</b></p> <p>,<br /> # </p> <p class="story">Once upon a time there were…bottom of a well. </p> <p>,<br /> # </p> <p class="story">… </p> <p>]<br /> This function only picks up the </p> <p> tags. It doesn’t pick up the <a><br /> tags, because those tags define both “class” and “id”. It doesn’t pick<br /> up tags like <html> and <title>, because those tags don’t define<br /> “class”.<br /> If you pass in a function to filter on a specific attribute like<br /> href, the argument passed into the function will be the attribute<br /> value, not the whole tag. Here’s a function that finds all a tags<br /> whose href attribute does not match a regular expression:<br /> def not_lacie(href):<br /> return href and not mpile(“lacie”)(href)<br /> nd_all(href=not_lacie)<br /> The function can be as complicated as you need it to be. Here’s a<br /> function that returns True if a tag is surrounded by string<br /> objects:<br /> from bs4 import NavigableString<br /> def surrounded_by_strings(tag):<br /> return (isinstance(xt_element, NavigableString)<br /> and isinstance(evious_element, NavigableString))<br /> for tag in nd_all(surrounded_by_strings):<br /> Now we’re ready to look at the search methods in detail.<br /> find_all()¶<br /> Method signature: find_all(name, attrs, recursive, string, limit, **kwargs)<br /> The find_all() method looks through a tag’s descendants and<br /> retrieves all descendants that match your filters. I gave several<br /> examples in Kinds of filters, but here are a few more:<br /> nd_all(“title”)<br /> nd_all(“p”, “title”)<br /> # [</p> <p class="title"><b>The Dormouse’s story</b></p> <p>]<br /> nd_all(“a”)<br /> nd_all(id=”link2″)<br /> # [<a class="sister" href=" id="link2">Lacie</a>]<br /> (mpile(“sisters”))<br /> Some of these should look familiar, but others are new. What does it<br /> mean to pass in a value for string, or id? Why does<br /> find_all(“p”, “title”) find a </p> <p> tag with the CSS class “title”?<br /> Let’s look at the arguments to find_all().<br /> The name argument¶<br /> Pass in a value for name and you’ll tell Beautiful Soup to only<br /> consider tags with certain names. Text strings will be ignored, as<br /> will tags whose names that don’t match.<br /> This is the simplest usage:<br /> Recall from Kinds of filters that the value to name can be a<br /> string, a regular expression, a list, a function, or the value<br /> True.<br /> The keyword arguments¶<br /> Any argument that’s not recognized will be turned into a filter on one<br /> of a tag’s attributes. If you pass in a value for an argument called id,<br /> Beautiful Soup will filter against each tag’s ‘id’ attribute:<br /> nd_all(id=’link2′)<br /> If you pass in a value for href, Beautiful Soup will filter<br /> against each tag’s ‘href’ attribute:<br /> nd_all(mpile(“elsie”))<br /> # [<a class="sister" href=" id="link1">Elsie</a>]<br /> You can filter an attribute based on a string, a regular<br /> expression, a list, a function, or the value True.<br /> This code finds all tags whose id attribute has a value,<br /> regardless of what the value is:<br /> nd_all(id=True)<br /> You can filter multiple attributes at once by passing in more than one<br /> keyword argument:<br /> nd_all(mpile(“elsie”), id=’link1′)<br /> Some attributes, like the data-* attributes in HTML 5, have names that<br /> can’t be used as the names of keyword arguments:<br /> data_soup = BeautifulSoup(‘</p> <div data-foo="value">foo! </div> <p>‘, ”)<br /> nd_all(data-foo=”value”)<br /> # SyntaxError: keyword can’t be an expression<br /> You can use these attributes in searches by putting them into a<br /> dictionary and passing the dictionary into find_all() as the<br /> attrs argument:<br /> nd_all(attrs={“data-foo”: “value”})<br /> # [</p> <div data-foo="value">foo! </div> <p>]<br /> You can’t use a keyword argument to search for HTML’s ‘name’ element,<br /> because Beautiful Soup uses the name argument to contain the name<br /> of the tag itself. Instead, you can give a value to ‘name’ in the<br /> name_soup = BeautifulSoup(‘<input name="email"/>‘, ”)<br /> nd_all(name=”email”)<br /> # []<br /> nd_all(attrs={“name”: “email”})<br /> # [<input name="email"/>]<br /> Searching by CSS class¶<br /> It’s very useful to search for a tag that has a certain CSS class, but<br /> the name of the CSS attribute, “class”, is a reserved word in<br /> Python. Using class as a keyword argument will give you a syntax<br /> error. As of Beautiful Soup 4. 1. 2, you can search by CSS class using<br /> the keyword argument class_:<br /> nd_all(“a”, class_=”sister”)<br /> As with any keyword argument, you can pass class_ a string, a regular<br /> expression, a function, or True:<br /> nd_all(mpile(“itl”))<br /> def has_six_characters(css_class):<br /> return css_class is not None and len(css_class) == 6<br /> nd_all(class_=has_six_characters)<br /> Remember that a single tag can have multiple<br /> values for its “class” attribute. When you search for a tag that<br /> matches a certain CSS class, you’re matching against any of its CSS<br /> classes:<br /> nd_all(“p”, class_=”strikeout”)<br /> # [</p> <p class="body strikeout"> <p>]<br /> nd_all(“p”, class_=”body”)<br /> You can also search for the exact string value of the class attribute:<br /> nd_all(“p”, class_=”body strikeout”)<br /> But searching for variants of the string value won’t work:<br /> nd_all(“p”, class_=”strikeout body”)<br /> If you want to search for tags that match two or more CSS classes, you<br /> should use a CSS selector:<br /> (“p. “)<br /> In older versions of Beautiful Soup, which don’t have the class_<br /> shortcut, you can use the attrs trick mentioned above. Create a<br /> dictionary whose value for “class” is the string (or regular<br /> expression, or whatever) you want to search for:<br /> nd_all(“a”, attrs={“class”: “sister”})<br /> The string argument¶<br /> With string you can search for strings instead of tags. As with<br /> name and the keyword arguments, you can pass in a string, a<br /> regular expression, a list, a function, or the value True.<br /> Here are some examples:<br /> nd_all(string=”Elsie”)<br /> # [‘Elsie’]<br /> nd_all(string=[“Tillie”, “Elsie”, “Lacie”])<br /> # [‘Elsie’, ‘Lacie’, ‘Tillie’]<br /> nd_all(mpile(“Dormouse”))<br /> # [“The Dormouse’s story”, “The Dormouse’s story”]<br /> def is_the_only_string_within_a_tag(s):<br /> “””Return True if this string is the only child of its parent tag. “””<br /> return (s ==)<br /> nd_all(string=is_the_only_string_within_a_tag)<br /> # [“The Dormouse’s story”, “The Dormouse’s story”, ‘Elsie’, ‘Lacie’, ‘Tillie’, ‘… ‘]<br /> Although string is for finding strings, you can combine it with<br /> arguments that find tags: Beautiful Soup will find all tags whose<br /> matches your value for string. This code finds the <a><br /> tags whose is “Elsie”:<br /> nd_all(“a”, string=”Elsie”)<br /> # [<a href=" class="sister" id="link1">Elsie</a>]<br /> The string argument is new in Beautiful Soup 4. 4. 0. In earlier<br /> versions it was called text:<br /> nd_all(“a”, text=”Elsie”)<br /> The limit argument¶<br /> find_all() returns all the tags and strings that match your<br /> filters. This can take a while if the document is large. If you don’t<br /> need all the results, you can pass in a number for limit. This<br /> works just like the LIMIT keyword in SQL. It tells Beautiful Soup to<br /> stop gathering results after it’s found a certain number.<br /> There are three links in the “three sisters” document, but this code<br /> only finds the first two:<br /> nd_all(“a”, limit=2)<br /> # <a class="sister" href=" id="link2">Lacie</a>]<br /> The recursive argument¶<br /> If you call nd_all(), Beautiful Soup will examine all the<br /> descendants of mytag: its children, its children’s children, and<br /> so on. If you only want Beautiful Soup to consider direct children,<br /> you can pass in recursive=False. See the differe<br /> <img decoding="async" src="" alt="Collecting Data from the Web with Python and Beautiful Soup" title="Collecting Data from the Web with Python and Beautiful Soup" /></p> <h2>Collecting Data from the Web with Python and Beautiful Soup</h2> <p>Introduction<br /> Many data analysis, big data, and machine learning projects require scraping websites to gather the data that you’ll be working with. The Python programming language is widely used in the data science community, and therefore has an ecosystem of modules and tools that you can use in your own projects. In this tutorial we will be focusing on the Beautiful Soup module.<br /> Beautiful Soup, an allusion to the Mock Turtle’s song found in Chapter 10 of Lewis Carroll’s Alice’s Adventures in Wonderland, is a Python library that allows for quick turnaround on web scraping projects. Currently available as Beautiful Soup 4 and compatible with both Python 2. 7 and Python 3, Beautiful Soup creates a parse tree from parsed HTML and XML documents (including documents with non-closed tags or tag soup and other malformed markup).<br /> In this tutorial, we will collect and parse a web page in order to grab textual data and write the information we have gathered to a CSV file.<br /> Prerequisites<br /> Before working on this tutorial, you should have a local or server-based Python programming environment set up on your machine.<br /> You should have the Requests and Beautiful Soup modules installed, which you can achieve by following our tutorial “How To Work with Web Data Using Requests and Beautiful Soup with Python 3. ” It would also be useful to have a working familiarity with these modules.<br /> Additionally, since we will be working with data scraped from the web, you should be comfortable with HTML structure and tagging.<br /> Understanding the Data<br /> In this tutorial, we’ll be working with data from the official website of the National Gallery of Art in the United States. The National Gallery is an art museum located on the National Mall in Washington, D. C. It holds over 120, 000 pieces dated from the Renaissance to the present day done by more than 13, 000 artists.<br /> We would like to search the Index of Artists, which, at the time of updating this tutorial, is available via the Internet Archive’s Wayback Machine at the following URL:<br /> Note: The long URL above is due to this website having been archived by the Internet Archive.<br /> The Internet Archive is a non-profit digital library that provides free access to internet sites and other digital media. This organization takes snapshots of websites to preserve sites’ histories, and we can currently access an older version of the National Gallery’s site that was available when this tutorial was first written. The Internet Archive is a good tool to keep in mind when doing any kind of historical data scraping, including comparing across iterations of the same site and available neath the Internet Archive’s header, you’ll see a page that looks like this:<br /> Since we’ll be doing this project in order to learn about web scraping with Beautiful Soup, we don’t need to pull too much data from the site, so let’s limit the scope of the artist data we are looking to scrape. Let’s therefore choose one letter — in our example we’ll choose the letter Z — and we’ll see a page that looks like this:<br /> In the page above, we see that the first artist listed at the time of writing is Zabaglia, Niccola, which is a good thing to note for when we start pulling data. We’ll start by working with this first page, with the following URL for the letter Z:<br /> It is important to note for later how many pages total there are for the letter you are choosing to list, which you can discover by clicking through to the last page of artists. In this case, there are 4 pages total, and the last artist listed at the time of writing is Zykmund, Václav. The last page of Z artists has the following URL:<br /> However, you can also access the above page by using the same Internet Archive numeric string of the first page:<br /> This is important to note because we’ll be iterating through these pages later in this tutorial.<br /> To begin to familiarize yourself with how this web page is set up, you can take a look at its DOM, which will help you understand how the HTML is structured. In order to inspect the DOM, you can open your browser’s Developer Tools.<br /> Importing the Libraries<br /> To begin our coding project, let’s activate our Python 3 programming environment. Make sure you’re in the directory where your environment is located, and run the following command:. my_env/bin/activate<br /> With our programming environment activated, we’ll create a new file, with nano for instance. You can name your file whatever you would like, we’ll call it in this tutorial.<br /> nano<br /> Within this file, we can begin to import the libraries we’ll be using — Requests and Beautiful Soup.<br /> The Requests library allows you to make use of HTTP within your Python programs in a human readable way, and the Beautiful Soup module is designed to get web scraping done quickly.<br /> We will import both Requests and Beautiful Soup with the import statement. For Beautiful Soup, we’ll be importing it from bs4, the package in which Beautiful Soup 4 is found.<br /> Import libraries<br /> import requests<br /> from bs4 import BeautifulSoup<br /> With both the Requests and Beautiful Soup modules imported, we can move on to working to first collect a page and then parse it.<br /> Collecting and Parsing a Web Page<br /> The next step we will need to do is collect the URL of the first web page with Requests. We’ll assign the URL for the first page to the variable page by using the method ().<br /> # Collect first page of artists’ list<br /> page = (”)<br /> Note: Because the URL is lengthy, the code above and throughout this tutorial will not pass PEP 8 E501 which flags lines longer than 79 characters. You may want to assign the URL to a variable to make the code more readable in final versions. The code in this tutorial is for demonstration purposes and will allow you to swap out shorter URLs as part of your own projects.<br /> We’ll now create a BeautifulSoup object, or a parse tree. This object takes as its arguments the document from Requests (the content of the server’s response) and then parses it from Python’s built-in<br /> # Create a BeautifulSoup object<br /> soup = BeautifulSoup(, ”)<br /> With our page collected, parsed, and set up as a BeautifulSoup object, we can move on to collecting the data that we would like.<br /> Pulling Text From a Web Page<br /> For this project, we’ll collect artists’ names and the relevant links available on the website. You may want to collect different data, such as the artists’ nationality and dates. Whatever data you would like to collect, you need to find out how it is described by the DOM of the web page.<br /> To do this, in your web browser, right-click — or CTRL + click on macOS — on the first artist’s name, Zabaglia, Niccola. Within the context menu that pops up, you should see a menu item similar to Inspect Element (Firefox) or Inspect (Chrome).<br /> Once you click on the relevant Inspect menu item, the tools for web developers should appear within your browser. We want to look for the class and tags associated with the artists’ names in this list.<br /> We’ll see first that the table of names is within </p> <div> tags where class=”BodyText”. This is important to note so that we only search for text within this section of the web page. We also notice that the name Zabaglia, Niccola is in a link tag, since the name references a web page that describes the artist. So we will want to reference the <a> tag for links. Each artist’s name is a reference to a link.<br /> To do this, we’ll use Beautiful Soup’s find() and find_all() methods in order to pull the text of the artists’ names from the BodyText </p> <div>.<br /> # Collect and parse first page<br /> # Pull all text from the BodyText div<br /> artist_name_list = (class_=’BodyText’)<br /> # Pull text from all instances of <a> tag within BodyText div<br /> artist_name_list_items = nd_all(‘a’)<br /> Next, at the bottom of our program file, we will want to create a for loop in order to iterate over all the artist names that we just put into the artist_name_list_items variable.<br /> We’ll print these names out with the prettify() method in order to turn the Beautiful Soup parse tree into a nicely formatted Unicode string.<br /> # Create for loop to print out all artists’ names<br /> for artist_name in artist_name_list_items:<br /> print(ettify())<br /> Let’s run the program as we have it so far:<br /> python<br /> Once we do so, we’ll receive the following output:<br /> Output<a href="/web/20121007172955/><br /> Zabaglia, Niccola<br /> </a>…<br /> <a href="/web/20121007172955/><br /> Zao Wou-Ki<br /> </a><br /> Zas-Zie<br /> Zie-Zor<br /> <strong><br /> next<br /> <br /> page<br /> </strong><br /> What we see in the output at this point is the full text and tags related to all of the artists’ names within the <a> tags found in the </p> <div class="BodyText"> tag on the first page, as well as some additional link text at the bottom. Since we don’t want this extra information, let’s work on removing this in the next section.<br /> Removing Superfluous Data<br /> So far, we have been able to collect all the link text data within one </p> <div> section of our web page. However, we don’t want to have the bottom links that don’t reference artists’ names, so let’s work to remove that part.<br /> In order to remove the bottom links of the page, let’s again right-click and Inspect the DOM. We’ll see that the links on the bottom of the </p> <div class="BodyText"> section are contained in an HTML table: </p> <table class="AlphaNav">:<br /> We can therefore use Beautiful Soup to find the AlphaNav class and use the decompose() method to remove a tag from the parse tree and then destroy it along with its contents.<br /> We’ll use the variable last_links to reference these bottom links and add them to the program file:<br /> # Remove bottom links<br /> last_links = (class_=’AlphaNav’)<br /> compose()<br /> Now, when we run the program with the python command, we’ll receive the following output:<br /> Zaccone, Fabian<br /> Zanotti, Giampietro<br /> At this point, we see that the output no longer includes the links at the bottom of the web page, and now only displays the links associated with artists’ names.<br /> Until now, we have targeted the links with the artists’ names specifically, but we have the extra tag data that we don’t really want. Let’s remove that in the next section.<br /> Pulling the Contents from a Tag<br /> In order to access only the actual artists’ names, we’ll want to target the contents of the <a> tags rather than print out the entire link tag.<br /> We can do this with Beautiful Soup’s. contents, which will return the tag’s children as a Python list data type.<br /> Let’s revise the for loop so that instead of printing the entire link and its tag, we’ll print the list of children (i. e. the artists’ full names):<br /> # Use. contents to pull out the <a> tag’s children<br /> names = ntents[0]<br /> print(names)<br /> Note that we are iterating over the list above by calling on the index number of each item.<br /> We can run the program with the python command to view the following output:<br /> OutputZabaglia, Niccola<br /> Zadkine, Ossip…<br /> Zanini-Viola, Giuseppe<br /> We have received back a list of all the artists’ names available on the first page of the letter Z.<br /> However, what if we want to also capture the URLs associated with those artists? We can extract URLs found within a page’s <a> tags by using Beautiful Soup’s get(‘href’) method.<br /> From the output of the links above, we know that the entire URL is not being captured, so we will concatenate the link string with the front of the URL string (in this case).<br /> These lines we’ll also add to the for loop:<br /> links = ” + (‘href’)<br /> print(links)<br /> When we run the program above, we’ll receive both the artists’ names and the URLs to the links that tell us more about the artists:<br /> Zaccone, Fabian…<br /> Although we are now getting information from the website, it is currently just printing to our terminal window. Let’s instead capture this data so that we can use it elsewhere by writing it to a file.<br /> Writing the Data to a CSV File<br /> Collecting data that only lives in a terminal window is not very useful. Comma-separated values (CSV) files allow us to store tabular data in plain text, and is a common format for spreadsheets and databases. Before beginning with this section, you should familiarize yourself with how to handle plain text files in Python.<br /> First, we need to import Python’s built-in csv module along with the other modules at the top of the Python programming file:<br /> import csv<br /> Next, we’ll create and open a file called for us to write to (we’ll use the variable f for file here) by using the ‘w’ mode. We’ll also write the top row headings: Name and Link which we’ll pass to the writerow() method as a list:<br /> f = (open(”, ‘w’))<br /> f. writerow([‘Name’, ‘Link’])<br /> Finally, within our for loop, we’ll write each row with the artists’ names and their associated links:<br /> f. writerow([names, links])<br /> You can see the lines for each of these tasks in the file below:<br /> # Create a file to write to, add headers row<br /> # Add each artist’s name and associated link to a row<br /> When you run the program now with the python command, no output will be returned to your terminal window. Instead, a file will be created in the directory you are working in called<br /> Depending on what you use to open it, it may look something like this:<br /> z-artist-names. csvName, Link<br /> “Zabaglia, Niccola”, “Zaccone, Fabian”, “Zadkine, Ossip”,…<br /> Or, it may look more like a spreadsheet:<br /> In either case, you can now use this file to work with the data in more meaningful ways since the information you have collected is now stored in your computer’s memory.<br /> We have created a program that will pull data from the first page of the list of artists whose last names start with the letter Z. However, there are 4 pages in total of these artists available on the website.<br /> In order to collect all of these pages, we can perform more iterations with for loops. This will revise most of the code we have written so far, but will employ similar concepts.<br /> To start, we’ll want to initialize a list to hold the pages:<br /> pages = []<br /> We will populate this initialized list with the following for loop:<br /> for i in range(1, 5):<br /> url = ” + str(i) + ”<br /> (url)<br /> Earlier in this tutorial, we noted that we should pay attention to the total number of pages there are that contain artists’ names starting with the letter Z (or whatever letter we’re using). Since there are 4 pages for the letter Z, we constructed the for loop above with a range of 1 to 5 so that it will iterate through each of the 4 pages.<br /> For this specific web site, the URLs begin with the string and then are followed with a number for the page (which will be the integer i from the for loop that we convert to a string) and end with We will concatenate these strings together and then append the result to the pages list.<br /> In addition to this loop, we’ll have a second loop that will go through each of the pages above. The code in this for loop will look similar to the code we have created so far, as it is doing the task we completed for the first page of the letter Z artists for each of the 4 pages total. Note that because we have put the original program into the second for loop, we now have the original loop as a nested for loop contained in it.<br /> The two for loops will look like this:<br /> for item in pages:<br /> page = (item)<br /> In the code above, you should see that the first for loop is iterating over the pages and the second for loop is scraping data from each of those pages and then is adding the artists’ names and links line by line through each row of each page.<br /> These two for loops come below the import statements, the CSV file creation and writer (with the line for writing the headers of the file), and the initialization of the pages variable (assigned to a list).<br /> Within the greater context of the programming file, the complete code looks like this:<br /> Since this program is doing a bit of work, it will take a little while to create the CSV file. Once it is done, the output will be complete, showing the artists’ names and their associated links from Zabaglia, Niccola to Zykmund, Václav.<br /> Being Considerate<br /> When scraping web pages, it is important to remain considerate of the servers you are grabbing information from.<br /> Check to see if a site has terms of service or terms of use that pertains to web scraping. Also, check to see if a site has an API that allows you to grab data before scraping it yourself.<br /> Be sure to not continuously hit servers to gather data. Once you have collected what you need from a site, run scripts that will go over the data locally rather than burden someone else’s servers.<br /> Additionally, it is a good idea to scrape with a header that has your name and email so that a website can identify you and follow up if they have any questions. An example of a header you can use with the Python Requests library is as follows:<br /> headers = {<br /> ‘User-Agent’: ‘Your Name, ‘,<br /> ‘From’: ”}<br /> url = ”<br /> page = (url, headers = headers)<br /> Using headers with identifiable information ensures that the people who go over a server’s logs can reach out to you.<br /> Conclusion<br /> This tutorial went through using Python and Beautiful Soup to scrape data from a website. We stored the text that we gathered within a CSV file.<br /> You can continue working on this project by collecting more data and making your CSV file more robust. For example, you may want to include the nationalities and years of each artist. You can also use what you have learned to scrape data from other websites.<br /> To continue learning about pulling information from the web, read our tutorial “How To Crawl A Web Page with Scrapy and Python 3. ”</p> <h2>Frequently Asked Questions about beautifulsoup tutorial python 2_7</h2> <h3></h3> <h3></h3> <h3></h3> </div> <div class="meks_ess layout-1-1 rectangle no-labels solid"><a href="#" class="meks_ess-item socicon-facebook" data-url=""><span>Facebook</span></a><a href="#" class="meks_ess-item socicon-twitter" data-url=""><span>Twitter</span></a></div> </article> </div> <div class="section-head"><h3 class="section-title h6">About the author</h3></div> <div class="section-content typology-author"> <div class="container"> <div class="col-lg-2"> <img alt='' src='' srcset=' 2x' class='avatar avatar-100 photo' height='100' width='100' loading='lazy' decoding='async'/> </div> <div class="col-lg-10"> <h5 class="typology-author-box-title">proxyreview</h5> <div class="typology-author-desc"> <p>If you 're a SEO / IM geek like us then you'll love our updates and our website. Follow us for the latest news in the world of web automation tools & proxy servers!</p> </div> <div class="typology-author-links"> <a class="typology-button-social hover-on" href="">View all posts</a><a href="" target="_blank" class="typology-icon-social hover-on fa fa-link"></a><a href="" target="_blank" class="typology-icon-social hover-on fa fa-facebook"></a><a href="" target="_blank" class="typology-icon-social hover-on fa fa-twitter"></a> </div> </div> </div> </div> <div class="typology-ad typology-ad-bottom"><!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "", "ym"); ym(85677304, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true }); </script> <noscript><div><img src="" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter --></div> </div> <div class="typology-section typology-section-related"> <div class="section-head"><h3 class="section-title h6">Read more</h3></div> <div class="section-content section-content-c"> <div class="typology-posts"> <article class="typology-post typology-layout-c col-lg-6 text-center post-image-off post-38368 post type-post status-publish format-standard has-post-thumbnail hentry category-proxy tag-craigslist-account-for-sale tag-craigslist-chicago-account tag-craigslist-homepage tag-craigslist-login tag-craigslist-my-account-not-working tag-how-to-place-an-ad-on-craigslist-with-pictures tag-post-ad-on-craigslist-for-free tag-sell-on-craigslist"> <header class="entry-header"> <h2 class="entry-title h4"><a href="">Create New Craigslist Account</a></h2> <div class="entry-meta"><div class="meta-item meta-date"><span class="updated">9 months ago</span></div></div> <div class="post-letter">C</div> </header> </article> <article class="typology-post typology-layout-c col-lg-6 text-center post-image-off post-41004 post type-post status-publish format-standard has-post-thumbnail hentry category-proxy tag-bittorrent-proxy tag-qbittorrent-proxy tag-torguard-proxy-list tag-torguard-proxy-qbittorrent tag-utorrent-proxy-connect-error tag-utorrent-proxy-free-download tag-utorrent-proxy-list tag-utorrent-proxy-site-kickass"> <header class="entry-header"> <h2 class="entry-title h4"><a href="">Utorrent Proxy</a></h2> <div class="entry-meta"><div class="meta-item meta-date"><span class="updated">9 months ago</span></div></div> <div class="post-letter">U</div> </header> </article> <article class="typology-post typology-layout-c col-lg-6 text-center post-image-off post-36208 post type-post status-publish format-standard has-post-thumbnail hentry category-proxy tag-crawl-website-for-all-urls tag-free-web-crawler tag-google-crawler tag-how-to-make-a-web-crawler-in-python tag-types-of-web-crawlers tag-web-crawler-is-an-example-of tag-web-crawler-tool tag-web-crawling-vs-web-scraping"> <header class="entry-header"> <h2 class="entry-title h4"><a href="">How To Crawl The Web</a></h2> <div class="entry-meta"><div class="meta-item meta-date"><span class="updated">9 months ago</span></div></div> <div class="post-letter">H</div> </header> </article> <article class="typology-post typology-layout-c col-lg-6 text-center post-image-off post-43551 post type-post status-publish format-standard has-post-thumbnail hentry category-proxy tag-best-vpn-to-hide-ip-address tag-free-vpn-to-hide-ip-address tag-hide-my-ip-address-free-online tag-how-to-hide-ip-address-free tag-how-to-hide-ip-address-on-android tag-how-to-hide-my-ip-address-without-vpn tag-how-to-hide-your-ip-address-on-iphone tag-how-to-protect-your-ip-address-from-hackers"> <header class="entry-header"> <h2 class="entry-title h4"><a href="">How To Protect My Ip Address From Tracking</a></h2> <div class="entry-meta"><div class="meta-item meta-date"><span class="updated">9 months ago</span></div></div> <div class="post-letter">H</div> </header> </article> </div> </div> </div> <div id="typology-single-sticky" class="typology-single-sticky"> <div class="typology-sticky-content meta"> <div class="typology-flex-center"> <div class="typology-sticky-author typology-sticky-l"> <img alt='' src='' srcset=' 2x' class='avatar avatar-50 photo' height='50' width='50' loading='lazy' decoding='async'/> <span class="sticky-author-title"> <a href="">By proxyreview</a> <span class="sticky-author-date">November 16, 2021</span> </span> </div> <div class="typology-sticky-c"> </div> <div class="typology-sticky-comments typology-sticky-r"> </div> </div> </div> <div class="typology-sticky-content prev-next"> <nav class="typology-prev-next-nav typology-flex-center"> <div class="typology-prev-link typology-sticky-l"> <a href=""> <span class="typology-pn-ico"><i class="fa fa-chevron-left"></i></span> <span class="typology-pn-link">The Piratebayproxylist_Net</span> </a> </div> <a href="javascript: void(0);" class="typology-sticky-to-top typology-sticky-c"> <span class="typology-top-ico"><i class="fa fa-chevron-up"></i></span> <span class="typology-top-link">To Top</span> </a> <div class="typology-next-link typology-sticky-r"> <a href=""> <span class="typology-pn-ico"><i class="fa fa-chevron-right"></i></span> <span class="typology-pn-link">Dota 2 Server Ip</span> </a> </div> </nav> </div> </div> <footer id="typology-footer" class="typology-footer"> <div class="container"> </div> </footer> </div> <div class="typology-sidebar"> <div class="typology-sidebar-header"> <div class="typology-sidebar-header-wrapper"> <div class="typology-site-branding"> <span class="site-title h4"><a href="" rel="home"><img class="typology-logo" src="" alt=""></a></span> </div> <span class="typology-sidebar-close"><i class="fa fa-times" aria-hidden="true"></i></span> </div> </div> <div class="widget typology-responsive-menu"> </div> <div id="recent-posts-4" class="widget clearfix widget_recent_entries"> <h4 class="widget-title h5">Recent Posts</h4> <ul> <li> <a href="">Create New Craigslist Account</a> </li> <li> <a href="">Utorrent Proxy</a> </li> <li> <a href="">How To Crawl The Web</a> </li> <li> <a href="">How To Protect My Ip Address From Tracking</a> </li> <li> <a href="">Android 9 Proxy Settings</a> </li> </ul> </div><div id="text-4" class="widget clearfix widget_text"><h4 class="widget-title h5">Useful Tools</h4> <div class="textwidget"><a href="">Proxy Package Finder</a></div> </div> </div> <div class="typology-sidebar-overlay"></div> <link rel='stylesheet' id='aal_style-css' href='' type='text/css' media='all' /> <script type='text/javascript' id='wp-postviews-cache-js-extra'> /* <![CDATA[ */ var viewsCacheL10n = {"admin_ajax_url":"https:\/\/\/wp-admin\/admin-ajax.php","post_id":"33727"}; /* ]]> */ </script> <script type='text/javascript' src='' id='wp-postviews-cache-js'></script> <script type='text/javascript' src='' id='imagesloaded-js'></script> <script type='text/javascript' id='typology-main-js-extra'> /* <![CDATA[ */ var typology_js_settings = {"rtl_mode":"","header_sticky":"1","logo":"https:\/\/\/wp-content\/uploads\/2021\/09\/logo_white.png","logo_retina":"https:\/\/\/wp-content\/uploads\/2021\/09\/logo_white_retina.png","use_gallery":"1","slider_autoplay":"0","cover_video_image_fallback":""}; /* ]]> */ </script> <script type='text/javascript' src='' id='typology-main-js'></script> <script type='text/javascript' src='' id='meks_ess-main-js'></script> <script>!function(){window.advanced_ads_ready_queue=window.advanced_ads_ready_queue||[],advanced_ads_ready_queue.push=window.advanced_ads_ready;for(var d=0,a=advanced_ads_ready_queue.length;d<a;d++)advanced_ads_ready(advanced_ads_ready_queue[d])}();</script> </body> </html>