August 6, 2026
Automating Recon with Python: 12 Scripts That Save Hours of Manual Work
Ever felt like reconnaissance is eating up your entire night — just poring over domains, subdomains, open ports, and every little crumb of…

By Very Lazy Tech 👾
6 min read
Ever felt like reconnaissance is eating up your entire night — just poring over domains, subdomains, open ports, and every little crumb of info? You're definitely not alone. Most IT folks and ethical hackers spend 60–70% of their pentesting time on recon alone. What if you could claw back hours, automate the grind, and spend your energy on the fun parts — like popping shells and chasing real vulnerabilities?
Let's dive deep into the practical side of automating recon with Python. These aren't just abstract scripts or "learning projects" — they're battle-tested, real-world tools I've personally used during bug bounties and internal assessments. Ready to slash your recon workload?
Why Automate Reconnaissance?
Before we get to the scripts, let's clarify why automation is a game-changer here. Recon isn't just about "finding domains." It's about:
- Spotting new assets before the blue team
- Scaling up: scanning 10, 100, or 1,000 targets without breaking a sweat
- Keeping consistent, repeatable processes (so you don't miss a low-hanging RCE again)
- Saving your brain for actual problem-solving
Manual recon is slow and error-prone. You'll forget that one weird subdomain, or typo an IP. But Python — well, it doesn't forget, get bored, or need coffee breaks.
Alright, let's get our hands dirty.
Script 1: Mass Subdomain Enumeration with subdomain_finder.py
Subdomain enumeration is the absolute bread-and-butter of recon. Many of the juiciest vulnerabilities hide behind obscure or forgotten subdomains.
How It Works
This script takes a domain and checks a list of possible subdomains (like admin, dev, test) using DNS queries. Not rocket science, but beating the pants off manual checks.
Example Code
import requests
def find_subdomains(domain, wordlist_path):
found = []
with open(wordlist_path, 'r') as f:
prefixes = [line.strip() for line in f.readlines()]
for prefix in prefixes:
url = f"http://{prefix}.{domain}"
try:
res = requests.get(url, timeout=2)
if res.status_code < 400:
print(f"[+] Found: {url}")
found.append(url)
except:
pass
return found
if __name__ == "__main__":
target = "example.com"
find_subdomains(target, "common_subs.txt")import requests
def find_subdomains(domain, wordlist_path):
found = []
with open(wordlist_path, 'r') as f:
prefixes = [line.strip() for line in f.readlines()]
for prefix in prefixes:
url = f"http://{prefix}.{domain}"
try:
res = requests.get(url, timeout=2)
if res.status_code < 400:
print(f"[+] Found: {url}")
found.append(url)
except:
pass
return found
if __name__ == "__main__":
target = "example.com"
find_subdomains(target, "common_subs.txt")Tips
- Use a solid subdomain wordlist, like Seclists.
- Threading can speed it up, but beware rate limits.
Script 2: Port Scanning (Better Than Nmap? Sometimes!)
Nmap's awesome, but sometimes you want a fast, customizable scan or to embed it in a bigger workflow.
Why Bother?
- Programmatic control: trigger scans on new hosts automatically.
- Parse results directly—no grep or XML wrangling.
Sample Python Port Scanner
import socket
def scan_ports(host, ports):
for port in ports:
sock = socket.socket()
sock.settimeout(0.5)
try:
sock.connect((host, port))
print(f"[OPEN] {host}:{port}")
except:
pass
finally:
sock.close()
if __name__ == "__main__":
scan_ports("127.0.0.1", range(1, 1025))import socket
def scan_ports(host, ports):
for port in ports:
sock = socket.socket()
sock.settimeout(0.5)
try:
sock.connect((host, port))
print(f"[OPEN] {host}:{port}")
except:
pass
finally:
sock.close()
if __name__ == "__main__":
scan_ports("127.0.0.1", range(1, 1025))Where It Shines
- Combine it with other scripts. Auto-scan new subdomains after finding them.
- Use for custom, targeted scans (just web ports, just rare ports).
Script 3: Banner Grabbing for Quick Fingerprinting
Sometimes you need to know what service/version is running — fast.
Banner Grabbing Script
import socket
def grab_banner(host, port):
s = socket.socket()
s.settimeout(1)
try:
s.connect((host, port))
banner = s.recv(1024)
print(f"Banner for {host}:{port} — {banner.decode().strip()}")
except Exception as e:
print(f"No banner for {host}:{port}")
finally:
s.close()
# Try it:
grab_banner("scanme.nmap.org", 80)import socket
def grab_banner(host, port):
s = socket.socket()
s.settimeout(1)
try:
s.connect((host, port))
banner = s.recv(1024)
print(f"Banner for {host}:{port} — {banner.decode().strip()}")
except Exception as e:
print(f"No banner for {host}:{port}")
finally:
s.close()
# Try it:
grab_banner("scanme.nmap.org", 80)Practical Use
- Identify weird or outdated services (think FTP, Telnet, or accidental dev servers).
- Feed into vulnerability checks—see a version, check for exploits.
Script 4: Directory and File Bruteforcing (dirbuster.py)
Web servers love to leak secrets in forgotten directories. Automating dir busting is a must.
Sample Script
import requests
def dir_brute(base_url, wordlist_path):
with open(wordlist_path, 'r') as f:
dirs = [line.strip() for line in f]
for d in dirs:
url = f"{base_url}/{d}"
try:
res = requests.get(url, timeout=2)
if res.status_code not in [404, 403]:
print(f"Found: {url} ({res.status_code})")
except:
pass
dir_brute("http://example.com", "dirs.txt")import requests
def dir_brute(base_url, wordlist_path):
with open(wordlist_path, 'r') as f:
dirs = [line.strip() for line in f]
for d in dirs:
url = f"{base_url}/{d}"
try:
res = requests.get(url, timeout=2)
if res.status_code not in [404, 403]:
print(f"Found: {url} ({res.status_code})")
except:
pass
dir_brute("http://example.com", "dirs.txt")Where It Saves Time
- Finds admin panels, dev folders, debug endpoints.
- Easy to point at every web service you found during subdomain enum.
Script 5: Screenshot Automation for Recon Visuals
You might think, "why do screenshots matter?" In practice, a single look at a login page or error can tell you more than lines of HTML.
Python Screenshotter (with Selenium and Headless Chrome)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def screenshot_url(url, output):
options = Options()
options.headless = True
driver = webdriver.Chrome(options=options)
try:
driver.get(url)
driver.save_screenshot(output)
print(f"Saved screenshot for {url} as {output}")
finally:
driver.quit()
# Example usage:
screenshot_url("http://example.com/login", "login_page.png")from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def screenshot_url(url, output):
options = Options()
options.headless = True
driver = webdriver.Chrome(options=options)
try:
driver.get(url)
driver.save_screenshot(output)
print(f"Saved screenshot for {url} as {output}")
finally:
driver.quit()
# Example usage:
screenshot_url("http://example.com/login", "login_page.png")Bonus: Batch Screenshots
- Loop through every found domain and save images.
- Easily review dozens of targets visually.
Script 6: Passive Recon with Shodan API
Shodan knows things you don't. Why not make it do the work?
Shodan Query Script
You'll need a Shodan API Key (free account is enough for basic use).
import requests
def shodan_search(query, api_key):
url = f"https://api.shodan.io/shodan/host/search?key={api_key}&query={query}"
resp = requests.get(url)
data = resp.json()
for result in data.get('matches', []):
print(f"{result['ip_str']}:{result['port']} — {result['hostnames']}")
# Use it:
api_key = "YOUR_SHODAN_API_KEY"
shodan_search("apache country:US", api_key)import requests
def shodan_search(query, api_key):
url = f"https://api.shodan.io/shodan/host/search?key={api_key}&query={query}"
resp = requests.get(url)
data = resp.json()
for result in data.get('matches', []):
print(f"{result['ip_str']}:{result['port']} — {result['hostnames']}")
# Use it:
api_key = "YOUR_SHODAN_API_KEY"
shodan_search("apache country:US", api_key)How This Helps
- Find exposed cams, databases, or IoT with single queries.
- Automate background checks on your recon targets.
Script 7: Reverse WHOIS Lookup for Asset Discovery
Finding all domains owned by a company can lead you straight to forgotten dev sites.
Simple Reverse WHOIS Lookup
Uses a third-party API (like WhoisXML). You'll need an API key.
import requests
def reverse_whois(email, api_key):
url = f"https://www.whoisxmlapi.com/whoisserver/WhoisService?apiKey={api_key}&emailAddress={email}&outputFormat=JSON"
resp = requests.get(url)
print(resp.json())
# Example:
reverse_whois("security@example.com", "YOUR_API_KEY")import requests
def reverse_whois(email, api_key):
url = f"https://www.whoisxmlapi.com/whoisserver/WhoisService?apiKey={api_key}&emailAddress={email}&outputFormat=JSON"
resp = requests.get(url)
print(resp.json())
# Example:
reverse_whois("security@example.com", "YOUR_API_KEY")Why Bother?
- Maps out external attack surface. Perfect for bug bounty.
- Chases down shadow IT.
Script 8: Favicon Hashing for Service Identification
Here's where it gets interesting: some orgs reuse favicons across hundreds of sites. You can hunt them down by favicon hash.
Quick Hash & Search
import requests
import hashlib
def favicon_hash(url):
try:
res = requests.get(f"{url}/favicon.ico", timeout=2)
if res.status_code == 200:
hashval = hashlib.md5(res.content).hexdigest()
print(f"{url}/favicon.ico MD5: {hashval}")
except:
print(f"Could not retrieve favicon for {url}")
favicon_hash("http://example.com")import requests
import hashlib
def favicon_hash(url):
try:
res = requests.get(f"{url}/favicon.ico", timeout=2)
if res.status_code == 200:
hashval = hashlib.md5(res.content).hexdigest()
print(f"{url}/favicon.ico MD5: {hashval}")
except:
print(f"Could not retrieve favicon for {url}")
favicon_hash("http://example.com")Practical Use
- Find clusters of related servers (sometimes on different domains).
- Cross-reference hashes on Shodan or Censys.
Script 9: Automated Google Dorking (OSINT Goldmine)
Manually dorking in Google? Painful and slow. Automate it.
Basic Google Dorker
(Heads-up: Google's API is paid and restrictive — use with care, and expect to get blocked if you hammer it.)
import requests
from bs4 import BeautifulSoup
def google_dork(query):
url = f"https://www.google.com/search?q={query}"
headers = {"User-Agent": "Mozilla/5.0"}
res = requests.get(url, headers=headers)
soup = BeautifulSoup(res.text, "html.parser")
for g in soup.find_all('div', class_='g'):
link = g.find('a', href=True)
if link:
print(link['href'])
google_dork("site:example.com ext:sql")import requests
from bs4 import BeautifulSoup
def google_dork(query):
url = f"https://www.google.com/search?q={query}"
headers = {"User-Agent": "Mozilla/5.0"}
res = requests.get(url, headers=headers)
soup = BeautifulSoup(res.text, "html.parser")
for g in soup.find_all('div', class_='g'):
link = g.find('a', href=True)
if link:
print(link['href'])
google_dork("site:example.com ext:sql")Where It Delivers
- Finds exposed files, backups, or test pages indexed by Google.
- Automate for every new subdomain or asset.
Script 10: DNS Zone Transfer Tester
Sometimes, misconfigurations let you dump a full DNS zone and uncover everything.
Simple AXFR Tester
import dns.query
import dns.zone
def test_zone_transfer(domain, ns):
try:
z = dns.zone.from_xfr(dns.query.xfr(ns, domain))
for n in z.nodes.keys():
print(z[n].to_text(n))
except Exception as e:
print(f"Zone transfer failed for {domain} @ {ns}")
test_zone_transfer("example.com", "ns1.example.com")import dns.query
import dns.zone
def test_zone_transfer(domain, ns):
try:
z = dns.zone.from_xfr(dns.query.xfr(ns, domain))
for n in z.nodes.keys():
print(z[n].to_text(n))
except Exception as e:
print(f"Zone transfer failed for {domain} @ {ns}")
test_zone_transfer("example.com", "ns1.example.com")Real-World Use
- Occasionally, you'll hit gold and map entire organizations.
- Should be in every recon toolbox.
Script 11: Extracting Emails and Secrets from Web Pages
Scraping emails and leaked secrets (API keys, tokens, etc.) can point you to privilege escalation or RCE vectors.
Email/Sensitive Data Scraper
import requests
import re
def scrape_emails(url):
res = requests.get(url)
emails = set(re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", res.text))
print(f"Emails found at {url}:")
for email in emails:
print(email)
scrape_emails("https://example.com/contact")import requests
import re
def scrape_emails(url):
res = requests.get(url)
emails = set(re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", res.text))
print(f"Emails found at {url}:")
for email in emails:
print(email)
scrape_emails("https://example.com/contact")Extend It
- Add regexes for AWS keys, API tokens, or JWTs.
- Point it at all your found endpoints.
Script 12: Live Asset Monitoring (Continuous Recon)
Why stop at one recon run? Set up continuous asset monitoring. Catch new assets or exposures as they appear.
Watchdog Script
import time
import hashlib
import requests
def monitor(url, interval=3600):
last_hash = None
while True:
try:
res = requests.get(url)
current_hash = hashlib.md5(res.content).hexdigest()
if last_hash and last_hash != current_hash:
print(f"Change detected at {url}!")
last_hash = current_hash
except:
print(f"Could not fetch {url}")
time.sleep(interval)
# Example: monitor homepage every hour
# monitor("https://example.com", 3600)import time
import hashlib
import requests
def monitor(url, interval=3600):
last_hash = None
while True:
try:
res = requests.get(url)
current_hash = hashlib.md5(res.content).hexdigest()
if last_hash and last_hash != current_hash:
print(f"Change detected at {url}!")
last_hash = current_hash
except:
print(f"Could not fetch {url}")
time.sleep(interval)
# Example: monitor homepage every hour
# monitor("https://example.com", 3600)How to Use
- Spot changes on login pages, API docs, or admin panels.
- Set alerts (email, Discord, etc.) for real-time notifications.
Making Automation Work for You
Now, you might be thinking, "but won't these scripts overlap?" Absolutely — they should! The real art is chaining your tools:
- Find subdomains → scan for open ports → grab banners
- Bruteforce directories → scrape for secrets
- Hash favicons → map related assets
- Monitor changes → trigger new scans
You can even orchestrate everything with a main Python script, or (if you're feeling fancy) tie it into a CI/CD pipeline for continuous recon.
Tips for Scaling Recon Automation
- Threading and async: Speed up large scans, but pace yourself to avoid bans or rate limits.
- Data storage: Dump results to CSV/JSON for later analysis.
- Modular scripts: Keep scripts focused; combine them creatively instead of making one monster script.
- Visualization: Use tools like Maltego, BloodHound, or even simple Graphviz to visualize relationships.
Real-World: How These Scripts Save Time in Pentesting and Bug Bounties
I've run these scripts on bug bounty scopes with thousands of assets. The time saved is wild — what used to take two days now happens in an hour. Even better, automation reduces human mistakes. No more missing that sneaky dev server or rare port because you spaced out.
Plus, the cool part? Automation gives you a repeatable process. When a new host pops up in scope, re-running your full recon takes minutes, not hours.
What's Next?
Take these scripts, tinker, and adapt them to your own recon flow. Add integrations (like Slack alerts or database storage). The more you personalize, the more hours you'll save — and the more likely you'll catch that RCE or SQLi before anyone else.
So — ready to automate your recon and actually enjoy more of your pentesting? There's no "one size fits all," but with these 12 scripts, you'll have a launcher pad for smarter, faster, and more effective cybersecurity reconnaissance.
Go ahead — let Python do the heavy lifting. Your next big bounty (or incident) might just thank you.
🚀 Become a VeryLazyTech Member — Get Instant Access
What you get today:
✅ 70GB Google Drive packed with cybersecurity content
✅ 3 full courses to level up fast
👉 Join the Membership → https://shop.verylazytech.com
📚 Need Specific Resources?
✅ Instantly download the best hacking guides, OSCP prep kits, cheat sheets, and scripts used by real security pros.
👉 Visit the Shop → https://shop.verylazytech.com
💬 Stay in the Loop
Want quick tips, free tools, and sneak peeks?
| 👾 https://github.com/verylazytech/
| 📺 https://youtube.com/@verylazytech/
| 📩 https://t.me/+mSGyb008VL40MmVk/
| 🕵️♂️ https://www.verylazytech.com/