Using the ISBNdb API with Python

by Salome Grasland

One of the great things about Python is that is can call APIs. I recently found this extremely helpful after scraping ISBN numbers from old bookstore newsletter. I was hoping to create a sort of bibliography of all books mentioned in the newsletter and found the ISBNdb API. While the service isn't free they do offer a 10 day free trial and offer discounted rates for non-profits. Of all the ISBN databases I investigated I found theirs to be really thorough.

Calling the API Using Python

Below is the code used to call the API, you can find the full notebook here.

Calling the needed libraries

import requests
import csv
import time

Insert your API Key

api_key = 'insert your ISBNdb API Key'

Replace with the original list of ISBNs you want to process

isbns_to_process = [
"9780333992845",
"9780915463657",
"9781728275840",
"9781250886040",
"9780505521941",
"9780743296281",
"9780307143754",
"9781529097429",
"9780750283441",
"9781471406232"
]

Store the base URL for the ISBNdb endpoint

base_url = 'https://api2.isbndb.com/book/'

Rate Limiter to throttle how many calls are made per second

The __init__ method is the constructor for the RateLimiter class. It initializes the object with the maximum number of calls allowed per second (calls_per_second), calculates the minimum interval between calls (self.interval), and initializes self.last_call to zero, which will track the timestamp of the last API call made.

class RateLimiter:
  def init(self, calls_per_second):
    self.calls_per_second = calls_per_second
    self.interval = 1.0 / calls_per_second
    self.last_call = 0
    
    def wait(self):
    now = time.time()
    elapsed = now - self.last_call
    if elapsed < self.interval:
        time.sleep(self.interval - elapsed)
    self.last_call = time.time()

rate_limiter = RateLimiter(3) # Allow 3 calls per second

Create a file to save book information

This line opens (or creates if it doesn't exist) a file named 'book_information.csv' in write mode. newline='' ensures that newline characters are handled correctly across different platforms, and encoding='utf-8' ensures the file is encoded in UTF-8. A csv.DictWriter object is created for writing dictionaries to the CSV file. The fieldnames list provides the keys corresponding to the dictionary values.

with open('book_information.csv', 'w', newline='', encoding='utf-8') as csv_file:
      fieldnames = ['ISBN', 'Title', 'Author', 'Publisher', 'Pages', 'Date Published',           'Subjects', 'Binding', 'Synopsis', 'Language', 'Edition', 'Dimensions', 'MSRP', 'Image', 'Status']
  writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
  writer.writeheader()

The API

A for loop starts, iterating over each ISBN in isbns_to_process. For each ISBN, a full URL is constructed for the API request by appending the ISBN to the base_url. The headers dictionary is created containing the Authorization header with the API key. An HTTP GET request is made to the constructed URL with the headers. The response from the API is stored in response. An if condition checks if the HTTP status code of the response is 200, which means the request was successful. The JSON response is parsed, and the script attempts to fetch the 'book' data. If 'book' is not found, an empty dictionary is used as a fallback. This line begins writing a row to the CSV file with the information retrieved from the API.

for isbn in isbns_to_process:
    url = f'{base_url}{isbn}'
    headers = {'Authorization': api_key}

    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        book_info = response.json().get('book', {})
        writer.writerow({
            'ISBN': isbn,
            'Title': book_info.get('title', ''),
            'Author': ', '.join(book_info.get('authors', [])),
            'Publisher': book_info.get('publisher', ''),
            'Pages': book_info.get('pages', ''),
            'Date Published': book_info.get('date_published', ''),
            'Subjects': ', '.join(book_info.get('subjects', [])),  # Add subjects here
            'Binding': book_info.get('binding', ''),
            'Synopsis': book_info.get('synopsis', ''),
            'Language': book_info.get('language', ''),
            'Edition': book_info.get('edition', ''),
            'Dimensions': book_info.get('dimensions', ''),
            'MSRP': book_info.get('msrp', ''),
            'Image': book_info.get('image', ''),
            'Status': 'Success'
        })
    else:
        print(f"Error for ISBN {isbn}: {response.status_code}")
        writer.writerow({
            'ISBN': isbn,
            'Status': 'Error',
            'Title': '',
            'Author': '',
            'Publisher': '',
            'Pages': '',
            'Date Published': '',
            'Binding': '',
            'Synopsis': '',
            'Language': '',
            'Edition': '',
            'Dimensions': '',
            'MSRP': '',
            'Image': ''
        })

    rate_limiter.wait()  # Pause according to the rate limiter
    print("CSV file created successfully.")