Hello community, here is the log from the commit of package python-shodan for openSUSE:Factory checked in at 2018-09-04 22:54:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-shodan (Old) and /work/SRC/openSUSE:Factory/.python-shodan.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-shodan" Tue Sep 4 22:54:19 2018 rev:4 rq:628028 version:1.9.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-shodan/python-shodan.changes 2018-06-29 22:27:15.966444336 +0200 +++ /work/SRC/openSUSE:Factory/.python-shodan.new/python-shodan.changes 2018-09-04 22:55:03.352772436 +0200 @@ -1,0 +2,8 @@ +Wed Aug 1 08:24:12 UTC 2018 - [email protected] + +- update to version 1.9.0: + * New optional parameter proxies for all interfaces to specify a proxy array for the requests library (#72) +- update to version 1.8.1: + * Fixed bug that prevented shodan scan submit from finishing (#70) + +------------------------------------------------------------------- Old: ---- shodan-1.8.0.tar.gz New: ---- shodan-1.9.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-shodan.spec ++++++ --- /var/tmp/diff_new_pack.erBpgU/_old 2018-09-04 22:55:03.696773612 +0200 +++ /var/tmp/diff_new_pack.erBpgU/_new 2018-09-04 22:55:03.700773626 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %{!?license: %global license %doc} Name: python-shodan -Version: 1.8.0 +Version: 1.9.0 Release: 0 Summary: Python library and command-line utility for Shodan License: MIT @@ -38,7 +38,6 @@ Requires: python-requests >= 2.2.1 Recommends: python-curses Suggests: %{name}-doc -BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildArch: noarch %python_subpackages ++++++ shodan-1.8.0.tar.gz -> shodan-1.9.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/LICENSE new/shodan-1.9.0/LICENSE --- old/shodan-1.8.0/LICENSE 2014-10-05 01:45:40.000000000 +0200 +++ new/shodan-1.9.0/LICENSE 2018-05-31 23:52:28.000000000 +0200 @@ -1,4 +1,4 @@ -Copyright (c) 2014 John Matherly <[email protected]> +Copyright (c) 2014- John Matherly <[email protected]> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/PKG-INFO new/shodan-1.9.0/PKG-INFO --- old/shodan-1.8.0/PKG-INFO 2018-05-29 12:28:02.000000000 +0200 +++ new/shodan-1.9.0/PKG-INFO 2018-08-01 08:26:35.000000000 +0200 @@ -1,16 +1,92 @@ Metadata-Version: 1.1 Name: shodan -Version: 1.8.0 +Version: 1.9.0 Summary: Python library and command-line utility for Shodan (https://developer.shodan.io) Home-page: http://github.com/achillean/shodan-python/tree/master Author: John Matherly Author-email: [email protected] License: UNKNOWN -Description: UNKNOWN +Description: shodan: The official Python library for accessing Shodan + ======================================================== + + .. image:: https://img.shields.io/pypi/v/shodan.svg + :target: https://pypi.org/project/shodan/ + + .. image:: https://img.shields.io/github/contributors/achillean/shodan-python.svg + :target: https://github.com/achillean/shodan-python/graphs/contributors + + Shodan is a search engine for Internet-connected devices. Google lets you search for websites, + Shodan lets you search for devices. This library provides developers easy access to all of the + data stored in Shodan in order to automate tasks and integrate into existing tools. + + Features + -------- + + - Search Shodan + - `Fast/ bulk IP lookups <https://help.shodan.io/developer-fundamentals/looking-up-ip-info>`_ + - Streaming API support for real-time consumption of Shodan firehose + - `Network alerts (aka private firehose) <https://help.shodan.io/guides/how-to-monitor-network>`_ + - Exploit search API fully implemented + - Bulk data downloads + + + Quick Start + ----------- + + .. code-block:: python + + from shodan import Shodan + + api = Shodan('MY API KEY') + + # Lookup an IP + ipinfo = api.host('8.8.8.8') + print(ipinfo) + + # Search for websites that have been "hacked" + for banner in api.search_cursor('http.title:"hacked by"'): + print(banner) + + # Get the total number of industrial control systems services on the Internet + ics_services = api.count('tag:ics') + print('Industrial Control Systems: {}'.format(ics_services['total'])) + + Grab your API key from https://account.shodan.io + + Installation + ------------ + + To install the Shodan library, simply: + + .. code-block:: bash + + $ pip install shodan + + Or if you don't have pip installed (which you should seriously install): + + .. code-block:: bash + + $ easy_install shodan + + + Documentation + ------------- + + Documentation is available at https://shodan.readthedocs.org/ and https://help.shodan.io + Keywords: security,network Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Software Development :: Libraries :: Python Modules diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/README.rst new/shodan-1.9.0/README.rst --- old/shodan-1.8.0/README.rst 2018-03-16 22:35:35.000000000 +0100 +++ new/shodan-1.9.0/README.rst 2018-06-01 04:35:05.000000000 +0200 @@ -1,6 +1,12 @@ shodan: The official Python library for accessing Shodan ======================================================== +.. image:: https://img.shields.io/pypi/v/shodan.svg + :target: https://pypi.org/project/shodan/ + +.. image:: https://img.shields.io/github/contributors/achillean/shodan-python.svg + :target: https://github.com/achillean/shodan-python/graphs/contributors + Shodan is a search engine for Internet-connected devices. Google lets you search for websites, Shodan lets you search for devices. This library provides developers easy access to all of the data stored in Shodan in order to automate tasks and integrate into existing tools. @@ -9,10 +15,35 @@ -------- - Search Shodan -- Fast IP lookups +- `Fast/ bulk IP lookups <https://help.shodan.io/developer-fundamentals/looking-up-ip-info>`_ - Streaming API support for real-time consumption of Shodan firehose +- `Network alerts (aka private firehose) <https://help.shodan.io/guides/how-to-monitor-network>`_ - Exploit search API fully implemented +- Bulk data downloads + + +Quick Start +----------- + +.. code-block:: python + + from shodan import Shodan + + api = Shodan('MY API KEY') + + # Lookup an IP + ipinfo = api.host('8.8.8.8') + print(ipinfo) + + # Search for websites that have been "hacked" + for banner in api.search_cursor('http.title:"hacked by"'): + print(banner) + + # Get the total number of industrial control systems services on the Internet + ics_services = api.count('tag:ics') + print('Industrial Control Systems: {}'.format(ics_services['total'])) +Grab your API key from https://account.shodan.io Installation ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/setup.py new/shodan-1.9.0/setup.py --- old/shodan-1.8.0/setup.py 2018-05-29 12:26:18.000000000 +0200 +++ new/shodan-1.9.0/setup.py 2018-08-01 08:08:43.000000000 +0200 @@ -2,24 +2,36 @@ from setuptools import setup -dependencies = open('requirements.txt', 'r').read().split('\n') +DEPENDENCIES = open('requirements.txt', 'r').read().split('\n') +README = open('README.rst', 'r').read() setup( name = 'shodan', - version = '1.8.0', + version = '1.9.0', description = 'Python library and command-line utility for Shodan (https://developer.shodan.io)', + long_description = README, + long_description_content_type = 'text/x-rst', author = 'John Matherly', author_email = '[email protected]', url = 'http://github.com/achillean/shodan-python/tree/master', packages = ['shodan', 'shodan.cli', 'shodan.cli.converter'], entry_points = {'console_scripts': ['shodan = shodan.__main__:main']}, - install_requires = dependencies, + install_requires = DEPENDENCIES, keywords = ['security', 'network'], classifiers = [ + 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Software Development :: Libraries :: Python Modules', ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/shodan/__main__.py new/shodan-1.9.0/shodan/__main__.py --- old/shodan-1.8.0/shodan/__main__.py 2018-05-29 12:11:21.000000000 +0200 +++ new/shodan-1.9.0/shodan/__main__.py 2018-08-01 08:07:51.000000000 +0200 @@ -522,7 +522,7 @@ for banner in host['data']: if banner['port'] in ports: ports.remove(banner['port']) - + # Add the placeholder banners for port in ports: banner = { @@ -898,7 +898,7 @@ versions = [version for version in sorted(banner['ssl']['versions']) if not version.startswith('-')] if len(versions) > 0: click.echo(' |-- SSL Versions: {}'.format(', '.join(versions))) - if 'dhparams' in banner['ssl']: + if 'dhparams' in banner['ssl'] and banner['ssl']['dhparams']: click.echo(' |-- Diffie-Hellman Parameters:') click.echo(' {:15s}{}\n {:15s}{}'.format('Bits:', banner['ssl']['dhparams']['bits'], 'Generator:', banner['ssl']['dhparams']['generator'])) if 'fingerprint' in banner['ssl']['dhparams']: @@ -1013,7 +1013,7 @@ results = api.search(query, limit=limit) except shodan.APIError as e: raise click.ClickException(e.value) - + # Error out if no results were found if results['total'] == 0: raise click.ClickException('No search results found') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/shodan/client.py new/shodan-1.9.0/shodan/client.py --- old/shodan-1.8.0/shodan/client.py 2017-12-05 06:44:11.000000000 +0100 +++ new/shodan-1.9.0/shodan/client.py 2018-08-01 08:07:51.000000000 +0200 @@ -43,7 +43,7 @@ :ivar exploits: An instance of `shodan.Shodan.Exploits` that provides access to the Exploits REST API. :ivar stream: An instance of `shodan.Shodan.Stream` that provides access to the Streaming API. """ - + class Data: def __init__(self, parent): @@ -62,7 +62,7 @@ :returns: A list of objects where each object contains a 'name', 'size', 'timestamp' and 'url' """ return self.parent._request('/shodan/data/{}'.format(dataset), {}) - + class Tools: def __init__(self, parent): @@ -74,16 +74,16 @@ :returns: str -- your IP address """ return self.parent._request('/tools/myip', {}) - + class Exploits: def __init__(self, parent): self.parent = parent - + def search(self, query, page=1, facets=None): """Search the entire Shodan Exploits archive using the same query syntax as the website. - + :param query: The exploit search query; same syntax as website. :type query: str :param facets: A list of strings or tuples to get summary information on. @@ -100,17 +100,17 @@ query_args['facets'] = create_facet_string(facets) return self.parent._request('/api/search', query_args, service='exploits') - + def count(self, query, facets=None): """Search the entire Shodan Exploits archive but only return the total # of results, not the actual exploits. - + :param query: The exploit search query; same syntax as website. :type query: str :param facets: A list of strings or tuples to get summary information on. :type facets: str :returns: dict -- a dictionary containing the results of the search. - + """ query_args = { 'query': query, @@ -119,7 +119,7 @@ query_args['facets'] = create_facet_string(facets) return self.parent._request('/api/count', query_args, service='exploits') - + class Labs: def __init__(self, parent): @@ -127,19 +127,21 @@ def honeyscore(self, ip): """Calculate the probability of an IP being an ICS honeypot. - + :param ip: IP address of the device :type ip: str :returns: int -- honeyscore ranging from 0.0 to 1.0 """ return self.parent._request('/labs/honeyscore/{}'.format(ip), {}) - - def __init__(self, key): + + def __init__(self, key, proxies=None): """Initializes the API object. - + :param key: The Shodan API key. :type key: str + :param proxies: A proxies array for the requests library, e.g. {'https': 'your proxy'} + :type key: dict """ self.api_key = key self.base_url = 'https://api.shodan.io' @@ -148,23 +150,25 @@ self.exploits = self.Exploits(self) self.labs = self.Labs(self) self.tools = self.Tools(self) - self.stream = Stream(key) + self.stream = Stream(key, proxies=proxies) self._session = requests.Session() - + if proxies: + self._session.proxies.update(proxies) + def _request(self, function, params, service='shodan', method='get'): """General-purpose function to create web requests to SHODAN. - + Arguments: function -- name of the function you want to execute params -- dictionary of parameters for the function - + Returns A dictionary containing the function's results. - + """ # Add the API key parameter automatically params['key'] = self.api_key - + # Determine the base_url based on which service we're interacting with base_url = { 'shodan': self.base_url, @@ -187,22 +191,22 @@ error = data.json()['error'] except Exception as e: error = 'Invalid API key' - + raise APIError(error) - + # Parse the text into JSON try: data = data.json() except: raise APIError('Unable to parse JSON response') - + # Raise an exception if an error occurred if type(data) == dict and 'error' in data: raise APIError(data['error']) - + # Return the data return data - + def count(self, query, facets=None): """Returns the total number of search results for the query. @@ -210,7 +214,7 @@ :type query: str :param facets: (optional) A list of properties to get summary information on :type facets: str - + :returns: A dictionary with 1 main property: total. If facets have been provided then another property called "facets" will be available at the top-level of the dictionary. Visit the website for more detailed information. """ query_args = { @@ -219,7 +223,7 @@ if facets: query_args['facets'] = create_facet_string(facets) return self._request('/shodan/host/count', query_args) - + def host(self, ips, history=False, minify=False): """Get all available information on an IP. @@ -232,14 +236,14 @@ """ if isinstance(ips, basestring): ips = [ips] - + params = {} if history: params['history'] = history if minify: params['minify'] = minify return self._request('/shodan/host/%s' % ','.join(ips), params) - + def info(self): """Returns information about the current API key, such as a list of add-ons and other features that are enabled for the current user's API plan. @@ -281,7 +285,7 @@ """ if isinstance(ips, basestring): ips = [ips] - + if isinstance(ips, dict): networks = json.dumps(ips) else: @@ -320,7 +324,7 @@ :returns: A dictionary with general information about the scan, including its status in getting processed. """ return self._request('/shodan/scan/%s' % scan_id, {}) - + def search(self, query, page=1, limit=None, offset=None, facets=None, minify=True): """Search the SHODAN database. @@ -336,8 +340,8 @@ :type facets: str :param minify: (optional) Whether to minify the banner and only return the important data :type minify: bool - - :returns: A dictionary with 2 main items: matches and total. If facets have been provided then another property called "facets" will be available at the top-level of the dictionary. Visit the website for more detailed information. + + :returns: A dictionary with 2 main items: matches and total. If facets have been provided then another property called "facets" will be available at the top-level of the dictionary. Visit the website for more detailed information. """ args = { 'query': query, @@ -352,9 +356,9 @@ if facets: args['facets'] = create_facet_string(facets) - + return self._request('/shodan/host/search', args) - + def search_cursor(self, query, minify=True, retries=5): """Search the SHODAN database. @@ -369,7 +373,7 @@ :type minify: bool :param retries: (optional) How often to retry the search in case it times out :type minify: int - + :returns: A search cursor that can be used as an iterator/ generator. """ args = { @@ -396,13 +400,13 @@ tries += 1 time.sleep(1.0) # wait 1 second if the search errored out for some reason - + def search_tokens(self, query): """Returns information about the search query itself (filters used etc.) :param query: Search query; identical syntax to the website :type query: str - + :returns: A dictionary with 4 main properties: filters, errors, attributes and string. """ query_args = { @@ -481,7 +485,8 @@ 'expires': expires, } - response = api_request(self.api_key, '/shodan/alert', data=data, params={}, method='post') + response = api_request(self.api_key, '/shodan/alert', data=data, params={}, method='post', + proxies=self._session.proxies) return response @@ -494,7 +499,8 @@ response = api_request(self.api_key, func, params={ 'include_expired': include_expired, - }) + }, + proxies=self._session.proxies) return response @@ -502,7 +508,8 @@ """Delete the alert with the given ID.""" func = '/shodan/alert/%s' % aid - response = api_request(self.api_key, func, params={}, method='delete') + response = api_request(self.api_key, func, params={}, method='delete', + proxies=self._session.proxies) return response diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/shodan/helpers.py new/shodan-1.9.0/shodan/helpers.py --- old/shodan-1.8.0/shodan/helpers.py 2017-06-17 00:16:47.000000000 +0200 +++ new/shodan-1.9.0/shodan/helpers.py 2018-08-01 08:07:51.000000000 +0200 @@ -23,17 +23,19 @@ facet_str += ',' return facet_str[:-1] - -def api_request(key, function, params=None, data=None, base_url='https://api.shodan.io', method='get', retries=1): + +def api_request(key, function, params=None, data=None, base_url='https://api.shodan.io', + method='get', retries=1, proxies=None): """General-purpose function to create web requests to SHODAN. - + Arguments: function -- name of the function you want to execute params -- dictionary of parameters for the function - + proxies -- a proxies array for the requests library + Returns A dictionary containing the function's results. - + """ # Add the API key parameter automatically params['key'] = key @@ -44,11 +46,13 @@ while tries <= retries: try: if method.lower() == 'post': - data = requests.post(base_url + function, json.dumps(data), params=params, headers={'content-type': 'application/json'}) + data = requests.post(base_url + function, json.dumps(data), params=params, + headers={'content-type': 'application/json'}, + proxies=proxies) elif method.lower() == 'delete': - data = requests.delete(base_url + function, params=params) + data = requests.delete(base_url + function, params=params, proxies=proxies) else: - data = requests.get(base_url + function, params=params) + data = requests.get(base_url + function, params=params, proxies=proxies) # Exit out of the loop break @@ -66,17 +70,17 @@ except: pass raise APIError('Invalid API key') - + # Parse the text into JSON try: data = data.json() except: raise APIError('Unable to parse JSON response') - + # Raise an exception if an error occurred if type(data) == dict and data.get('error', None): raise APIError(data['error']) - + # Return the data return data @@ -93,10 +97,10 @@ from ujson import loads except: pass - + if isinstance(files, basestring): files = [files] - + for filename in files: # Create a file handle depending on the filetype if filename.endswith('.gz'): @@ -157,7 +161,7 @@ return '1 byte' if bytes < 1024: return '%.*f %s' % (precision, bytes, "bytes") - + suffixes = ['KB', 'MB', 'GB', 'TB', 'PB'] multiple = 1024.0 #.0 force float on python 2 for suffix in suffixes: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/shodan/stream.py new/shodan-1.9.0/shodan/stream.py --- old/shodan-1.8.0/shodan/stream.py 2017-12-03 23:57:41.000000000 +0100 +++ new/shodan-1.9.0/shodan/stream.py 2018-08-01 08:07:51.000000000 +0200 @@ -9,18 +9,31 @@ base_url = 'https://stream.shodan.io' - def __init__(self, api_key): + def __init__(self, api_key, proxies=None): self.api_key = api_key + self.proxies = proxies def _create_stream(self, name, timeout=None): + params = { + 'key': self.api_key, + } + stream_url = self.base_url + name + # The user doesn't want to use a timeout # If the timeout is specified as 0 then we also don't want to have a timeout if ( timeout and timeout <= 0 ) or ( timeout == 0 ): timeout = None - + + # If the user requested a timeout then we need to disable heartbeat messages + # which are intended to keep stream connections alive even if there isn't any data + # flowing through. + if timeout: + params['heartbeat'] = False + try: while True: - req = requests.get(self.base_url + name, params={'key': self.api_key}, stream=True, timeout=timeout) + req = requests.get(stream_url, params=params, stream=True, timeout=timeout, + proxies=self.proxies) # Status code 524 is special to Cloudflare # It means that no data was sent from the streaming servers which caused Cloudflare @@ -46,7 +59,7 @@ req.encoding = 'utf-8' return req - def _iter_stream(self, stream, raw, timeout=None): + def _iter_stream(self, stream, raw): for line in stream.iter_lines(decode_unicode=True): # The Streaming API sends out heartbeat messages that are newlines # We want to ignore those messages since they don't contain any data @@ -55,16 +68,6 @@ yield line else: yield json.loads(line) - else: - # If the user specified a timeout then we want to keep track of how long we've - # been getting heartbeat messages and exit the loop if it's been too long since - # we've seen any activity. - if timeout: - # TODO: This is a placeholder for now but since the Streaming API added heartbeats it broke - # the ability to use inactivity timeouts (the connection timeout still works). The timeout is - # mostly needed when doing on-demand scans and wanting to temporarily consume data from a - # network alert. - pass def alert(self, aid=None, timeout=None, raw=False): if aid: @@ -120,4 +123,4 @@ stream = self._create_stream('/shodan/ports/%s' % ','.join([str(port) for port in ports]), timeout=timeout) for line in self._iter_stream(stream, raw): yield line - + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/shodan/threatnet.py new/shodan-1.9.0/shodan/threatnet.py --- old/shodan-1.8.0/shodan/threatnet.py 2017-05-17 19:09:05.000000000 +0200 +++ new/shodan-1.9.0/shodan/threatnet.py 2018-08-01 08:07:51.000000000 +0200 @@ -11,17 +11,19 @@ :type key: str :ivar stream: An instance of `shodan.Threatnet.Stream` that provides access to the Streaming API. """ - + class Stream: base_url = 'https://stream.shodan.io' - def __init__(self, parent): + def __init__(self, parent, proxies=None): self.parent = parent + self.proxies = proxies def _create_stream(self, name): try: - req = requests.get(self.base_url + name, params={'key': self.parent.api_key}, stream=True) + req = requests.get(self.base_url + name, params={'key': self.parent.api_key}, + stream=True, proxies=self.proxies) except: raise APIError('Unable to contact the Shodan Streaming API') @@ -53,10 +55,10 @@ if line: banner = json.loads(line) yield banner - + def __init__(self, key): """Initializes the API object. - + :param key: The Shodan API key. :type key: str """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/shodan-1.8.0/shodan.egg-info/PKG-INFO new/shodan-1.9.0/shodan.egg-info/PKG-INFO --- old/shodan-1.8.0/shodan.egg-info/PKG-INFO 2018-05-29 12:28:02.000000000 +0200 +++ new/shodan-1.9.0/shodan.egg-info/PKG-INFO 2018-08-01 08:26:34.000000000 +0200 @@ -1,16 +1,92 @@ Metadata-Version: 1.1 Name: shodan -Version: 1.8.0 +Version: 1.9.0 Summary: Python library and command-line utility for Shodan (https://developer.shodan.io) Home-page: http://github.com/achillean/shodan-python/tree/master Author: John Matherly Author-email: [email protected] License: UNKNOWN -Description: UNKNOWN +Description: shodan: The official Python library for accessing Shodan + ======================================================== + + .. image:: https://img.shields.io/pypi/v/shodan.svg + :target: https://pypi.org/project/shodan/ + + .. image:: https://img.shields.io/github/contributors/achillean/shodan-python.svg + :target: https://github.com/achillean/shodan-python/graphs/contributors + + Shodan is a search engine for Internet-connected devices. Google lets you search for websites, + Shodan lets you search for devices. This library provides developers easy access to all of the + data stored in Shodan in order to automate tasks and integrate into existing tools. + + Features + -------- + + - Search Shodan + - `Fast/ bulk IP lookups <https://help.shodan.io/developer-fundamentals/looking-up-ip-info>`_ + - Streaming API support for real-time consumption of Shodan firehose + - `Network alerts (aka private firehose) <https://help.shodan.io/guides/how-to-monitor-network>`_ + - Exploit search API fully implemented + - Bulk data downloads + + + Quick Start + ----------- + + .. code-block:: python + + from shodan import Shodan + + api = Shodan('MY API KEY') + + # Lookup an IP + ipinfo = api.host('8.8.8.8') + print(ipinfo) + + # Search for websites that have been "hacked" + for banner in api.search_cursor('http.title:"hacked by"'): + print(banner) + + # Get the total number of industrial control systems services on the Internet + ics_services = api.count('tag:ics') + print('Industrial Control Systems: {}'.format(ics_services['total'])) + + Grab your API key from https://account.shodan.io + + Installation + ------------ + + To install the Shodan library, simply: + + .. code-block:: bash + + $ pip install shodan + + Or if you don't have pip installed (which you should seriously install): + + .. code-block:: bash + + $ easy_install shodan + + + Documentation + ------------- + + Documentation is available at https://shodan.readthedocs.org/ and https://help.shodan.io + Keywords: security,network Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Software Development :: Libraries :: Python Modules
