Skip to content

Commit 8b4f66d

Browse files
authored
Create WigleSearch.py
0 parents  commit 8b4f66d

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

WigleSearch.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import requests
2+
import json
3+
import time
4+
import argparse
5+
import sys
6+
from xml.etree.ElementTree import Element, SubElement, tostring
7+
import xml.dom.minidom
8+
9+
10+
def fetch_wigle_data(ssid, token_name, api_token, max_results):
11+
base_url = 'https://api.wigle.net/api/v2/network/search'
12+
headers = {'accept': 'application/json'}
13+
params = {
14+
'onlymine': 'false',
15+
'freenet': 'false',
16+
'paynet': 'false',
17+
'ssid': ssid,
18+
'resultsPerPage': 100
19+
}
20+
21+
all_results = []
22+
total_fetched = 0
23+
search_after = None
24+
25+
print(f"[*] Searching for SSID: {ssid}")
26+
27+
while total_fetched < max_results:
28+
if search_after:
29+
params['searchAfter'] = search_after
30+
31+
response = requests.get(base_url, headers=headers, params=params, auth=(token_name, api_token))
32+
if response.status_code != 200:
33+
print(f"[!] Error {response.status_code}: {response.text}")
34+
break
35+
36+
data = response.json()
37+
results = data.get('results', [])
38+
39+
if not results:
40+
print("[*] No more results returned. Ending search.")
41+
break
42+
43+
all_results.extend(results)
44+
total_fetched += len(results)
45+
46+
print(f"[+] Fetched {len(results)} records (Total: {total_fetched})")
47+
48+
if 'searchAfter' in data:
49+
search_after = data['searchAfter']
50+
else:
51+
print("[*] No 'searchAfter' field found. Ending search.")
52+
break
53+
54+
time.sleep(1)
55+
56+
return all_results
57+
58+
59+
def save_as_json(results, output_file):
60+
with open(output_file, 'w') as f:
61+
json.dump(results, f, indent=2)
62+
print(f"[✓] Saved {len(results)} records to {output_file} (JSON)")
63+
64+
65+
def save_as_kml(results, output_file):
66+
kml = Element('kml', xmlns="http://www.opengis.net/kml/2.2")
67+
doc = SubElement(kml, 'Document')
68+
69+
for entry in results:
70+
lat = entry.get('trilat')
71+
lon = entry.get('trilong')
72+
ssid = entry.get('ssid', 'unknown')
73+
bssid = entry.get('netid', 'unknown')
74+
75+
if lat is None or lon is None:
76+
continue
77+
78+
placemark = SubElement(doc, 'Placemark')
79+
name = SubElement(placemark, 'name')
80+
name.text = f"{ssid} ({bssid})"
81+
82+
point = SubElement(placemark, 'Point')
83+
coords = SubElement(point, 'coordinates')
84+
coords.text = f"{lon},{lat},0"
85+
86+
kml_str = xml.dom.minidom.parseString(tostring(kml)).toprettyxml(indent=" ")
87+
with open(output_file, 'w', encoding='utf-8') as f:
88+
f.write(kml_str)
89+
90+
print(f"[✓] Saved {len(results)} records to {output_file} (KML)")
91+
92+
93+
def main():
94+
parser = argparse.ArgumentParser(description="Fetch WiGLE results for a given SSID and save as JSON or KML.")
95+
parser.add_argument('--ssid', required=True, help='SSID to search for')
96+
parser.add_argument('--token-name', required=True, help='WiGLE Account Token Name (not your login username)')
97+
parser.add_argument('--token', required=True, help='WiGLE API token (used with the token name)')
98+
parser.add_argument('--output', default=None, help='Output file (default: <SSID>_wigle_results.json or .kml)')
99+
parser.add_argument('--max', type=int, default=1000, help='Maximum number of records to fetch (default: 1000)')
100+
parser.add_argument('--format', choices=['json', 'kml'], default='json', help='Output format: json (default) or kml')
101+
102+
args = parser.parse_args()
103+
104+
output_file = args.output
105+
if not output_file:
106+
output_file = f"{args.ssid}_wigle_results.{args.format}"
107+
108+
results = fetch_wigle_data(args.ssid, args.token_name, args.token, args.max)
109+
110+
if args.format == 'json':
111+
save_as_json(results, output_file)
112+
else:
113+
save_as_kml(results, output_file)
114+
115+
116+
if __name__ == '__main__':
117+
main()

0 commit comments

Comments
 (0)