Search engines like Shodan and Censys are great, but they show you an index — data collected on their schedule, which can be hours, days, or weeks old. Sometimes you don't want the last snapshot. You want to know what's open right now.
That's the gap ScanSearch fills: instead of querying a pre-built index, you trigger a real SYN + service-detection scan of a target through a REST API and get current results back in seconds. Here's how to drive it from Python.
Install
The SDK is open source (MIT). Until the PyPI release it installs straight from GitHub:
pip install git+https://github.com/ScanSearch/scansearch-python.git
Grab an API key from your dashboard at https://scansearch.net/dashboard/api-keys/ and export it — the client picks it up automatically:
export SCANSEARCH_API_KEY="your-key"
The free tier scans at 2 kpps, which is plenty to follow along.
Scan a CIDR and wait for the result
from scansearch import Client
api = Client() # reads SCANSEARCH_API_KEY from the environment
job = api.scan(
targets=["192.0.2.0/24"],
ports="80,443,8080,8443",
modules=["ports", "services"],
)
result = api.scan_wait(job["task_id"])
print(f"open ports: {result['open_ports_found']}")
print(f"services: {result['services_found']}")
modules=["ports", "services"] means you get open ports plus service identification — banners, product/version, TLS certificate details, and JARM/JA3S fingerprints — per host/port.
Fire-and-forget for big targets
A /24 finishes fast. A whole country does not, so don't block on it — kick it off, store the task_id, and poll when you're ready:
job = api.scan(targets=["country:DE"], ports="9200")
print("task_id:", job["task_id"])
# ...later, from anywhere
print(api.scan_status(job["task_id"]))
Targets can be a single IP, a CIDR, a list of CIDRs, a domain list, or a country:<CC> code.
Turn up the speed
Scan rate is set per call (capped by your plan). Higher speed = the same job finishes sooner:
job = api.scan(
targets=["10.0.0.0/16", "192.168.0.0/16"],
ports="1-1024",
modules=["ports", "services"],
speed=1000, # kpps
)
api.scan_wait(job["task_id"], poll_interval=10)
# changed your mind?
api.scan_stop(job["task_id"])
Handle the errors you'll actually hit
from scansearch import Client, AuthError, RateLimitError, NotFoundError, APIError
try:
api.scan_status(99999)
except NotFoundError:
... # no such task
except RateLimitError:
... # daily quota or per-minute limit
except AuthError:
... # bad / revoked key
except APIError as e:
print(e.status, e.body)
Prefer the shell?
Everything above has a CLI equivalent:
scansearch scan 192.0.2.0/24 --ports 80,443,8080 --modules ports,services --wait
scansearch scan country:DE --ports 9200 --speed 1000 --wait
scansearch status 1234
scansearch stop 1234
Where on-demand scanning beats an index
- Bug-bounty recon — scan your in-scope CIDRs fresh and grab current open ports + banners, not last month's.
- Asset discovery / shadow IT — point it at your own AS or netblocks and find what's exposed that shouldn't be.
- Continuous monitoring — scan your ranges daily, diff the results, alert on new open ports.
-
Vulnerability triage — combine
servicesenrichment with CVE matching to find newly exposedssh,rdp,elasticsearch, etc.
Links
- Source (Python SDK + CLI): https://github.com/ScanSearch/scansearch-python
- API docs: https://scansearch.net/resources/api-docs/
- Free recon tools (port scanner, SSL checker, subdomain finder, CVE lookup): https://scansearch.net/tools/
If you build something with it, I'd love to hear what you scanned and why.
Top comments (0)