Technical SEO audits can become complicated very quickly.
You can crawl thousands of URLs, export dozens of reports, connect Search Console data, analyze Core Web Vitals, inspect structured data, and end up with a spreadsheet containing hundreds of issues.
Sometimes that is necessary.
But for many small and medium-sized websites, I prefer to start with something much simpler: a short technical check that answers a few basic questions.
- Can search engines access the page?
- Does the page return the correct HTTP status?
- Is the canonical URL correct?
- Is the page accidentally set to
noindex? - Does it have a meaningful title and meta description?
- Is there a single, clear H1?
- Are important images missing alternative text?
- Are there obvious internal linking problems?
Most of these checks can be automated with a surprisingly small Python script.
Building a Simple SEO Checker in Python
We'll use two libraries:
pip install requests beautifulsoup4
Then create a file called:
quick_seo_check.py
Here is a basic version:
import sys
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
HEADERS = {
"User-Agent": "Mozilla/5.0 (compatible; QuickSEOCheck/1.0)"
}
def analyze_page(url):
try:
response = requests.get(
url,
headers=HEADERS,
timeout=10,
allow_redirects=True
)
except requests.RequestException as error:
print(f"Request failed: {error}")
return
print(f"\nURL: {url}")
print(f"Final URL: {response.url}")
print(f"Status code: {response.status_code}")
soup = BeautifulSoup(response.text, "html.parser")
# Title
title = soup.title.string.strip() if soup.title and soup.title.string else ""
print(f"\nTitle: {title}")
print(f"Title length: {len(title)}")
# Meta description
description = soup.find("meta", attrs={"name": "description"})
description_content = (
description.get("content", "").strip()
if description else ""
)
print(f"\nMeta description: {description_content}")
print(f"Description length: {len(description_content)}")
# Robots
robots = soup.find("meta", attrs={"name": "robots"})
robots_content = robots.get("content", "") if robots else "Not specified"
print(f"\nMeta robots: {robots_content}")
# Canonical
canonical = soup.find("link", attrs={"rel": "canonical"})
canonical_url = canonical.get("href") if canonical else "Missing"
print(f"Canonical: {canonical_url}")
# H1
h1_tags = soup.find_all("h1")
print(f"\nH1 count: {len(h1_tags)}")
for index, h1 in enumerate(h1_tags, start=1):
print(f"H1 #{index}: {h1.get_text(' ', strip=True)}")
# Images without alt text
images = soup.find_all("img")
missing_alt = [
img.get("src")
for img in images
if not img.has_attr("alt") or not img.get("alt", "").strip()
]
print(f"\nImages: {len(images)}")
print(f"Images missing alt text: {len(missing_alt)}")
for image in missing_alt[:10]:
print(f" - {image}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python quick_seo_check.py https://example.com/page")
sys.exit(1)
analyze_page(sys.argv[1])
Run it like this:
python quick_seo_check.py https://example.com/
In a few seconds you get a compact overview of some of the most common technical SEO problems on the page.
Why Start Small?
SEO tools are excellent, but sometimes they hide simple problems inside large reports.
For example, imagine a local business website with only 30 pages.
You probably don't need a 5,000-row spreadsheet to discover that:
/services/
returns a 302 redirect,
/contact/
has a noindex tag,
and three important landing pages share the same title.
A small script can expose those problems immediately.
This approach is especially useful for local business websites, where technical problems often affect a relatively small number of commercially important pages. That's something I regularly look at when working as an SEO consultant in Netanya and on similar local SEO projects.
The goal isn't to replace a crawler.
The goal is to find the obvious problems before opening a much larger toolbox.
Finding Internal Links
We can extend the script to collect all internal links found on the page.
Add this function:
def get_internal_links(soup, current_url):
domain = urlparse(current_url).netloc
links = set()
for anchor in soup.find_all("a", href=True):
href = anchor["href"].strip()
if href.startswith(("#", "mailto:", "tel:", "javascript:")):
continue
absolute_url = urljoin(current_url, href)
parsed_url = urlparse(absolute_url)
if parsed_url.netloc == domain:
clean_url = absolute_url.split("#")[0]
links.add(clean_url)
return sorted(links)
Then inside analyze_page():
internal_links = get_internal_links(soup, response.url)
print(f"\nInternal links found: {len(internal_links)}")
for link in internal_links:
print(f" - {link}")
Now the script can quickly show where the page is sending users and crawlers.
That becomes useful when troubleshooting orphan pages, navigation problems, or landing pages that don't receive enough internal links.
Checking Links for Broken URLs
We can go one step further:
def check_link(url):
try:
response = requests.head(
url,
headers=HEADERS,
timeout=5,
allow_redirects=True
)
return response.status_code
except requests.RequestException:
return "ERROR"
And then:
for link in internal_links:
status = check_link(link)
if status != 200:
print(f"{status}: {link}")
I wouldn't use this approach to crawl a site with hundreds of thousands of pages.
But for a quick manual audit of a small website, it can be surprisingly effective.
A Useful Browser Console Check
Python isn't always necessary.
Sometimes the browser console is the fastest SEO tool available.
For example, this JavaScript snippet identifies images without an alt attribute:
[...document.querySelectorAll("img")]
.filter(img => !img.hasAttribute("alt") || !img.alt.trim())
.map(img => img.src);
Paste it into Chrome DevTools → Console.
You can also find links without meaningful anchor text:
[...document.querySelectorAll("a")]
.filter(link => !link.innerText.trim())
.map(link => link.href);
Or inspect heading structure:
[...document.querySelectorAll("h1, h2, h3, h4, h5, h6")]
.map(heading => ({
tag: heading.tagName,
text: heading.innerText.trim()
}));
These aren't sophisticated tools.
That's exactly why I like them.
They're fast.
Don't Automate the Thinking Part
One mistake I see in technical SEO is treating every warning as a problem that must be fixed.
A missing meta description isn't necessarily catastrophic.
Multiple H1 elements aren't automatically a ranking disaster.
A redirect isn't necessarily wrong.
An image without an alt attribute might even be intentional if the image is purely decorative.
Scripts should help you find things worth investigating.
They shouldn't make the final decision.
Think of automation as a filter:
Website
↓
Automated checks
↓
Potential issues
↓
Manual review
↓
Actual SEO tasks
That last manual-review step is still important.
What I'd Add Next
A more complete version of this script could also check:
- redirect chains
- canonical mismatches
-
nofollowdirectives - response times
- duplicate titles
- Open Graph tags
- JSON-LD structured data
- broken internal links
- image file sizes
- pages linked with too many parameters
- missing viewport tags
- hreflang implementation
You could eventually turn it into a small crawler.
But I wouldn't start there.
Start with the checks you actually need, automate repetitive work, and add functionality only when it solves a real problem.
Final Thought
The most useful technical SEO tools aren't always the biggest ones.
Sometimes a 50-line Python script, Chrome DevTools, and ten minutes of focused investigation can tell you more than another giant exported report.
Automation works best when it removes repetitive work and leaves the interesting part — understanding what actually matters — to the person doing the audit.
Top comments (0)