Python调用Shodan API获取country_code报KeyError的解决方法
Hey there! That KeyError pops up because not every device result from Shodan includes full geolocation data. Some hosts might not have a location field at all, or the country_code might be missing even if location exists. Let's fix this with safe field access so your script doesn't crash unexpectedly.
Why the Error Happens
Shodan's API doesn't guarantee that every result will have a location object—for example, internal network devices, hosts with incomplete metadata, or anonymized endpoints won't provide geolocation details. Trying to directly access result['location']['country_code'] without checking if those fields exist will throw a KeyError.
Correct Implementation
Use Python's dictionary get() method to safely retrieve nested fields. This lets you set a default value (like 'N/A') if the field doesn't exist. Here's a complete working example:
import shodan # Replace with your actual Shodan API key SHODAN_API_KEY = 'your_api_key_here' api = shodan.Shodan(SHODAN_API_KEY) try: # Replace with your target search string search_query = 'your_specific_search_string_here' results = api.search(search_query) print(f"Total results found: {results['total']}") for result in results['matches']: # Safely get country code with fallback values country_code = result.get('location', {}).get('country_code', 'N/A') # Print key details (customize this to your needs) print(f"IP: {result['ip_str']} | Country Code: {country_code}") print(f"Sample Data: {result['data'][:60]}...\n") except shodan.APIError as e: print(f"Shodan API Error: {e}")
How This Works
result.get('location', {}): If thelocationkey doesn't exist in the result, it returns an empty dictionary instead of raising an error..get('country_code', 'N/A'): Then we check the (possibly empty) location dict forcountry_code. If it's missing, we return'N/A'as a fallback.
Alternative: Conditional Checks
If you prefer explicit conditionals over chained get() calls, this works too:
for result in results['matches']: country_code = 'N/A' if 'location' in result: if 'country_code' in result['location']: country_code = result['location']['country_code'] # Rest of your code...
Pro Tips
- Filter Results Upfront: If you only want hosts with valid country codes, add
country:*to your search query (e.g.,'your_query country:*'). This reduces the number of results missing geolocation data, but still keep the safe access in code for edge cases. - Normalize Case: Shodan returns country codes in uppercase (e.g.,
US,DE). Usecountry_code.lower()if you need lowercase values. - Check API Limits: Make sure you're within your Shodan API rate limits to avoid unexpected errors.
内容的提问来源于stack exchange,提问作者Store LTE




