SEO Automation and Python Tools: Make Repetitive Work Run Efficiently

SEO Automation with Python Tools: Make Repetitive Work Run Efficiently

Why Does SEO Need Automation?

Highly repetitive SEO tasks:

The value of automation:

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.