MediumHow to Fix 403 Forbidden in BeautifulSoup | Medium
Sitemap
Spaw.co - Blog

Spaw.co - Blog

This is a blog of a mobile proxy service - Spaw. We publish useful information on scraping different sources and working with mobile proxies.

How to Solve BeautifulSoup 403 Error

4 min readMay 21, 2024

--

Press enter or click to view image in full size

Encountering a 403 Forbidden error while scraping a website using BeautifulSoup can be a stumbling block for many web scrapers. This error indicates that the server is refusing to fulfill the request, often due to perceived unauthorized access. Addressing this requires understanding the root causes and implementing strategic solutions.

Understanding the 403 Error

A 403 error means the server has received the request but refuses to authorize it. Common reasons for this include:

  1. User-Agent Restrictions: Some websites block requests that lack a proper User-Agent string or have one indicating a bot.
  2. IP Blocking: Repeated requests from the same IP address may trigger blocking mechanisms.
  3. HTTP Headers: Absence of necessary headers like Referer, Accept-Language, etc., can lead to access denial.
  4. Cookies: Some websites require cookies for session management and access.

Solutions to Overcome the 403 Error

1. Setting a User-Agent

Many servers check the User-Agent string to determine the nature of the request. A legitimate User-Agent string can mimic a request from a real browser.

import requests
from bs4 import BeautifulSoup

url = 'http://example.com'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser')

2. Using Proxies

Servers may block IP addresses that send too many requests. Using proxies can distribute requests across multiple IPs, reducing the risk of getting blocked. We would recommend mobile proxies; with them, such errors will occur less often.

Press enter or click to view image in full size
You can register and request a free demo period from support at Spaw.co
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
response = requests.get(url, headers=headers, proxies=proxies)

3. Adding Headers

Web servers often require additional headers to mimic a real browser request. Common headers include Accept-Language, Referer, and others.

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Accept-Language': 'en-US,en;q=0.5',
'Referer': 'http://google.com'
}
response = requests.get(url, headers=headers)

Get Spaw.co - Blog’s stories in your inbox

Join Medium for free to get updates from this writer.

4. Handling Cookies

Websites sometimes require cookies for session handling. Using cookies in requests can help bypass 403 errors.

session = requests.Session()
response = session.get(url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser')

5. Using Rotating User-Agents and Proxies

To simulate real user behavior, rotating User-Agents and proxies can be effective. This method involves switching User-Agents and proxies for each request.

from itertools import cycle

user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0',
# add more user agents
]

proxies = [
'http://10.10.1.10:3128',
'http://10.10.1.11:3128',
# add more proxies
]

proxy_pool = cycle(proxies)

for user_agent in user_agents:
proxy = next(proxy_pool)
headers = {'User-Agent': user_agent}
response = requests.get(url, headers=headers, proxies={"http": proxy, "https": proxy})
if response.status_code == 200:
soup = BeautifulSoup(response.content, 'html.parser')
break

6. Timeout and Retry Logic

Implementing a timeout and retry logic can help handle transient issues. If a request fails, retrying after a short delay can sometimes succeed.

import time

def fetch_url(url, headers, max_retries=3):
retries = 0
while retries < max_retries:
try:
response = requests.get(url, headers=headers, timeout=5)
if response.status_code == 200:
return response
except requests.exceptions.RequestException as e:
retries += 1
time.sleep(2) # wait before retrying
return None

response = fetch_url(url, headers)
if response:
soup = BeautifulSoup(response.content, 'html.parser')

7. Respect Robots.txt

Check the website’s robots.txt file to ensure your scraping efforts comply with the site's rules. Ignoring these can lead to IP bans.

import urllib.robotparser

rp = urllib.robotparser.RobotFileParser()
rp.set_url('http://example.com/robots.txt')
rp.read()

url = 'http://example.com/somepage'
if rp.can_fetch('*', url):
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser')
else:
print("Scraping not allowed by robots.txt")

8. Rate Limiting

Web servers may block requests that come in too frequently. Implementing rate limiting can help avoid triggering these blocks.

import time

def fetch_with_rate_limit(url, headers, rate_limit=1):
response = requests.get(url, headers=headers)
time.sleep(rate_limit)
return response

response = fetch_with_rate_limit(url, headers)
soup = BeautifulSoup(response.content, 'html.parser')

9. Using a Headless Browser

Sometimes, simple requests won’t suffice, and using a headless browser like Selenium can mimic real user interactions more accurately.

from selenium import webdriver
from bs4 import BeautifulSoup

options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
driver.quit()

10. API Access

When available, using a website’s API can be a more reliable and efficient way to get data. APIs often provide structured access to the site’s data without the need for scraping.

import requests

api_url = 'http://api.example.com/data'
response = requests.get(api_url, headers=headers)
data = response.json()

Conclusion

Dealing with a 403 Forbidden error in BeautifulSoup involves understanding server restrictions and implementing techniques to mimic genuine browsing behavior. By setting appropriate headers, using proxies, handling cookies, and respecting robots.txt, you can navigate around these blocks and scrape data effectively. Always consider the ethical implications and terms of service of the website you are scraping to avoid legal issues.

--

--