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 Schema.org 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 https://www.goodreads.com/api/keys

You will also need to get OAuth tokens

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

 Python 3from rauth.service import OAuth1Service, OAuth1Session

# Get a real consumer key & secret from: https://www.goodreads.com/api/keys
API_KEY    = 'ABC123'
API_SECRET = 'XYZ789'

goodreads = OAuth1Service(
    consumer_key    = API_KEY,
    consumer_secret = API_SECRET,
    name='goodreads',
    request_token_url = 'https://www.goodreads.com/oauth/request_token',
    authorize_url     = 'https://www.goodreads.com/oauth/authorize',
    access_token_url  = 'https://www.goodreads.com/oauth/access_token',
    base_url          = 'https://www.goodreads.com/'
)

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

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

 Python 3session = 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.

 Python 3import requests
from bs4 import BeautifulSoup
import json
import re

review_url = 'https://shkspr.mobi/blog/2019/11/review-because-internet-by-gretchen-mcculloch/'
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

 Python 3goodreads_id = requests.get("https://www.goodreads.com/book/isbn_to_id/" + 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.

 Python 3goodreads_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
#   https://www.goodreads.com/api/index#review.create

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

response = goodreads_api.post('https://www.goodreads.com/review.xml', review_data)

print(response.text)

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:

 Python 3import 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 = goodreads_api.post('https://www.goodreads.com/review/'+review_id+'.xml', review_data)
print(response.text)

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="">