Learning Python for Forensics
上QQ阅读APP看书,第一时间看更新

Our first iteration – bitcoin_address_lookup.v1.py

The first iteration of our script will focus primarily on ingesting and processing the data appropriately. In this script, we'll print out transaction summaries for the account to the console. In later iterations, we'll add logging and outputting data to a CSV file. This script has been written and tested specifically for Python 3.7.1. The usage of the urllib library, a library we use to make HTTP requests, is structured differently in Python 2 and 3. In the final iteration of this script, we'll demonstrate the necessary code to make this script Python 2 and 3 compatible.

We'll use five modules in the initial version of the script. The argparsejsonurllib, and sys modules are all part of the standard library. The unix_converter module is the mostly unmodified script that we wrote in Chapter 2Python Fundamentals, and is used here to convert Unix timestamps into the Bitcoin transaction data. The specific version of this module is available in the provided code for this chapter. Both argparse and urllib have been used previously for user input and web requests, respectively. The json module is responsible for loading our transaction data into Python objects that we can manipulate:

001 """First iteration of the Bitcoin JSON transaction parser."""
002 import argparse
003 import json
004 import urllib.request
005 import unix_converter as unix
006 import sys
...
036 __authors__ = ["Chapin Bryce", "Preston Miller"]
037 __date__ = 20181027
038 __description__ = """This scripts downloads address transactions
039 using blockchain.info public APIs"""

Our script's logic is handled by five functions. The main() function, defined on line 42, serves as the coordinator between the other four functions. First, we pass the address supplied by the user to the get_address() function. This function is responsible for calling the blockchain.info API using urllib and returning the JSON data containing the transactions for that address.

Afterward, print_transactions() is called to traverse the nested dictionaries and lists and print out transaction details. In print_transactions(), function calls are made to print_header() and get_inputs(). The print_header() function is responsible for printing out non-transaction data, such as the number of transactions, current balance, and total sent and received values:

042 def main():
...
053 def get_address():
...
070 def print_transactions():
...
098 def print_header():
...
116 def get_inputs():

As seen before, we use argparse to create an ArgumentParser object and add the appropriate argument. Our only argument, ADDR, is a positional argument representing the Bitcoin address of interest. We call the main() function on line 145 and pass the ADDR argument:

128 if __name__ == '__main__':
129 # Run this code if the script is run from the command line.
130 parser = argparse.ArgumentParser(
131 description=__description__,
132 epilog='Built by {}. Version {}'.format(
133 ", ".join(__authors__), __date__),
134 formatter_class=argparse.ArgumentDefaultsHelpFormatter
135 )
136 parser.add_argument('ADDR', help='Bitcoin Address')
137 args = parser.parse_args()
138
139 # Print Script Information
140 print('{:=^22}'.format(''))
141 print('{}'.format('Bitcoin Address Lookup'))
142 print('{:=^22} \n'.format(''))
143
144 # Run main program
145 main(args.ADDR)

A flow diagram of our script can be seen as follows: