Python 1 min read
Automating Repetitive Recon Tasks With Python
March 5, 2026
Reconnaissance involves a lot of repetitive checking: is this host alive, what does it respond with, what's actually on the page. Doing that by hand for more than a handful of targets gets old fast, so I wrote a small script to handle the first pass.
The goal
Take a list of subdomains and produce a clean table showing, for each one:
- Whether it responded
- The HTTP status code
- The page
<title>, if any
It is only a first pass, but it quickly shows which hosts are worth checking manually.
The script
import requests
from bs4 import BeautifulSoup
def check_host(host: str) -> dict:
url = f"https://{host}"
try:
response = requests.get(url, timeout=5)
title = BeautifulSoup(response.text, "html.parser").title
return {
"host": host,
"status": response.status_code,
"title": title.string.strip() if title else "—",
}
except requests.RequestException:
return {"host": host, "status": "unreachable", "title": "—"}
def main(subdomain_file: str):
with open(subdomain_file) as f:
hosts = [line.strip() for line in f if line.strip()]
results = [check_host(h) for h in hosts]
print(f"{'HOST':30} {'STATUS':10} {'TITLE'}")
for r in results:
print(f"{r['host']:30} {str(r['status']):10} {r['title']}")
if __name__ == "__main__":
main("subdomains.txt")
Why I wrote it
- It is a filter, not a replacement for thinking. The script removes dead or unreachable hosts from the first pass; deciding what matters still requires manual work.
- The exception handling keeps one bad host from stopping the run. Timeouts, DNS failures, and connection errors are handled by the same exception type.
- The five-second timeout is a trade-off. A shorter timeout can skip slow hosts; a longer one makes unreachable hosts take more time.
What I would change next
The script currently checks hosts one at a time. For larger lists, I would use concurrent.futures.ThreadPoolExecutor to make the requests concurrently.