Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4380fda

Browse files
Initial commit
0 parents commit 4380fda

21 files changed

+406
-0
lines changed

‎.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/api_key.py
2+
# Created by .ignore support plugin (hsz.mobi)
3+
### IPythonNotebook template
4+
# Temporary data
5+
.ipynb_checkpoints/
6+

‎README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# py_etherscan_api module
2+
EtherScan.io API python bindings
3+
4+
## Description
5+
This module is written as an effort to provide python bindings to the EtherScan.io API, which can be found at:
6+
https://etherscan.io/apis
7+
In order to use this, you must attain an Etherscan user account, and generate an API key.
8+
9+
The API variable name `key` needs to be stored in a file named `api_key.py` in the base module directory. This will be
10+
sorted out to be more user friendly later.
11+
12+
## Available bindings
13+
Currently, only the following Etherscan.io API modules are available:
14+
15+
- accounts
16+
- stats
17+
- tokens
18+
19+
The remaining available modules provided by Etherscan.io will be added shortly
20+
21+
## Examples
22+
All possible calls have an associated example file in the examples folder to show how to call the binding
23+
24+
These of course will be fleshed out with more details and explanation in time
25+
26+
## TODO:
27+
28+
- Package and submit to PyPI
29+
- Add the following modules:
30+
- event logs
31+
- geth proxy
32+
- websockets
33+
- Add robust documentation
34+
- Add unit test suite
35+
- Add requests.session as a connection option
36+
- include request throttling based on Etherscan's suggestions
37+
- jupyter notebook examples
38+
39+
## Holla at ya' boy
40+
BTC: 16Ny72US78VEjL5GUinSAavDwARb8dXWKG
41+
ETH: 0x5E8047fc033499BD5d8C463ADb29f10f11165ed0

‎etherscan/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'Corey Petty'

‎etherscan/accounts.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
from .client import Client
2+
import json
3+
import re
4+
5+
6+
class Account(Client):
7+
def __init__(self, address=Client.dao_address):
8+
Client.__init__(self, address=address)
9+
self.module += 'account'
10+
11+
def make_url(self, call_type=''):
12+
if call_type == 'balance':
13+
self.url = self.prefix \
14+
+ self.module \
15+
+ self.action \
16+
+ self.address \
17+
+ self.tag \
18+
+ self.key
19+
elif call_type == 'transactions':
20+
self.url = self.prefix \
21+
+ self.module \
22+
+ self.action \
23+
+ self.address \
24+
+ self.offset \
25+
+ self.page \
26+
+ self.key
27+
elif call_type == 'blocks':
28+
self.url = self.prefix \
29+
+ self.module \
30+
+ self.action \
31+
+ self.address \
32+
+ self.blocktype \
33+
+ self.offset \
34+
+ self.page \
35+
+ self.key
36+
37+
def get_balance(self):
38+
self.action += 'balance'
39+
self.tag += 'latest'
40+
self.make_url()
41+
req = self.connect()
42+
if req.status_code == 200:
43+
return json.loads(req.text)['result']
44+
else:
45+
return req.status_code
46+
47+
def get_balance_multiple(self):
48+
self.action += 'balancemulti'
49+
self.tag += 'latest'
50+
self.make_url(call_type='balance')
51+
req = self.connect()
52+
if req.status_code == 200:
53+
return json.loads(req.text)['result']
54+
else:
55+
return req.status_code
56+
57+
def get_transaction_page(self, page=1, offset=10000, sort='asc') -> list:
58+
"""
59+
Get a page of transactions, each transaction returns list of dict with keys:
60+
nonce
61+
hash
62+
cumulativeGasUsed
63+
gasUsed
64+
timeStamp
65+
blockHash
66+
value (in wei)
67+
input
68+
gas
69+
isInternalTx
70+
contractAddress
71+
confirmations
72+
gasPrice
73+
transactionIncex
74+
to
75+
from
76+
isError
77+
blockNumber
78+
79+
sort options:
80+
'asc' -> ascending order
81+
'des' -> descending order
82+
"""
83+
self.action += 'txlist'
84+
self.page += str(page)
85+
self.offset += str(offset)
86+
self.sort += sort
87+
self.make_url(call_type='transactions')
88+
req = self.connect()
89+
if req.status_code == 200:
90+
return json.loads(req.text)['result']
91+
else:
92+
return req.status_code
93+
94+
def get_all_transactions(self, offset=10000, sort='asc') -> list:
95+
self.action += 'txlist'
96+
self.page += str(1)
97+
self.offset += str(offset)
98+
self.sort += sort
99+
self.make_url(call_type='transactions')
100+
101+
trans_list = []
102+
while True:
103+
self.make_url(call_type='transactions')
104+
req = self.connect()
105+
if "No transactions found" in json.loads(req.text)['message']:
106+
print("Total number of transactions: {}".format(len(trans_list)))
107+
return trans_list
108+
else:
109+
trans_list += json.loads(req.text)['result']
110+
# Find any character block that is a integer of any length
111+
page_number = re.findall(r'[1-9](?:\d{0,2})(?:,\d{3})*(?:\.\d*[1-9])?|0?\.\d*[1-9]|0', self.page)
112+
print("page {} added".format(page_number[0]))
113+
self.page = self.page[:6] + str(int(page_number[0]) + 1)
114+
115+
def get_blocks_mined_page(self, blocktype='blocks', page=1, offset=10000) -> list:
116+
"""
117+
Get a page of blocks mined by given address, returns list of dict with keys:
118+
blockReward (in wei)
119+
blockNumber
120+
timeStamp
121+
122+
blocktype options:
123+
'blocks' -> full blocks only
124+
'uncles' -> uncles only
125+
"""
126+
self.action += 'getminedblocks'
127+
self.blocktype += blocktype
128+
self.page += str(page)
129+
self.offset += str(offset)
130+
self.make_url(call_type='blocks')
131+
req = self.connect()
132+
if req.status_code == 200:
133+
return json.loads(req.text)['result']
134+
else:
135+
return req.status_code
136+
137+
def get_all_blocks_mined(self, blocktype='blocks', offset=10000) -> list:
138+
self.action += 'getminedblocks'
139+
self.blocktype += blocktype
140+
self.page += str(1)
141+
self.offset += str(offset)
142+
blocks_list = []
143+
while True:
144+
self.make_url(call_type='blocks')
145+
req = self.connect()
146+
print(json.loads(req.text)['message'])
147+
if "No transactions found" in json.loads(req.text)['message']:
148+
print("Total number of blocks mined: {}".format(len(blocks_list)))
149+
return blocks_list
150+
else:
151+
blocks_list += json.loads(req.text)['result']
152+
# Find any character block that is a integer of any length
153+
page_number = re.findall(r'[1-9](?:\d{0,2})(?:,\d{3})*(?:\.\d*[1-9])?|0?\.\d*[1-9]|0', self.page)
154+
print("page {} added".format(page_number[0]))
155+
self.page = self.page[:6] + str(int(page_number[0]) + 1)
156+
157+
def update_transactions(self, address, trans):
158+
"""
159+
Gets last page of transactions (last 10k trans) and updates current trans book (book)
160+
"""
161+
pass

‎etherscan/client.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import requests
2+
from api_key import key
3+
4+
5+
# Assume user puts his API key in the api_key.py file under variable name "key"
6+
class Client(object):
7+
dao_address = '0xbb9bc244d798123fde783fcc1c72d3bb8c189413'
8+
9+
def __init__(self, address):
10+
self.http = None
11+
self.url = ''
12+
self.prefix = 'https://api.etherscan.io/'
13+
self.module = 'api?module='
14+
self.action = '&action='
15+
self.tag = '&tag='
16+
self.offset = '&offset='
17+
self.page = '&page='
18+
self.sort = '&sort='
19+
self.blocktype = '&blocktype='
20+
21+
self.key = '&apikey=' + str(key)
22+
if (len(address) > 20) and (type(address)== list):
23+
print("Etherscan only takes 20 addresses at a time")
24+
quit()
25+
elif (type(address) == list) and (len(address) <= 20):
26+
self.address = '&address=' + ','.join(address)
27+
else:
28+
self.address = '&address=' + address
29+
30+
def connect(self):
31+
# TODO: deal with "unknown exception" error
32+
try:
33+
req = requests.get(self.url)
34+
except requests.exceptions.ConnectionError:
35+
req.status_code = "Connection refused"
36+
return req

‎etherscan/stats.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from .client import Client
2+
import json
3+
4+
5+
class Stats(Client):
6+
def __init__(self):
7+
Client.__init__(self, address='')
8+
self.module += 'stats'
9+
10+
def make_url(self, call_type=''):
11+
if call_type == 'stats':
12+
self.url = self.prefix \
13+
+ self.module \
14+
+ self.action \
15+
+ self.key
16+
17+
def get_total_ether_supply(self):
18+
self.action += 'ethsupply'
19+
self.make_url(call_type='stats')
20+
req = self.connect()
21+
if req.status_code == 200:
22+
return json.loads(req.text)['result']
23+
else:
24+
return req.status_code
25+
26+
def get_ether_last_price(self):
27+
self.action += 'ethprice'
28+
self.make_url(call_type='stats')
29+
req = self.connect()
30+
if req.status_code == 200:
31+
return json.loads(req.text)['result']
32+
else:
33+
return req.status_code

‎etherscan/tokens.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from .client import Client
2+
import json
3+
4+
5+
class Tokens(Client):
6+
def __init__(self, tokenname):
7+
Client.__init__(self, address='')
8+
self.module += ''
9+
self.tokenname = '&tokenname=' + tokenname
10+
11+
def make_url(self, call_type=''):
12+
if call_type == 'tokensupply':
13+
self.url = self.prefix \
14+
+ self.module \
15+
+ self.action \
16+
+ self.tokenname \
17+
+ self.key
18+
elif call_type == 'tokenbalance':
19+
self.url = self.prefix \
20+
+ self.module \
21+
+ self.action \
22+
+ self.address \
23+
+ self.tokenname \
24+
+ self.key
25+
26+
def get_total_supply(self):
27+
self.action += 'tokensupply'
28+
self.module += 'stats'
29+
self.make_url(call_type='tokensupply')
30+
req = self.connect()
31+
if req.status_code == 200:
32+
return json.loads(req.text)['result']
33+
else:
34+
return req.status_code
35+
36+
def get_token_balance(self, address):
37+
self.address += address
38+
self.module += 'account'
39+
self.action += 'tokenbalance'
40+
self.make_url(call_type='tokenbalance')
41+
req = self.connect()
42+
if req.status_code == 200:
43+
return json.loads(req.text)['result']
44+
else:
45+
return req.status_code

‎examples/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'Corey Petty'

‎examples/accounts/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__author__ = 'Corey Petty'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
__author__ = 'Corey Petty'
2+
from etherscan.accounts import Account
3+
4+
address = '0x2a65aca4d5fc5b5c859090a6c34d164135398226'
5+
6+
api = Account(address=address)
7+
blocks = api.get_all_blocks_mined(offset=10000, blocktype='uncles')
8+
print(blocks)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /