{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
\n",
"\n",
"Measurement Research within the Python3 Ecosystem\n",
"============================================\n",
"\n",
"### [Steffie Jacob Eravuchira](mailto: s.eravuchira@jacobs-university.de) , [Vaibhav Bajpai](mailto: v.bajpai@jacobs-university.de) , [Jürgen Schönwälder](mailto: j.schoenwaelder@jacobs-university.de)\n",
"\n",
"School of Engineering and Sciences, \n",
"Campus Ring 1, Jacobs University Bremen, \n",
"Bremen 28759 \n",
"Bremen, Germany \n",
"\n",
" \n",
"
\n",
"***\n",
"\n",
"This notebook is available online at: https://github.com/vbajpai/ripe69-python3-toolset\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Table of Contents\n",
"----------------\n",
"\n",
"* [Fetching Multi-Dimensional Data](#fetching-multidim-data)\n",
"* [Frictionless SQL Storage](#frictionless-sql-storage)\n",
"* [Frictionless Data Retrieval](#frictionless-data-retrieval)\n",
"* [Data Analysis](#data-analysis)\n",
"* [Data Visualisation](#data-visualization)\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fetching Multi-Dimensional Data\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* [`requests`](#requests)\n",
"* [`requests + atlas.ripe.net`](#requests-ripeatlas)\n",
"* [`requests + stat.ripe.net`](#requests-ripestat)\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### [`requests` →](http://docs.python-requests.org)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import requests"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `get_json_resource_from_absolute_uri(...):`\n",
"- Takes an absolute URI to a JSON resource and a dictionary of query parameters\n",
"- Performs HTTP GET request on the absolute URI to fetch the JSON resource.\n",
"- Returns the JSON resource as a dictionary"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def get_json_resource_from_absolute_uri(url, query_params):\n",
" try: res = requests.get(url, params = query_params)\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" else:\n",
" try: res_json = res.json()\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" else: \n",
" return res_json"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Example Usage:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\n",
" \"query\": {\n",
" \"pages\": {\n",
" \"736\": {\n",
" \"ns\": 0,\n",
" \"contentmodel\": \"wikitext\",\n",
" \"lastrevid\": 656156313,\n",
" \"title\": \"Albert Einstein\",\n",
" \"pagelanguage\": \"en\",\n",
" \"length\": 124542,\n",
" \"touched\": \"2015-04-12T18:40:50Z\",\n",
" \"pageid\": 736\n",
" }\n",
" },\n",
" \"normalized\": [\n",
" {\n",
" \"to\": \"Albert Einstein\",\n",
" \"from\": \"Albert_Einstein\"\n",
" }\n",
" ]\n",
" }\n",
"}\n"
]
}
],
"source": [
"import json\n",
"url = 'https://en.wikipedia.org/w/api.php'\n",
"query_params = {'action': 'query', 'titles': 'Albert_Einstein', 'prop': 'info', 'format': 'json', 'rawcontinue':'true'}\n",
"res = get_json_resource_from_absolute_uri(url, query_params)\n",
"if res: print(json.dumps(res,indent = 4))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `requests` + [`atlas.ripe.net` →](http://atlas.ripe.net)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import requests"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `get_count_registered_atlas_probes(...):`\n",
"- Returns the count of registered probes using the [RIPE Atlas probe API →](https://atlas.ripe.net/docs/rest/#probe)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def get_count_registered_atlas_probes():\n",
" base_uri = 'https://atlas.ripe.net'; url = '%s/api/v1/probe'%base_uri\n",
" try: res = get_json_resource_from_absolute_uri(url, None)\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" else:\n",
" try: total_registered = res['meta']['total_count']\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" else: return total_registered"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Example Usage:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIPE Atlas Registered Probes: 13488\n"
]
}
],
"source": [
"count = get_count_registered_atlas_probes()\n",
"if count: print(\"# RIPE Atlas Registered Probes: %d\"%count)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - - \n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `get_count_connected_atlas_probes(...):`\n",
"- Returns the count of connected probes using the [RIPE Atlas probe API →](https://atlas.ripe.net/docs/rest/#probe)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def get_count_connected_atlas_probes():\n",
" base_uri = 'https://atlas.ripe.net'; url = '%s/api/v1/probe'%base_uri\n",
" offset = 0; limit = 100; connected_objects = 0\n",
" registered_count = get_count_registered_atlas_probes() \n",
" if not registered_count: return None\n",
" while (offset <= registered_count):\n",
" query_params = {'offset': '%d'%offset, 'limit': '%d'%limit}\n",
" try: res = get_json_resource_from_absolute_uri(url, query_params)\n",
" except Exception as e: print(e, file=sys.stderr); return None\n",
" try: objects = res['objects']\n",
" except Exception as e: print(e, file=sys.stderr); return None\n",
" for object in objects: \n",
" if object['status'] == 1: connected_objects += 1\n",
" print('.', end='')\n",
" offset = offset + limit\n",
" print('')\n",
" return connected_objects"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Example Usage:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
".......................................................................................................................................\n",
"# RIPE Atlas Connected probes: 8086\n"
]
}
],
"source": [
"count = get_count_connected_atlas_probes()\n",
"if count: print(\"# RIPE Atlas Connected probes: %d\"%count)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"###`requests +` [`stat.ripe.net` →](https://stat.ripe.net)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import requests"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `get_holder_from_asn(...)`\n",
"- Takes ASN as input\n",
"- Fetch the holder organization name associated with the ASN using the [RIPEstat Data API →](https://stat.ripe.net/docs/data_api)\n",
"- Returns the fetched organization name associated with the ASN."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def get_holder_from_asn(asn):\n",
" base_uri = 'https://stat.ripe.net'; url = '%s/data/as-overview/data.json'%base_uri\n",
" params = {'resource' : asn}\n",
" try: res = get_json_resource_from_absolute_uri(url, params)\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" try: holder = res['data']['holder']\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" return holder"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Example:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15169 => GOOGLE - Google Inc.,US\n"
]
}
],
"source": [
"asn = '15169'\n",
"holder = get_holder_from_asn(asn)\n",
"print('%s => %s'%(asn, holder))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - - \n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `get_asn_from_endpoint(...):`\n",
"\n",
"- Takes an IP endpoint as input\n",
"- Using the [RIPEstat Data API →](https://stat.ripe.net/docs/data_api)\n",
" - Calculates the 1st-level less-specific prefix encompassing the IP endpoint.\n",
" - Fetches the ASN (`ASN`) announcing the prefix.\n",
" - Fetches the holder organization name (`holder`) associated with the ASN. \n",
"- Returns a list of `(ASN, holder)` tuple."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def get_asn_from_endpoint(endpoint):\n",
" asn = holder = None\n",
" base_uri = 'https://stat.ripe.net'; url = '%s/data/prefix-overview/data.json'%base_uri\n",
" params = {'resource' : endpoint}\n",
" try: res = get_json_resource_from_absolute_uri(url, params)\n",
" except Exception as e: print(e, file=sys.stderr); return None\n",
" try:\n",
" asns_holders = []\n",
" for item in res['data']['asns']:\n",
" asn = item['asn']; holder = item['holder']\n",
" asns_holders.append((asn, holder))\n",
" except Exception as e: print(e, file=sys.stderr)\n",
" return asns_holders"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Example:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8.8.8.8\n",
"=> 15169, GOOGLE - Google Inc.,US\n",
"\n",
"2001:4860:4860::8888\n",
"=> 15169, GOOGLE - Google Inc.,US\n"
]
}
],
"source": [
"ep4 = '8.8.8.8'\n",
"ep6 = '2001:4860:4860::8888'\n",
"\n",
"asns_holders_v4 = get_asn_from_endpoint(ep4)\n",
"asns_holders_v6 = get_asn_from_endpoint(ep6)\n",
"\n",
"print('%s'%ep4)\n",
"for asn, holder in asns_holders_v4: print('=> %d, %s'%(asn, holder))\n",
" \n",
"print('\\n%s'%ep6)\n",
"for asn, holder in asns_holders_v6: print('=> %d, %s'%(asn, holder))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `create_pretty_node_names(...)`\n",
"- Takes ASN and associated holder organization name as input\n",
"- Returns the pretty-printed form of input"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def create_pretty_node_names(asn, holder):\n",
" firstname = holder.split('-')[0].split(' ')[0]\n",
" if 'AS' in str(asn): nodename = '%s (%s)'%(firstname, asn)\n",
" else: nodename = '%s (AS%s)'%(firstname, asn)\n",
" return nodename"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Example:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"GOOGLE (AS15169)\n"
]
}
],
"source": [
"node = create_pretty_node_names(asn, holder)\n",
"print(node)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"[Back to Top](#top)\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Frictionless SQL storage\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* [`pandas + DataFrame`](#pandas-dataframe)\n",
"* [`pandas + to_sql`](#pandas-to-sql)\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### [`pandas` →](http://pandas.pydata.org/) + `DataFrame`"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import pandas as pd"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### `pandas.DataFrame(...)`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- We use the [RIPE Atlas probe archive API →](https://atlas.ripe.net/docs/rest/#probe-archive)\n",
"- We only show few probe API fields for brevity reasons.\n",
"- The probe ID is set as the index of the `DataFrame`."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" asn_v4 | \n",
" asn_v6 | \n",
" country_code | \n",
" status_name | \n",
" tags | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1 | \n",
" 6830 | \n",
" NaN | \n",
" NL | \n",
" Connected | \n",
" [cable, home, nat, system-v1, system-resolves-... | \n",
"
\n",
" \n",
" 1 | \n",
" 2 | \n",
" 5615 | \n",
" NaN | \n",
" NL | \n",
" Connected | \n",
" [home, nat, system-v1, system-resolves-a-corre... | \n",
"
\n",
" \n",
" 2 | \n",
" 3 | \n",
" 3265 | \n",
" 3265 | \n",
" NL | \n",
" Connected | \n",
" [home, nat, system-v1, system-resolves-a-corre... | \n",
"
\n",
" \n",
" 3 | \n",
" 4 | \n",
" 3265 | \n",
" 3265 | \n",
" NL | \n",
" Connected | \n",
" [dsl, home, nat, native-ipv6, system-v1, syste... | \n",
"
\n",
" \n",
" 4 | \n",
" 5 | \n",
" 3265 | \n",
" 3265 | \n",
" NL | \n",
" Connected | \n",
" [home, nat, system-v1, system-resolves-a-corre... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id asn_v4 asn_v6 country_code status_name \\\n",
"0 1 6830 NaN NL Connected \n",
"1 2 5615 NaN NL Connected \n",
"2 3 3265 3265 NL Connected \n",
"3 4 3265 3265 NL Connected \n",
"4 5 3265 3265 NL Connected \n",
"\n",
" tags \n",
"0 [cable, home, nat, system-v1, system-resolves-... \n",
"1 [home, nat, system-v1, system-resolves-a-corre... \n",
"2 [home, nat, system-v1, system-resolves-a-corre... \n",
"3 [dsl, home, nat, native-ipv6, system-v1, syste... \n",
"4 [home, nat, system-v1, system-resolves-a-corre... "
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"url = 'https://atlas.ripe.net/api/v1/probe-archive/'\n",
"res = get_json_resource_from_absolute_uri(url, {'format': json})\n",
"df = pd.DataFrame(res['objects'])\n",
"df[['id', 'asn_v4', 'asn_v6', 'country_code', 'status_name', 'tags']].head()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `pandas` + `to_sql(...)`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####`sqlite3.connect(...)` function:\n",
"\n",
"Connects to a `sqlite3` database:\n",
"- Creates the database if it does not exist, or\n",
"- Connects to the databse if it exists "
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import sqlite3\n",
"DBNAME = 'ripe69-toolset.db'\n",
"con = sqlite3.connect(DBNAME)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need to unbox DataFrame columns of a object datatype into a string representation to allow insertion into a SQL table"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"for c in df.columns:\n",
" if df[c].dtype == object: df[c] = df[c].astype(str)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"df = df.set_index('id')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####`DataFrame.to_sql(...)`:\n",
"\n",
"Write DataFrame records to a SQL database table:\n",
"- Creates the table (with the supplied table name) if it does not exit.\n",
"- Overwrites if the table (with the suppleid table name) exists.\n",
"- Inserts the records within a DataFrame into the table."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"try: cur = con.execute('pragma foreign_keys=ON')\n",
"except Exception as e: print(e, file=sys.stderr)\n",
"else:\n",
" TABLENAME = 'ra_probe_api_2014'\n",
" try:\n",
" df.to_sql( '%s'%TABLENAME\n",
" , con\n",
" , flavor='sqlite'\n",
" , if_exists = 'replace'\n",
" , index_label = 'id'\n",
" )\n",
" except Exception as e: print(e, file=sys.stderr)\n",
"con.commit()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"[Back to Top](#top)\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Frictionless Data Retrieval\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `pandas` + `read(...)`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####`pd.read(...)` function:\n",
"- Takes a SQL connection object and a SQL query as input.\n",
"- Applies the SQL query on the connected database and returns a `pandas DataFrame` "
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" asn_v4 | \n",
" asn_v6 | \n",
" country_code | \n",
" status_name | \n",
" tags | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 1 | \n",
" 6830 | \n",
" NaN | \n",
" NL | \n",
" Connected | \n",
" ['cable', 'home', 'nat', 'system-v1', 'system-... | \n",
"
\n",
" \n",
" 1 | \n",
" 2 | \n",
" 5615 | \n",
" NaN | \n",
" NL | \n",
" Connected | \n",
" ['home', 'nat', 'system-v1', 'system-resolves-... | \n",
"
\n",
" \n",
" 2 | \n",
" 3 | \n",
" 3265 | \n",
" 3265 | \n",
" NL | \n",
" Connected | \n",
" ['home', 'nat', 'system-v1', 'system-resolves-... | \n",
"
\n",
" \n",
" 3 | \n",
" 4 | \n",
" 3265 | \n",
" 3265 | \n",
" NL | \n",
" Connected | \n",
" ['dsl', 'home', 'nat', 'native-ipv6', 'system-... | \n",
"
\n",
" \n",
" 4 | \n",
" 5 | \n",
" 3265 | \n",
" 3265 | \n",
" NL | \n",
" Connected | \n",
" ['home', 'nat', 'system-v1', 'system-resolves-... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id asn_v4 asn_v6 country_code status_name \\\n",
"0 1 6830 NaN NL Connected \n",
"1 2 5615 NaN NL Connected \n",
"2 3 3265 3265 NL Connected \n",
"3 4 3265 3265 NL Connected \n",
"4 5 3265 3265 NL Connected \n",
"\n",
" tags \n",
"0 ['cable', 'home', 'nat', 'system-v1', 'system-... \n",
"1 ['home', 'nat', 'system-v1', 'system-resolves-... \n",
"2 ['home', 'nat', 'system-v1', 'system-resolves-... \n",
"3 ['dsl', 'home', 'nat', 'native-ipv6', 'system-... \n",
"4 ['home', 'nat', 'system-v1', 'system-resolves-... "
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"query = '''select id, asn_v4, asn_v6, country_code, status_name, tags from %s'''%TABLENAME\n",
"df = pd.read_sql(query, con)\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"[Back to Top](#top)\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Data Analysis\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `python3 ipaddress`"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import ipaddress"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####`ipaddress.ip_address(...)` :\n",
"Creates an IPv4/ipv6 address object from the input string "
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8.8.8.8 => \n",
"2001:4860:4860::8888 => \n"
]
}
],
"source": [
"try: \n",
" myipv4 = ipaddress.ip_address(ep4)\n",
" myipv6 = ipaddress.ip_address(ep6)\n",
"except Exception as e: print(e, file=sys.stderr)\n",
"else: \n",
" print('%s => %s'%(myipv4, type(myipv4)))\n",
" print('%s => %s'%(myipv6, type(myipv6)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####`ipaddress.is_private`:\n",
"\n",
"- Returns `True` if IP endpoint is Private [RFC1918 →](https://tools.ietf.org/html/rfc1918)\n",
"- Returns `False` if IP endpoint is not Private [RFC1918 →](https://tools.ietf.org/html/rfc1918)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Is 8.8.8.8 Private [RFC1918]? => False\n"
]
}
],
"source": [
"print('Is %s Private [RFC1918]? => %s'%(myipv4, myipv4.is_private))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####`ipaddress.version`:\n",
"\n",
"- Returns 4 if IP endpoint is IPv4.\n",
"- Returns 6 if IP endpoint is IPv6.\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8.8.8.8 => IPv4\n",
"2001:4860:4860::8888 => IPv6\n"
]
}
],
"source": [
"print(\"%s => IPv%s\"%(myipv4, myipv4.version))\n",
"print(\"%s => IPv%s\"%(myipv6,myipv6.version))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- - -\n",
"[Back to Top](#top)\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Data Visualization\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `pandas + matplotlib`\n",
"\n",
"- Uses `Pandas.read_sql(...)` to read the probe ID and ASN v4 from the sqlite3 table (dump of the probe API data).\n",
"- Uses `DataFrame.groupby(...)` to group the probe IDs by ASN v4.\n",
"- Uses `DataFrameGroupby.agg(...)` to aggregate by counting the number of probes behind each ASN v4.\n",
"- Uses `DataFrame.sort(...)` to sort the ASN v4 aggregates by number of probes."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"query = '''select id, asn_v4 from %s'''%TABLENAME\n",
"df = pd.read_sql(query, con)\n",
"dfgroupby = df.groupby('asn_v4')\n",
"dfagg = dfgroupby.agg(len)\n",
"dfsort = dfagg.sort('id', ascending=False)\n",
"df = dfsort.reset_index().reset_index()\n",
"df['index'] = df['index'].apply(lambda x: x+1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Uses `DataFrame.plot(...)` to plot the distribution of number of probes by ASN index (designated by the number of deployed probes)."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Populating the interactive namespace from numpy and matplotlib\n"
]
},
{
"data": {
"text/plain": [
""
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\nYII=\n",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%pylab inline\n",
"ax = df.plot('index', 'id', logx = True, kind = 'area', legend = False, figsize = (12,8))\n",
"ax.set_ylabel(\"# of Registered RIPE Atlas probes\", fontsize=18)\n",
"ax.set_xlabel(\"ASN index (log scale)\", fontsize=18)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Back to Top](#top)\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Work Supported by Leone Project: [leone-project.eu →](http://leone-project.eu/) ###"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}