VOOZH about

URL: https://dev.to/devyjones/on-demand-internet-scanning-in-python-scan-any-ip-cidr-or-country-with-scansearch-2n40

⇱ On-demand internet scanning in Python: scan any IP, CIDR, or country with ScanSearch - DEV Community


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 services enrichment with CVE matching to find newly exposed ssh, rdp, elasticsearch, etc.

Links

If you build something with it, I'd love to hear what you scanned and why.