Add review to Goodreads from Schema markup

I write book reviews on my blog. I also want to syndicate them to Goodreads.

Sadly, Goodreads doesn't natively read the markup I so carefully craft. So here's the scrap of code I use to syndicate my reviews.

Goodreads API Keys

Get your Keys from

You will also need to get OAuth tokens

For this documentation, I'll use the example keys - please substitute them with your own keys.

from rauth.service import OAuth1Service, OAuth1Session

# Get a real consumer key & secret from:
API_KEY    = 'ABC123'

goodreads = OAuth1Service(
    consumer_key    = API_KEY,
    consumer_secret = API_SECRET,
    request_token_url = '',
    authorize_url     = '',
    access_token_url  = '',
    base_url          = ''

OAUTH_TOKEN, OAUTH_SECRET = goodreads.get_request_token(header_auth=True)
authorize_url = goodreads.get_authorize_url(request_token)

Visit the URL printed out, and authorise the app. Then run this to get the access tokens you need:

session = goodreads.get_auth_session(OAUTH_TOKEN, OAUTH_SECRET)
ACCESS_TOKEN = session.access_token
ACCESS_TOKEN_SECRET = session.access_token_secret

Save those tokens, we'll need them later!

Get JSON-LD from HTML page

This uses Requests and BeautifulSoup.

import requests
from bs4 import BeautifulSoup
import json
import re

review_url = ''
r = requests.get(review_url)
soup = BeautifulSoup(r.text)
pattern = re.compile(r"\"@type\":\"Review\"")
script = soup.find("script", text=pattern)
review = script.text
review_json = json.loads(review)

isbn        = review_json["itemReviewed"]["isbn"]
rating      = review_json["reviewRating"]["ratingValue"]
date        = review_json["datePublished"]:date[0:10]
description = review_json["description"] + " " + review_url

ISBN to Goodreads ID

goodreads_id = requests.get("" + isbn + "?key=" + API_KEY).text

This will return a number - the Goodreads ID.

Post a review

The documentation for posting Goodreads reviews is a bit sparse.

goodreads_api = OAuth1Session(
    consumer_key        = API_KEY,
    consumer_secret     = API_SECRET,
    access_token        = ACCESS_TOKEN,
    access_token_secret = ACCESS_TOKEN_SECRET,

#  Post the review to the API

review_data = {"book_id": goodreads_id, "review[review]":description, "review[rating]":rating, "review[read_at]":date}

response ='', review_data)


Setting the date

The Goodreads API is... crap. Posting the review doesn't actually add a date to the review. So you need to edit the review to post it again. To start with, we need to get the review's ID:

import xml.etree.ElementTree as ET
tree = ET.fromstring(response.text)
review_id = tree.find("id").text
review_data = {"review[read_at]":date[0:10]}
response =''+review_id+'.xml', review_data)

Get the code

The Python code is available on my GitLab.

But... The Goodreads API is a bit picky. ISBN lookup doesn't work very well, and bits of the API are flaky. So while this code mostly works, I don't run it that often.

Share this post on…

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">