SEO Automation with Python Tools: Make Repetitive Work Run Efficiently
Why Does SEO Need Automation?
Highly repetitive SEO tasks:
- Daily rank checks (inefficient to do manually)
- Bulk page status-code checks (harder to do manually the larger the site)
- Monitoring competitors' newly published content
- Generating SEO reports on a regular schedule
- Bulk metadata optimization (for large-scale sites)
The value of automation:
- Saves 70-80% of the time spent on repetitive work
- Reduces human error
- Enables real-time monitoring (catch problems faster)
- Lets SEO staff focus on high-value analytical work
Core SEO Automation Libraries
Must-have Python libraries
# Basic crawling and requests
import requests
from bs4 import BeautifulSoup
# Data analysis
import pandas as pd
import numpy as np
# SEO-specific
from googlesearch import search # Google search results
import advertools # SEO data analysis
import serpapi # SERP data API
# Visualization
import matplotlib.pyplot as plt
Common SEO Automation Scripts
Script 1: Bulk page status check
import requests
import pandas as pd
from urllib.parse import urlparse
def check_url_status(urls):
results = []
for url in urls:
try:
response = requests.get(url, timeout=10, allow_redirects=True)
final_url = response.url
status_code = response.status_code
results.append({
"original_url": url,
"final_url": final_url,
"status_code": status_code,
"redirected": url != final_url
})
except Exception as e:
results.append({
"original_url": url,
"final_url": None,
"status_code": None,
"error": str(e)
})
return pd.DataFrame(results)
# Usage
urls_to_check = ["https://example.com/page1", "https://example.com/page2"]
results_df = check_url_status(urls_to_check)
results_df.to_csv("url_status_report.csv", index=False)
print(f"Check complete: {len(results_df)} URLs")
Script 2: Bulk extraction of SEO metadata
import requests
from bs4 import BeautifulSoup
import pandas as pd
def extract_seo_metadata(url):
try:
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.content, "html.parser")
# Extract basic SEO data
title = soup.find("title").text.strip() if soup.find("title") else ""
h1 = soup.find("h1").text.strip() if soup.find("h1") else ""
meta_desc = soup.find("meta", {"name": "description"})
description = meta_desc["content"] if meta_desc else ""
# Word count
body_text = soup.find("body").get_text() if soup.find("body") else ""
word_count = len(body_text.split())
# Internal-link count
internal_links = [a["href"] for a in soup.find_all("a", href=True)
if urlparse(a["href"]).netloc == "" or
"yourdomain.com" in urlparse(a["href"]).netloc]
return {
"url": url,
"title": title,
"title_length": len(title),
"h1": h1,
"description": description,
"description_length": len(description),
"word_count": word_count,
"internal_link_count": len(internal_links)
}
except Exception as e:
return {"url": url, "error": str(e)}
# Bulk extraction from a sitemap
sitemap_urls = ["https://example.com/page1", ...]
metadata_df = pd.DataFrame([extract_seo_metadata(url) for url in sitemap_urls])
metadata_df.to_csv("seo_metadata_audit.csv", index=False)
Script 3: Competitor content monitoring
import feedparser
import hashlib
import json
from datetime import datetime
def monitor_competitor_content(rss_feeds):
"""Monitor competitors' RSS feeds to discover new content"""
new_content = []
# Load known content hashes
try:
with open("known_content.json", "r") as f:
known_hashes = json.load(f)
except FileNotFoundError:
known_hashes = {}
for feed_url, competitor_name in rss_feeds.items():
feed = feedparser.parse(feed_url)
for entry in feed.entries:
content_hash = hashlib.md5(entry.link.encode()).hexdigest()
if content_hash not in known_hashes:
new_content.append({
"competitor": competitor_name,
"title": entry.title,
"url": entry.link,
"published": entry.published if hasattr(entry, "published") else ""
})
known_hashes[content_hash] = {
"url": entry.link,
"discovered_at": datetime.now().isoformat()
}
# Update known content
with open("known_content.json", "w") as f:
json.dump(known_hashes, f, ensure_ascii=False)
return new_content
# Usage example
rss_feeds = {
"https://competitor1.com/feed": "Competitor A",
"https://competitor2.com/rss.xml": "Competitor B"
}
new_articles = monitor_competitor_content(rss_feeds)
if new_articles:
print(f"Found {len(new_articles)} new pieces of competitor content!")
Script 4: Automatic sitemap updates
import xml.etree.ElementTree as ET
from datetime import datetime
def update_sitemap(sitemap_path, new_urls):
"""Add new URLs to a sitemap"""
tree = ET.parse(sitemap_path)
root = tree.getroot()
namespace = "http://www.sitemaps.org/schemas/sitemap/0.9"
ET.register_namespace("", namespace)
for url_data in new_urls:
url_element = ET.SubElement(root, f"{{{namespace}}}url")
loc = ET.SubElement(url_element, f"{{{namespace}}}loc")
loc.text = url_data["loc"]
lastmod = ET.SubElement(url_element, f"{{{namespace}}}lastmod")
lastmod.text = url_data.get("lastmod", datetime.now().strftime("%Y-%m-%d"))
priority = ET.SubElement(url_element, f"{{{namespace}}}priority")
priority.text = str(url_data.get("priority", 0.8))
tree.write(sitemap_path, encoding="UTF-8", xml_declaration=True)
print(f"Sitemap update complete; added {len(new_urls)} URLs")
Google Search Console API Automation
Use the GSC API to extract data automatically and avoid manual exports:
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
def get_gsc_data(site_url, start_date, end_date, dimensions=["query", "page"]):
"""Extract search data from the GSC API"""
scopes = ["https://www.googleapis.com/auth/webmasters.readonly"]
credentials = ServiceAccountCredentials.from_json_keyfile_name(
"service_account.json", scopes
)
service = build("searchconsole", "v1", credentials=credentials)
request = {
"startDate": start_date,
"endDate": end_date,
"dimensions": dimensions,
"rowLimit": 25000
}
response = service.searchanalytics().query(siteUrl=site_url, body=request).execute()
rows = response.get("rows", [])
data = [{
**{dim: row["keys"][i] for i, dim in enumerate(dimensions)},
"clicks": row["clicks"],
"impressions": row["impressions"],
"ctr": row["ctr"],
"position": row["position"]
} for row in rows]
return pd.DataFrame(data)
# Usage example
df = get_gsc_data("https://yourdomain.com", "2026-04-27", "2026-05-27")
df.to_csv("gsc_data.csv", index=False)
Conclusion
SEO automation is an important way to boost team efficiency. The scripts above provide the most common starting points for SEO automation. We recommend beginning with bulk status checks and metadata extraction, then gradually building out a complete SEO automation workflow. As your level of automation grows, your SEO team can devote more energy to high-value work such as strategic thinking and content creation.