DEV Community

Machine4321
Machine4321

Posted on • Originally published at softa-analyysi.com

How I Automated Internal Linking for My B2B SaaS Review Blog Using Python

Internal linking is one of the most overlooked ranking factors in SEO.

For high-ticket affiliate sites—especially in competitive niches like B2B SaaS reviews—structuring your links correctly is the difference between ranking on page 1 of Google or page 10. You want your informational posts linking back to your "Hub" pages (like your "Best CRM Tools" or "Best Accounting Software" reviews) to pass on page authority (Link Juice).

But doing this manually across hundreds of posts is incredibly tedious.

To solve this, I built a Python engine that runs automatically, categorizes my articles, matches key search terms, and safely injects internal HTML links into my WordPress/Astro content database without breaking layouts.

Here is exactly how I built it and how you can implement it.


The Architecture: How the Internal Linker Works

Our Python script performs three main tasks:

  1. Fetch Articles: Download all published and scheduled posts via the WordPress/Astro REST API.
  2. Build Keyword-to-Link Map: Scan post titles, tag them into niches (CRM, Finance, VPN, Web Builders), and generate a sorted dictionary of keywords to link.
  3. Regex Search & Inject: Safely parse raw article HTML, find matching keywords, and wrap them in anchor tags.

🛠️ The Python Implementation

Here is a simplified, functional version of the automated internal linking script.

1. The Mapping Engine

First, we define which keywords should trigger links to specific articles based on their niche. For example, if we have a guide on sales tracking, we want the keyword "CRM" in any other article to link back to our CRM guide.

import re

def build_keyword_map(posts):
    link_targets = {}
    for p in posts:
        title = p['title'].lower()
        url = p['link']
        keywords = []
        is_hub = False

        # Identify Hub articles (e.g. review guides)
        if any(kw in title for kw in ["paras", "arvostelu", "vertailu", "opas"]):
            is_hub = True

        # Niche 1: CRM & Sales Tools
        if any(kw in title for kw in ["crm", "myynnin", "asiakkuus"]):
            keywords.extend(["crm-järjestelmä", "asiakkuudenhallinta", "crm-työkalu"])

        # Niche 2: Finance & Accounting Tools
        if any(kw in title for kw in ["laskutus", "kirjanpito", "laina"]):
            keywords.extend(["laskutusohjelma", "kirjanpito", "yrityslaina"])

        if keywords:
            link_targets[p['id']] = {
                "url": url,
                "is_hub": is_hub,
                # Sort keywords by length descending so long-tail phrases are matched first
                "keywords": sorted(list(set(keywords)), key=len, reverse=True)
            }
    return link_targets
Enter fullscreen mode Exit fullscreen mode

2. The Link Injection Logic

When parsing text, we must make sure we never inject links inside:

  • Existing anchor (<a>) tags (to avoid nested links).
  • Image (<img>) source or alt tags.
  • Heading (<h1>, <h2>, etc.) elements where it might look spammy.

We use regex to search for the keyword outside of HTML tags and replace it:

def inject_link(html_content, keyword, url):
    # Regex to match keyword only outside of HTML tags and existing anchors
    pattern = re.compile(
        rf'(?<!href=")(?<!src=")(?<!>)\b({re.escape(keyword)})\b(?![^<]*</a>)(?![^<]*>)', 
        re.IGNORECASE
    )

    # Inject link only for the first occurrence to avoid link stuffing
    new_html, count = pattern.subn(f'<a href="{url}">{keyword}</a>', html_content, count=1)
    return new_html, count
Enter fullscreen mode Exit fullscreen mode

📈 Real-World Results

I run this script daily as part of my automated publishing robot. It powers my Finnish B2B software comparison site Softa-analyysi.

Since implementing the auto-linker:

  • Indexation Time: New reviews are discovered and indexed by Google search crawlers in hours instead of days because they are instantly linked from related historical posts.
  • Domain Authority Boost: Link equity is distributed perfectly to money-generating Hub reviews.
  • Zero Overhead: The script runs in a lightweight container alongside my data crawlers (like my Trustpilot Reviews Scraper, which I use to gather customer feedback for competitor SaaS analysis).

Automating the small tasks like internal linking and review monitoring allows you to scale content websites to thousands of pages with almost zero maintenance.


How do you handle internal linking in your stack? Let me know in the comments!

Top comments (0)