Skip to content

Python Web Scraping Tutorial: Step-by-Step Guide [2023]

Welcome to my ultimate guide on web scraping with Python!

By the end, you‘ll know:

  • What web scraping is and why companies use it
  • Python libraries for extracting data
  • Steps to build a complete scraper
  • Expert tips to scrape robustly
  • How to handle complex scraping scenarios
  • Tons of resources to take your skills further

Let‘s get scraping!

What is Web Scraping?

Web scraping is the process of automatically collecting structured web data in bulk.

Some key terms:

  • Web crawling – Broadly downloading data from websites.
  • Web scraping – Targeted extraction of specific data points.
  • Data mining – Analyzing scraped datasets for insights.

Web scraping powers a wide range of critical business use cases:

  • Price monitoring – Track prices for products across ecommerce sites. This competitive pricing data allows dynamic pricing.
  • Market research – Analyze trends across news sites, forums, reviews and social media posts. Provides valuable consumer and competitor intelligence.
  • Lead generation – Build lists of prospects from industry directories and company websites. Kickstarts sales pipelines.
  • Recruitment – Scrape job postings across multiple job boards to source qualified candidates faster.
  • Travel aggregation – Extract flight/hotel listings from OTAs to show in consolidated travel metasearch engines.

As per estimates, web scraping can provide over a 5000% ROI compared to slow and expensive manual data collection. It unlocks immense time and cost savings.

However, always scrape ethically and legally. Avoid violating sites‘ terms of service, scraping data you don‘t have rights to, denial of service attacks etc. When in doubt, read robots.txt files for guidelines and scrape respectfully. Do not replicate scraped content verbatim without authorization.

Now let‘s look at why Python is a great choice for web scraping.

Why Use Python for Web Scraping?

Here are some key advantages that make Python one of the most popular languages for web scraping:

  • Easy to learn – Python has simple and intuitive syntax. It‘s great for programmers of any skill level.
  • Huge ecosystem – There are numerous robust libraries and frameworks specifically for web scraping like Scrapy, BeautifulSoup, Selenium etc.
  • Cross-platform – Python code works on Windows, Mac, Linux without changes. Web scrapers you build are highly portable.
  • General purpose – Along with web scraping, Python excels at tasks like data analysis, automation, machine learning, app development etc.
  • Large community – As one of the world‘s most popular languages, there are many resources and active forums ready to help.

According to SlashData, over 8.2 million developers use Python. This huge community enables quick answers to coding questions and technical support.

In summary, Python boosts your productivity as a scraper developer. You spend less time dealing with language complexities and more time building the scraping logic.

Now let‘s explore some key Python libraries that form the toolset for modern web scraping.

Python Libraries for Web Scraping

There are dozens of Python libraries that aid with web scraping. I‘ll summarize the most popular ones:


Requests allows sending HTTP requests extremely easily. We can use it to download web pages for scraping.

Here‘s a simple example:

import requests

response = requests.get(‘‘)
print(response.text) # Print HTML content

Beyond GET requests, Requests supports:

  • POST requests to submit forms
  • Adding custom headers
  • Cookies persistence with Sessions
  • Authentication
  • Streaming content
  • Automatic gzip/connection handling

In short, it takes care of all complexities of working with HTTP requests while exposing a simple interface to you.

Beautiful Soup

Once Requests downloads an HTML page, Beautiful Soup helps parse and analyze its content. It represents the HTML in a nested data structure and provides methods like:

  • Navigating the parse tree
  • Searching for items that match criteria
  • Modifying and updating the HTML

For example:

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, ‘html.parser‘)

links = soup.find_all(‘a‘) # Get all anchor tags
for link in links: 
  print(link[‘href‘]) # Print link URL

Beautiful Soup supports searching via CSS selectors, regular expressions and XPath making it very versatile.

Overall, it simplifies working with parsed HTML – saving tons of time versus manually analyzing raw HTML yourself.


Selenium launches and controls actual web browsers like Chrome, Firefox etc.

It effectively acts as a real user – scrolling web pages, clicking elements, filling forms etc. This allows it to load dynamic content like JavaScript.

Here‘s an example to extract results from a site after scrolling down:

from selenium import webdriver
from bs4 import BeautifulSoup 

driver = webdriver.Chrome()

# Scroll to load dynamic content
driver.execute_script("window.scrollTo(0, 1000);") 

html = driver.page_source
soup = BeautifulSoup(html, ‘html.parser‘)

results = soup.find_all(‘div‘, class_=‘result‘) 


While slower than requests-based scraping, Selenium provides full automation capabilities to scrape complex sites.

Comparing Python Web Scraping Libraries

Library Description Pros Cons
Requests Makes HTTP requests Simple interface Cannot parse returned HTML
BeautifulSoup Parses HTML/XML Excellent parser, easy to use Cannot execute JavaScript
Selenium Controls browsers Handles JavaScript, dynamic actions Slower compared to other libraries

To summarize, for basic scraping you need Requests for downloading and BeautifulSoup for parsing content. Selenium adds browser automation capabilities but involves higher overhead.

Now let‘s apply these libraries to build a scraper.

Building a Python Web Scraper Step-by-Step

Let‘s walk through a hands-on example to scrape names and phone numbers from an online directory page.

Import Libraries

We‘ll need Request, BeautifulSoup and Pandas:

import requests
from bs4 import BeautifulSoup
import pandas as pd

Make a Request

Use Requests to download the page:

URL = ‘‘
response = requests.get(URL)

Verify successful response:

if response.status_code == 200:
  print(‘Failed to fetch page‘)

Parse HTML

We‘ll use BeautifulSoup to parse and analyze the page content:

soup = BeautifulSoup(response.text, ‘html.parser‘)

Extract Data

Identify elements containing the names and phone numbers.

The HTML looks like:

<p class="name">John Doe</p>
<p class="phone">123-456-7890</p> 

Use a CSS selector to extract the text:

names = []
phones = []

for name in‘‘):

for phone in‘‘):

Store in DataFrame

Put the data in a Pandas DataFrame:

import pandas as pd 

df = pd.DataFrame({‘Name‘: names, ‘Phone‘: phones}) 

This gives us a structured dataset – ready for analysis and export!

The full code is:

import requests 
from bs4 import BeautifulSoup
import pandas as pd

URL = ‘‘

response = requests.get(URL)
soup = BeautifulSoup(response.text, ‘html.parser‘)

names = [] 
phones = []

for name in‘‘):

for phone in‘‘):

df = pd.DataFrame({‘Name‘: names, ‘Phone‘: phones})

This demonstrates core concepts like:

  • Using Requests and BeautifulSoup
  • Selecting elements
  • Extracting and structuring data
  • Storing scraped data in Pandas

These form the building blocks for robust scraping in Python. Next let‘s look at expert techniques to scrape at scale.

Web Scraping Best Practices

Here are some tips to scrape data reliably and efficiently:

Use Proxies

Proxies route your scraper‘s requests through intermediate servers so the target sites don‘t see all traffic as coming from a single source.

Benefits of proxies:

  • Avoid IP blocks – Spread requests across IPs to distribute load and look less suspicious.
  • Access restricted data – Proxies based in specific countries let you scrape region-locked data.
  • Remain anonymous – Hide your scraper‘s identity for discreet data collection.

Proxies API provides millions of residential and datacenter proxies globally with granular targeting options.

Here‘s how to authenticate and use a proxy with Requests:

import requests

proxy = ‘http://user:password@proxy:port‘ 

proxies = {
  ‘http‘: proxy,
  ‘https‘: proxy

response = requests.get(‘‘, proxies=proxies)

Implement Random Delays

To mimic human scrolling and clicking, add random delays between page requests using time.sleep():

import time
import random

# Fetch page
# Scrape page

time.sleep(random.randint(1, 5)) # Sleep 1-5 seconds  

Adding small delays avoids flooding servers with requests which can get your scraper blocked.

Rotate User Agents

Websites can identify scrapers by consistent user agents.

Use a library like Fake Useragent to generate a variety of user agents:

from fake_useragent import UserAgent
ua = UserAgent()

header = {‘User-Agent‘:}
response = requests.get(url, headers=header) 

Rotating user agents helps mask scrapers as normal traffic.

Use Exception Handling

Gracefully handle errors like missing elements, connectivity issues etc:

  # Try scraping
except Exception as e:
  print(f‘Scraping failed due to {e}‘)

Robust error handling ensures your scraper doesn‘t fail due to transient errors.

Store Incrementally

Save scraped data incrementally rather than all at once at the end.

This prevents losing all data if errors occur mid-scrape.

These tips help build industrial-grade scrapers that extract data reliably.

Now let‘s tackle some common challenges.

Expanding on the Basics

While we covered core concepts, here are techniques to handle complex scenarios:

Scrape Paginated Sites

Rather than scraping page-by-page, inspect network requests and find APIs returning paginated data in JSON/XML format:

Build pagination logic on top to loop through pages efficiently:

import requests 

results = []
page = 1 

while True:
  response = requests.get(f‘{page}‘)

  # Parse and store results

  if not response.json():

  page += 1

Handle Infinite Scroll

Use Selenium to scroll down and trigger loading more results:

driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")

Add a delay to allow loading before collecting page source.

If data is split across pages, scrape unique identifiers like product IDs.

Use them to reconcile related records.

Scrape Javascript Sites

For purely Javascript sites, Selenium provides full JS execution capabilities before parsing content with BeautifulSoup.

soup = BeautifulSoup(driver.page_source, ‘html.parser‘) 

Scrape Forms

Selenium can automate form filling, clicking buttons etc:

driver.find_element(By.ID, ‘email‘).send_keys(‘[email protected]‘) 
driver.find_element(By.ID, ‘submit‘).click()

This handles multi-page workflows and AJAX requests.

Create Robust Workflows

Build modular and parameterized scrapers that:

  • Navigate between URLs
  • Handle logins
  • Follow flows across pages
  • Support reruns for updated data

Here is a sample scaffolded framework for reference.

These patterns allow industrial-scale web scraping.

Now that you‘re a pro, let‘s look at additional resources to master web scraping with Python.

Additional Resources to Level Up

Here are useful resources I recommend:

Web Scraping Courses




With these resources, you‘ll be able to take your Python web scraping skills to the next level.


In this comprehensive 2200+ word guide, we covered:

  • Web scraping fundamentals
  • Python libraries like Requests, BeautifulSoup, Selenium
  • Building a scraper from scratch
  • Expert techniques like proxies, exceptions, pagination
  • Tons of additional resources

You should now have a strong foundation to start scraping sites using Python.

The best way to improve is to practice on real-world websites and expand scrapers to handle complex flows.

I aim to provide actionable details through examples, code snippets and recommendations.

Hopefully this tutorial equips you with deep knowledge to extract value from data on the web!


Join the conversation

Your email address will not be published. Required fields are marked *