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.
import 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.
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
# 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:
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 = 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.