SimilarWeb is a leading platform specializing in web analytics, acting as a directory for worldwide website traffic. Imagine the insights and SEO impact that scraping SimilarWeb could provide!
In this comprehensive guide, we’ll demonstrate how to scrape SimilarWeb through a detailed step-by-step approach. We’ll extract comprehensive domain traffic insights, website comparison data, sitemaps, and trending industry domains. Let’s get started!
Key Takeaways
Master similarweb scraper techniques using Python with httpx and parsel, extracting domain insights, competitor data, and SEO rankings for comprehensive market analysis.
- Implement similarweb scraper solutions with advanced anti-detection techniques and proxy rotation
- Use specialized tools like Webparsers for automated SimilarWeb data extraction with anti-blocking features
- Configure proper headers, user agents, and request patterns to avoid detection
- Apply rate limiting and request delays to prevent blocking and maintain access
- Use residential proxies and IP rotation for reliable SimilarWeb data collection
- Implement error handling and retry mechanisms for robust scraping operations
Why Scrape SimilarWeb?
Web scraping SimilarWeb provides detailed valuable insights into website traffic, which can be beneficial across different aspects.
Competitor Analysis
One of the primary features of web analytics involves analyzing industry peers and benchmarking against their traffic performance. Scraping SimilarWeb enables this data retrieval, allowing businesses to fine-tune their strategies to compete effectively and gain a competitive advantage.
SEO and Keyword Analysis
Search Engine Optimization (SEO) is essential for driving traffic to domains. SimilarWeb data extraction provides comprehensive insights into SEO keywords and search engine rankings, enabling better online presence and visibility optimization.
Data-Driven Decision Making
Search trends are dynamic and rapidly changing. Therefore, utilizing SimilarWeb scraping for data-driven insights is essential for supporting decision-making and defining strategic approaches.
Have a look at our comprehensive guide on web scraping use cases for further details.In this article, we’ll take a look at SEO web scraping, what it is and how to use it for better SEO keyword optimization. We’ll also create an SEO keyword scraper that scrapes Google search rankings and suggested keywords.
Setup
To web scrape SimilarWeb, we’ll use Python with a few community packages.
- httpx: To request SimilarWeb pages and get the data as HTML. Feel free to replace httpx with any other HTTP client, such as requests.
- parsel: To parse the HTML retrieved using web selectors, such as XPath and CSS.
- JMESPath: To refine the JSON datasets we get and remove the unnecessary details.
- asyncio: To increase our SimilarWeb scraper speed by running it asynchronously.
- loguru: Optional prerequisite to monitor our code through colored terminal outputs.
Since asyncio comes pre-installed in Python, we’ll only have to install the other packages using the following pip command:
pip install httpx parsel jmespath loguru
How to Discover SimilarWeb Pages?
Crawling sitemaps is an excellent way to discover and navigate pages on a website. Since they direct search engines for organized indexing, we can utilize them for scraping purposes as well!
The SimilarWeb sitemaps can be found at similarweb.com/robots.txt, which appears like this:
User-agent: *
Disallow: */search/
Disallow: */adult/*
Disallow: /corp/*.pdf$
Disallow: /corp/solution/
Disallow: /corp/lps/
Disallow: /corp/get-data/
Disallow: /silent-login/
Disallow: /signin-oidc/
Disallow: /signout-oidc/
Sitemap: https://www.similarweb.com/corp/sitemap_index.xml
Sitemap: https://www.similarweb.com/blog/sitemap_index.xml
Sitemap: https://www.similarweb.com/sitemaps/sitemap_index.xml.gz
#
# sMMMMMMMMs
# MNdmMh+-``.:ohNM
# MNy/ .sMd- `/yNM
# MNo` sMo .oNM
# Md - sMo -dM
# 'MM+ -dMm+. yMM'
# MN` `:yNMd/ .NM
# MN- `-hMy :MM
# MMN- sMd` -NM
# Md:` `sh`` .sMM
# Mdms+-.```-hmMds
# oMMMMMMMMo
#
# OFFICIAL MEASURE OF THE DIGITAL WORLD
#
Each of the above sitemap indexes represents a group of related sitemaps. Let’s explore the latest sitemap /sitemaps/sitemap_index.xml.gz. It’s a gz compressed file to save bandwidth, which appears like this after extraction:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
....
<sitemap>
<loc>https://www.similarweb.com/sitemaps/top-websites-trending/part-00000.gz</loc>
<lastmod>2023-08-17</lastmod>
</sitemap>
<sitemap>
<loc>https://www.similarweb.com/sitemaps/website/part-00000.gz</loc>
<lastmod>2023-08-17</lastmod>
</sitemap>
<sitemap>
<loc>https://www.similarweb.com/sitemaps/website_competitors/part-00000.gz</loc>
<lastmod>2023-08-17</lastmod>
</sitemap>
</sitemapindex>
We have reached another sitemap index for several website insight pages. Each sitemap located in a loc element provides further scraping targets:
[
"https://www.similarweb.com/top-websites/food-and-drink/groceries/trending/",
"https://www.similarweb.com/top-websites/gambling/bingo/trending/",
"https://www.similarweb.com/top-websites/travel-and-tourism/transportation-and-excursions/trending/",
"https://www.similarweb.com/top-websites/health/health-conditions-and-concerns/trending/",
"https://www.similarweb.com/top-websites/finance/investing/trending/",
....
]
The above URLs represent website ranking pages for different industries. Let’s scrape them next!
How to Scrape SimilarWeb Trending Websites?
The trending website pages on SimilarWeb display two related insights:
- Trending: The month’s trending websites and their traffic changes.
- Ranking: The industry’s overall website rankings with essential traffic insights.
Let’s scrape the trending website section. Navigate to any industry trending page, such as the one for software, and you will encounter a similar web page:
website rankings on SimilarWeb
Website rankings on SimilarWeb
We can parse the above SimilarWeb page using selectors to scrape it. However, there is a more effective approach: hidden web data.The visible HTML doesn’t always represent the complete dataset available on the page. In this article, we’ll be examining the scraping of hidden web data. What is it and how can we scrape it using Python?
To locate the website ranking hidden web data, follow these steps:
- Open the browser developer tools by pressing the F12 key.
- Search for the XPath selector:
//script[@id='dataset-json-ld'].
After following the above steps, you will find the below data:
similarweb ranking pages html source
The above data is identical to what appears on the web page but before getting rendered into the HTML. To scrape it, we’ll select its associated script tag and then parse it:
import asyncio
import json
from typing import List, Dict
from httpx import AsyncClient, Response
from parsel import Selector
from loguru import logger as log
# initialize an async httpx client
client = AsyncClient(
# enable http2
http2=True,
# add basic browser like headers to prevent getting blocked
headers={
"Accept-Language": "en-US,en;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br"
},
)
def parse_trending_data(response: Response) -> List[Dict]:
"""parse hidden trending JSON data from script tags"""
selector = Selector(response.text)
json_data = json.loads(selector.xpath("//script[@id='dataset-json-ld']/text()").get())["mainEntity"]
data = {}
data["name"] = json_data["name"]
data["url"] = str(response.url)
data["list"] = json_data["itemListElement"]
return data
async def scrape_trendings(urls: List[str]) -> List[Dict]:
"""parse trending websites data"""
to_scrape = [client.get(url) for url in urls]
data = []
for response in asyncio.as_completed(to_scrape):
response = await response
category_data = parse_trending_data(response)
data.append(category_data)
log.success(f"scraped {len(data)} trneding categories from similarweb")
return data
We use the previously defined httpx client and define additional functions:
- parse_trending_data: For extracting the page JSON data from the hidden script tag, organizing the data by removing the JSON schema details and adding the URL.
- scrape_trendings: For adding the page URLs to a list and requesting them concurrently.
Here is a sample output of the above SimilarWeb scraping code:
[
{
"name": "Most Visited Social Media Networks Websites",
"url": "https://www.similarweb.com/top-websites/computers-electronics-and-technology/social-networks-and-online-communities/",
"list": [
{
"@type": "ListItem",
"position": 1,
"item": {
"@type": "WebSite",
"name": "facebook.com",
"url": "https://www.similarweb.com/website/facebook.com/"
}
},
....
]
},
....
]
Next, let’s explore the exciting part of our SimilarWeb scraper: website analytics! But before this, we must address a SimilarWeb scraping blocking issue: validation challenge.
How to Avoid SimilarWeb Validation Challenge?
The SimilarWeb validation challenge is a web scraping blocking mechanism that blocks HTTP requests from clients without JavaScript support. It’s a JavaScript challenge that’s automatically bypassed after 5 seconds when requesting the domain for the first time:
SimilarWeb scraping blocking: request processing
Since we scrape SimilarWeb with an HTTP client that doesn’t support JavaScript (httpx), requests sent to pages with this challenge will be blocked due to not evaluating it:
from httpx import Client
client = Client(
# enable http2
http2=True,
# add basic browser like headers to prevent getting blocked
headers={
"Accept-Language": "en-US,en;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
},
)
response = client.get("https://www.similarweb.com/website/google.com/")
print(response.text)
"""
<!DOCTYPE html><html><head><meta charset="utf-8">
<title>Challenge Validation</title>
<script type="text/javascript">function cp_clge_done(){location.reload(true);}</script>
<script src="/_sec/cp_challenge/sec-cpt-int-4-3.js" async defer></script>
<script type="text/javascript">sessionStorage.setItem('data-duration', 5);</script>
</html>
"""
To avoid the SimilarWeb validation challenge, we can use a headless browser to complete the challenge automatically using JavaScript. However, there’s a technique we can use to bypass the challenge without JavaScript: cookies!
When the validation challenge is solved, the website cookies are updated with the challenge state, so it’s not triggered again.
We can leverage cookies for web scraping to bypass the validation challenge automatically! To do this, we need to obtain the cookie value:
- Go to any protected SimilarWeb page with the challenge.
- Open the browser developer tools by pressing the F12 key.
- Select the Application tab and choose cookies.
- Copy the
_abckcookie value, which is responsible for the challenge.
After following the above steps, you will find the SimilarWeb saved cookies:
SimilarWeb cookies
Adding the _abck cookie to the requests will authorize them against the challenge:
from httpx import Client
client = Client(
# enable http2
http2=True,
# add basic browser like headers to prevent getting blocked
headers={
"Accept-Language": "en-US,en;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Cookie": "_abck=85E72C5791B36ED327B311F1DC7461A6~0~YAAQHPR6XIavCzyOAQAANeDuYgs83VF+IZs6MdB2WGsdsp5d89AWqe1hI+IskJ6V24OYvokUZSIn2Om9PATl5rqminoOTHQYZAMWO5Om8bcXlT3q2D9axmG+YQkS/77h/7O98vFFDrFX8Jns/upO+RbomHm7SxQ0IGk0yS80GGbWBQoSkxN+770ltBb9vdyT/7ShUBl3eKz/iLfyMSe4SyOxymE0pQL0pch0FJhvCiC2CD4asMBXGBNMQv2qvA553uO9bwz4Yr1X/7zLPOm6Vn2bz242O7rephGPmVud25Yc3Khs0oEqiQ4pgMvCy/NGIXTlVKN8anBc5QlnqGw7dq8kLqDrID9HqzbqusS9p5gkNUd4A2QJXDj80pjB9k4SWitpn1zRhsUNUYzrfvHMeGiDZhNuTYSq3sMcYg==~-1~-1~-1"
},
)
response = client.get("https://www.similarweb.com/website/google.com/")
print(response.text) # full HTML response
We can successfully bypass the validation challenge. However, the cookie value needs to be rotated as it can expire. The rotation logic can also be automated with a headless browser for better rotation efficiency.
How to Scrape SimilarWeb Website Analytics?
The SimilarWeb website analytics pages provide a powerful feature that includes comprehensive insights about the domain, including:
- Ranking: The domain’s category, country, and global rank.
- Traffic: Engagement analysis including total visits, bounce rate, and visit duration.
- Geography: The domain’s traffic by top countries.
- Demographics: The visitors’ composition distribution by age and gender.
- Interests: The visitors’ interests by categories and topics.
- Competitors: The domain’s competitors and alternatives and their similarities.
- Traffic sources: The domain’s traffic by its source, such as search, direct, or emails.
- Keywords: Top keywords visitors use to search the domain.
First, let’s examine what the website analysis page looks like on our target website by targeting a specific domain: Google.com. Navigate to the domain page on SimilarWeb, and you will see a page similar to this:
google analytics domain page on similarweb
Google analytics page on SimilarWeb
The above page data is challenging to scrape using selectors, as they are mostly located in charts and graphs. Therefore, we’ll use the hidden web data approach.
Search through the HTML using the following XPath selector: //script[contains(text(), 'window.__APP_DATA__')]. The script tag found contains a comprehensive JSON dataset with the domain analysis data:
google domain analytics page source on similarweb
To scrape SimilarWeb traffic analytics pages, we’ll select this script tag and parse the inside JSON data:
import re
import asyncio
import json
from typing import List, Dict
from httpx import AsyncClient, Response
from parsel import Selector
from loguru import logger as log
# initialize an async httpx client
client = AsyncClient(
# enable http2
http2=True,
# add basic browser like headers to prevent getting blocked
headers={
"Accept-Language": "en-US,en;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Cookie": "_abck=D2F915DBAC628EA7C01A23D7AA5DF495~0~YAAQLvR6XFLvH1uOAQAAJcI+ZgtcRlotheILrapRd0arqRZwbP71KUNMK6iefMI++unozW0X7uJgFea3Mf8UpSnjpJInm2rq0py0kfC+q1GLY+nKzeWBFDD7Td11X75fPFdC33UV8JHNmS+ET0pODvTs/lDzog84RKY65BBrMI5rpnImb+GIdpddmBYnw1ZMBOHdn7o1bBSQONMFqJXfIbXXEfhgkOO9c+DIRuiiiJ+y24ubNN0IhWu7XTrcJ6MrD4EPmeX6mFWUKoe/XLiLf1Hw71iP+e0+pUOCbQq1HXwV4uyYOeiawtCcsedRYDcyBM22ixz/6VYC8W5lSVPAve9dabqVQv6cqNBaaCM2unTt5Vy+xY3TCt1s8a0srhH6qdAFdCf9m7xRuRsi6OarPvDYjyp94oDlKc0SowI=~-1~-1~-1"
},
)
def parse_hidden_data(response: Response) -> List[Dict]:
"""parse website insights from hidden script tags"""
selector = Selector(response.text)
script = selector.xpath("//script[contains(text(), 'window.__APP_DATA__')]/text()").get()
data = json.loads(re.findall(r"(\{.*?)(?=window\.__APP_META__)", script, re.DOTALL)[0])
return data
async def scrape_website(domains: List[str]) -> List[Dict]:
"""scrape website inights from website pages"""
# define a list of similarweb URLs for website pages
urls = [f"https://www.similarweb.com/website/{domain}/" for domain in domains]
to_scrape = [client.get(url) for url in urls]
data = []
for response in asyncio.as_completed(to_scrape):
response = await response
website_data = parse_hidden_data(response)["layout"]["data"]
data.append(website_data)
log.success(f"scraped {len(data)} website insights from similarweb website pages")
return data
🤖 Update the “_abck” cookie before running the above code, as it may expire, to avoid challenge validation blocking or use Webparsers instead.
Let’s break down the above SimilarWeb scraping code:
- parse_hidden_data: For selecting the script tag that contains the domain analysis data and then parsing the JSON data using regex to exclude the HTML tags.
- scrape_website: For creating the domain analytics page URLs on SimilarWeb and then requesting them concurrently while utilizing the parsing logic.
Here’s an example output of the results we obtained:
Example output
The above web scraping SimilarWeb results are the raw analytics data. We can use it for further analysis ourselves!
How to Scrape SimilarWeb Website Comparing Pages?
The SimilarWeb comparison pages are similar to the dedicated pages for website analytics. They include traffic insights for two compared domains.
For example, let’s compare Twitter and Instagram using our target website. Navigate to the compare page on SimilarWeb, and you will see a similar page:
similarweb comparing pages
SimilarWeb compare pages
To scrape the above data, we’ll use the hidden data approach again using the previously used selector //script[contains(text(), 'window.__APP_DATA__')]. The data inside the script tag looks like the following:
similarweb comparing pages source
Similar to our previous SimilarWeb scraping code, we’ll select the script tag and parse the inside data:
import jmespath
import re
import asyncio
import json
from typing import List, Dict, Optional
from httpx import AsyncClient, Response
from parsel import Selector
from loguru import logger as log
# initialize an async httpx client
client = AsyncClient(
# enable http2
http2=True,
# add basic browser like headers to prevent getting blocked
headers={
"Accept-Language": "en-US,en;q=0.9",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Cookie": "_abck=D2F915DBAC628EA7C01A23D7AA5DF495~0~YAAQLvR6XFLvH1uOAQAAJcI+ZgtcRlotheILrapRd0arqRZwbP71KUNMK6iefMI++unozW0X7uJgFea3Mf8UpSnjpJInm2rq0py0kfC+q1GLY+nKzeWBFDD7Td11X75fPFdC33UV8JHNmS+ET0pODvTs/lDzog84RKY65BBrMI5rpnImb+GIdpddmBYnw1ZMBOHdn7o1bBSQONMFqJXfIbXXEfhgkOO9c+DIRuiiiJ+y24ubNN0IhWu7XTrcJ6MrD4EPmeX6mFWUKoe/XLiLf1Hw71iP+e0+pUOCbQq1HXwV4uyYOeiawtCcsedRYDcyBM22ixz/6VYC8W5lSVPAve9dabqVQv6cqNBaaCM2unTt5Vy+xY3TCt1s8a0srhH6qdAFdCf9m7xRuRsi6OarPvDYjyp94oDlKc0SowI=~-1~-1~-1"
},
)
def parse_hidden_data(response: Response) -> List[Dict]:
"""parse website insights from hidden script tags"""
selector = Selector(response.text)
script = selector.xpath("//script[contains(text(), 'window.__APP_DATA__')]/text()").get()
data = json.loads(re.findall(r"(\{.*?)(?=window\.__APP_META__)", script, re.DOTALL)[0])
return data
def parse_website_compare(response: Response, first_domain: str, second_domain: str) -> Dict:
"""parse website comparings inights between two domains"""
def parse_domain_insights(data: Dict, second_domain: Optional[bool]=None) -> Dict:
"""parse each website data and add it to each domain"""
data_key = data["layout"]["data"]
if second_domain:
data_key = data_key["compareCompetitor"] # the 2nd website compare key is nested
parsed_data = jmespath.search(
"""{
overview: overview,
traffic: traffic,
trafficSources: trafficSources,
ranking: ranking,
demographics: geography
}""",
data_key
)
return parsed_data
script_data = parse_hidden_data(response)
data = {}
data[first_domain] = parse_domain_insights(data=script_data)
data[second_domain] = parse_domain_insights(data=script_data, second_domain=True)
return data
async def scrape_website_compare(first_domain: str, second_domain: str) -> Dict:
"""parse website comparing data from similarweb comparing pages"""
url = f"https://www.similarweb.com/website/{first_domain}/vs/{second_domain}/"
response = await client.get(url)
data = parse_website_compare(response, first_domain, second_domain)
f"scraped comparing insights between {first_domain} and {second_domain}"
log.success(f"scraped comparing insights between {first_domain} and {second_domain}")
return data
In the above code, we use the previously defined parse_hidden_data to parse data from the page and define two additional functions:
- parse_website_compare: For organizing the JSON data and parsing it to exclude unnecessary details with JMESPath.
- scrape_website_compare: For defining the SimilarWeb comparison URL and requesting it, while utilizing the parsing logic.
Introduction to JMESPath – JSON query language which is used in web scraping to parse JSON datasets for scrape data.
With this final feature, our SimilarWeb scraper is complete. It can scrape extensive website traffic data from sitemaps, trending, domain, and comparison pages. However, our scraper will soon encounter a major challenge: scraping blocking!
Bypass SimilarWeb Web Scraping Blocking
We can successfully scrape SimilarWeb for a limited number of requests. However, attempting to scale our scraper will cause SimilarWeb to block the IP address or request us to log in:
SimilarWeb scraping blocking
This is where Webparsers can lend a hand for scraping SimilarWeb without getting blocked.
scrapfly middleware
Webparsers provides web scraping, screenshot, and extraction APIs for data collection at scale.
- Anti-bot protection bypass – scrape web pages without blocking!
- Rotating residential proxies – prevent IP address and geographic blocks.
- JavaScript rendering – scrape dynamic web pages through cloud browsers.
- Full browser automation – control browsers to scroll, input and click on objects.
- Format conversion – scrape as HTML, JSON, Text, or Markdown.
- Python and Typescript SDKs, as well as Scrapy and no-code tool integrations.
For example, with scrapfly all we have to do is enable the asp parameter and select a proxy country:
# standard web scraping code
import httpx
from parsel import Selector
response = httpx.get("some similarweb.com URL")
selector = Selector(response.text)
# in ScrapFly becomes this 👇
from scrapfly import ScrapeConfig, ScrapflyClient
# replaces your HTTP client (httpx in this case)
scrapfly = ScrapflyClient(key="Your ScrapFly API key")
response = scrapfly.scrape(ScrapeConfig(
url="website URL",
asp=True, # enable the anti scraping protection to bypass blocking
proxy_pool="public_residential_pool", # select the residential proxy pool
country="US", # set the proxy location to a specfic country
render_js=True # enable rendering JavaScript (like headless browsers) to scrape dynamic content if needed
))
# use the built in Parsel selector
selector = response.selector
# access the HTML content
html = response.scrape_result['content']
FAQ
To wrap up this guide on SimilarWeb web scraping, let’s examine some frequently asked questions.
Are there public APIs for SimilarWeb?
SimilarWeb offers a subscription-based API. However, extracting data from SimilarWeb is straightforward, and you can use it to create your own scraper API.
Summary
In this guide, we demonstrated how to scrape SimilarWeb with Python. We started by exploring and navigating the website through sitemap scraping. Then, we went through a step-by-step guide on scraping various SimilarWeb pages for traffic, rankings, trending, and comparison data.
We have also explored bypassing web scraping blocks on SimilarWeb using Webparsers and avoiding its validation challenges.
Legal Disclaimer and Precautions
This tutorial covers popular web scraping techniques for educational purposes. Interacting with public servers requires diligence and respect and here’s a good summary of what not to do:
- Do not scrape at rates that could damage the website.
- Do not scrape data that’s not available publicly.
- Do not store PII of EU citizens who are protected by GDPR.
- Do not repurpose the entire public datasets which can be illegal in some countries.
Webparsers does not offer legal advice but these are good general rules to follow in web scraping and for more you should consult a lawyer.