DEV Community

Cover image for Five Minutes Per Site Times 500 Sites Is Not Five Minutes, So I Scripted It
Boris Dzhingarov
Boris Dzhingarov

Posted on

Five Minutes Per Site Times 500 Sites Is Not Five Minutes, So I Scripted It

I published a checklist in Forbes this week on how to tell a real publication from a content farm before you pitch it. The premise is that five minutes inside a site's archive tells you whether anyone is home: read five recent articles, check whether the bylines belong to people who exist, see if the site stays in one lane or covers pet insurance and industrial valves on the same day, look for a masthead.

The first reply I got was from someone on my own team, and it was fair. Five minutes per site is fine. Five minutes times the 500 domains on a typical outreach list is 41 hours, and nobody is doing that on a Tuesday.

So I did the thing I keep doing lately: opened Claude Code and described the checklist as if it were a program.

It is a publication-shaped object. Nobody is inside.

That's the line from the Forbes piece I wanted the script to detect, and most of the signals behind it turn out to be countable.

What a machine can check

Not everything on the checklist survives translation into code. "Does the writing hold something a machine could not know" is a human judgment and it stays one. But four of the checks are just arithmetic on the RSS feed and a couple of HTTP requests.

Posting frequency. A real trade publication with three editors produces a handful of articles a day at most. A farm produces one every twenty minutes. The feed timestamps give you posts per day in two lines.

Byline diversity. Farms either have one author called "admin" on everything, or a different invented name on every post and none of them twice. Both patterns are visible in a counter.

Topic spread. Fifty recent posts across sixty distinct tags is a site that serves no reader in particular.

Masthead. Real publications have an about page and a contact page, and the pages tell you who edits the thing. Hollow sites often 404 on both, because there is nobody to list.

import feedparser, requests, collections
from datetime import datetime

def vet(domain):
    feed = feedparser.parse(f"https://{domain}/feed")
    entries = feed.entries[:50]
    if not entries:
        return {"domain": domain, "verdict": "no feed, check by hand"}

    dates = [datetime(*e.published_parsed[:6])
             for e in entries if hasattr(e, "published_parsed")]
    span = max((max(dates) - min(dates)).days, 1)

    authors = collections.Counter(e.get("author", "none") for e in entries)
    tags = {t.term for e in entries for t in e.get("tags", [])}

    pages = {}
    for path in ("/about", "/contact"):
        try:
            pages[path] = requests.get(f"https://{domain}{path}", timeout=10).status_code
        except requests.RequestException:
            pages[path] = "err"

    return {
        "domain": domain,
        "posts_per_day": round(len(dates) / span, 1),
        "distinct_authors": len(authors),
        "top_author_share": round(authors.most_common(1)[0][1] / len(entries), 2),
        "tag_count": len(tags),
        "pages": pages,
    }
Enter fullscreen mode Exit fullscreen mode

The flags on top are deliberately dumb: more than twenty posts a day, one author on more than 90% of posts or fifty authors on fifty posts, more tags than articles, and a 404 on both /about and /contact. Any two together and the domain goes to the "probably hollow" pile. One alone means nothing, which matters, because a small trade journal with a single editor who writes everything would trip the byline check and be exactly the kind of site you want.

The check that needed a model

The fifth signal is the one I added to the checklist this year: ask an AI assistant a few questions about the topics the site claims to cover and see whether it ever gets cited. That one is not arithmetic, but I already had the loop for it. My last post here was the same idea pointed at company names. Point it at domains instead and you get a rough census of which sources the wider web takes seriously.

The numbers behind that are lopsided in a useful direction. Graphite found that 82% of the articles ChatGPT and Perplexity cite were written by humans, at the same time as roughly half of all new articles on the web are now AI-generated. Farms publish half the web and get a fifth of the citations. A site that never shows up in an answer, on its own topic, has already been judged.

Why it lives on a server now

The first version ran in a terminal on my laptop and stopped existing when the laptop slept, which was a problem, because a list of 500 domains with a ten second timeout each is an hour and a half of not closing the lid. I moved it to the same $6 box that runs my indexing monitor, added a cron line, and now a CSV of domains dropped into a folder on Sunday night is a scored list on Monday morning.

I wrote up the general case of that move on my own blog, including the part I underestimated: an always-on script holding API keys is a different security posture from a tab you close. Scoped credentials, a firewall, and a monthly hour of maintenance are the price. The server is cheap. The attention is not.

What it costs me, specifically

A confession that belongs here. My agency, ESBO Ltd, sells placements. A script whose whole job is to say no to 470 of 500 domains is not obviously good for a company that gets paid per placement. It shrinks the menu.

I built it anyway, because the 470 were never producing anything. Coverage on a farm is a press release into a void, and in the campaigns I've tracked it doesn't move rankings, doesn't send traffic, and never gets cited by anything. The 30 that survive are slower to earn and they are the only ones that were ever worth the invoice. I would rather sell thirty things that work than five hundred that look like they might.

What it still can't do

It can't tell a new publication from a hollow one, because both have thin archives. It can't judge whether a small site's 5,000 readers happen to be your exact buyers, which is the case where size lies. And it can't read. The last 30 still get the five minutes, by a person, and the script's only real achievement is making sure those five minutes go to sites where someone might be on the other side.

If you've automated any part of judging whether a website is real, I'd like to know which signal you trust most. Mine is the masthead. Everything else can be faked cheaply. A named editor with a LinkedIn history costs more to fabricate than most farms are willing to spend.

Top comments (0)