Forked from gpiancastelli/goodreads-oauth-example.py
Last active
August 21, 2024 17:57
-
-
Save steve-kertes/5862716 to your computer and use it in GitHub Desktop.
A Python example of how to use OAuth on GoodReads.
Includes scripts to pull list of books that are on a shelf and to add all owned books to a shelf.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from string import Template | |
import oauth2 as oauth | |
import urlparse | |
import urllib | |
import time | |
import xml.dom.minidom | |
import sys, getopt | |
# If you get 'Title Messed Up By Unicode Error' messages try | |
# export PYTHONIOENCODING=utf-8 | |
url = 'http://www.goodreads.com' | |
target_list = 'holding' | |
consumer = oauth.Consumer(key='Your-GoodReads-Key', | |
secret='Your-GoodReads-Secret') | |
token = oauth.Token('oauth token key', | |
'oauth token secret') | |
client = oauth.Client(consumer, token) | |
############################# | |
# | |
# who are we? | |
# | |
def getUserId(): | |
response, content = client.request('%s/api/auth_user' % url,'GET') | |
if response['status'] != '200': | |
raise Exception('Cannot fetch resource: %s' % response['status']) | |
# else: | |
# print 'User loaded.' | |
userxml = xml.dom.minidom.parseString(content) | |
user_id = userxml.getElementsByTagName('user')[0].attributes['id'].value | |
return str(user_id) | |
############################# | |
# | |
# fetch xml for a page of books on a shelf | |
# | |
def getShelfBooks(page, shelf_name): | |
owned_template = Template('${base}/review/list?format=xml&v=2&id=${user_id}&sort=author&order=a&key=${dev_key}&page=${page}&per_page=100&shelf=${shelf_name}') | |
body = urllib.urlencode({}) | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
request_url = owned_template.substitute(base=url, user_id=user_id, page=page, dev_key='gYPjS9uMjMC5CnWuSohlw', shelf_name=shelf_name) | |
response, content = client.request(request_url, 'GET', body, headers) | |
if response['status'] != '200': | |
raise Exception('Failure status: %s for page ' % response['status'] + page) | |
# else: | |
# print 'Page loaded!' | |
return content | |
############################# | |
# | |
# grab id and title from a <book> node | |
# | |
def getBookInfo(book): | |
book_id = book.getElementsByTagName('id')[0].firstChild.nodeValue | |
book_title = book.getElementsByTagName('title')[0].firstChild.nodeValue | |
return book_id, book_title | |
############################# | |
# | |
# grab id and title from a <book> node | |
# | |
def addBookToList(book_id, shelf_name): | |
body = urllib.urlencode({'name': shelf_name, 'book_id': book_id}) | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
response, content = client.request('%s/shelf/add_to_shelf.xml' % url,'POST', body, headers) | |
if response['status'] != '201': | |
raise Exception('Failure status: %s' % response['status']) | |
# else: | |
# print 'Book added!' | |
return True | |
############################# | |
# | |
# loop over each page of owned books | |
# loop over each book | |
# add book to list | |
# | |
user_id = getUserId() | |
print 'User id is: ' + user_id | |
current_page = 0 | |
total_books = 0 | |
while True: | |
current_page = current_page + 1 | |
content = getShelfBooks(current_page, target_list) | |
xmldoc = xml.dom.minidom.parseString(content) | |
page_books = 0 | |
for book in xmldoc.getElementsByTagName('book'): | |
book_id , book_title = getBookInfo(book) | |
try: | |
print 'Book %10s : %s' % (str(book_id), book_title) | |
except UnicodeEncodeError: | |
print 'Book %10s : %s' % (str(book_id), 'Title Messed Up By Unicode Error') | |
page_books += 1 | |
total_books += 1 | |
# addBookToList(book_id, 'holding') | |
# time.sleep(1) | |
# addBookToList(book_id, target_list) | |
# time.sleep(1) | |
print 'Found ' + str(page_books) + ' books on page ' + str(current_page) + ' (total = ' + str(total_books) + ')' | |
time.sleep(1) | |
if (page_books == 0): | |
break; | |
############################# | |
# | |
# so much fun | |
# | |
print 'Found ' + str(total_books) | |
print 'Done.' | |
## END ## |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# oauth example for goodreads | |
# | |
# based on code found in https://gist.github.com/gpiancastelli/537923 by Giulio Piancastelli | |
# | |
# edit script with your dev key and secret | |
# run it | |
# visit the url | |
# confirm that you have accepted | |
# write down token! | |
# | |
import oauth2 as oauth | |
import urllib | |
import urlparse | |
url = 'http://www.goodreads.com' | |
request_token_url = '%s/oauth/request_token' % url | |
authorize_url = '%s/oauth/authorize' % url | |
access_token_url = '%s/oauth/access_token' % url | |
consumer = oauth.Consumer(key='Your-GoodReads-Key', | |
secret='Your-GoodReads-Secret') | |
client = oauth.Client(consumer) | |
response, content = client.request(request_token_url, 'GET') | |
if response['status'] != '200': | |
raise Exception('Invalid response: %s, content: ' % response['status'] + content) | |
request_token = dict(urlparse.parse_qsl(content)) | |
authorize_link = '%s?oauth_token=%s' % (authorize_url, | |
request_token['oauth_token']) | |
print "Use a browser to visit this link and accept your application:" | |
print authorize_link | |
accepted = 'n' | |
while accepted.lower() == 'n': | |
# you need to access the authorize_link via a browser, | |
# and proceed to manually authorize the consumer | |
accepted = raw_input('Have you authorized me? (y/n) ') | |
token = oauth.Token(request_token['oauth_token'], | |
request_token['oauth_token_secret']) | |
client = oauth.Client(consumer, token) | |
response, content = client.request(access_token_url, 'POST') | |
if response['status'] != '200': | |
raise Exception('Invalid response: %s' % response['status']) | |
access_token = dict(urlparse.parse_qsl(content)) | |
# this is the token you should save for future uses | |
print 'Save this for later: ' | |
print 'oauth token key: ' + access_token['oauth_token'] | |
print 'oauth token secret: ' + access_token['oauth_token_secret'] | |
token = oauth.Token(access_token['oauth_token'], | |
access_token['oauth_token_secret']) | |
# | |
# As an example, let's add a book to one of the user's shelves | |
# | |
add_to_list = False | |
def addABook(): | |
client = oauth.Client(consumer, token) | |
# the book is: "Generation A" by Douglas Coupland | |
body = urllib.urlencode({'name': 'to-read', 'book_id': 6801825}) | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
response, content = client.request('%s/shelf/add_to_shelf.xml' % url, | |
'POST', body, headers) | |
# check that the new resource has been created | |
if response['status'] != '201': | |
raise Exception('Cannot create resource: %s' % response['status']) | |
else: | |
print 'Book added!' | |
if add_to_list: | |
addABook() | |
## END ## |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# I addded all my books to 'owned books' with the Quick Add. | |
# Since none of those books were on an actual shelf I could not export them. | |
# This script will move _all_ owned books to a shelf. | |
# | |
# Use goodreads-oauth-example.py to get an oauth token for your application. | |
# Fill in the consumer and token strings. | |
# Be sure to set target_list to the list you want to move _all_ your owned books onto. | |
# | |
from string import Template | |
import oauth2 as oauth | |
import urlparse | |
import urllib | |
import time | |
import xml.dom.minidom | |
import sys, getopt | |
# If you get 'Title Messed Up By Unicode Error' messages try | |
# export PYTHONIOENCODING=utf-8 | |
target_list = 'own' | |
consumer = oauth.Consumer(key='Your-GoodReads-Key', | |
secret='Your-GoodReads-Secret') | |
token = oauth.Token('oauth token key', | |
'oauth token secret') | |
client = oauth.Client(consumer, token) | |
url = 'http://www.goodreads.com' | |
############################# | |
# | |
# who are we? | |
# | |
def getUserId(): | |
response, content = client.request('%s/api/auth_user' % url,'GET') | |
if response['status'] != '200': | |
raise Exception('Cannot fetch resource: %s' % response['status']) | |
# else: | |
# print 'User loaded.' | |
userxml = xml.dom.minidom.parseString(content) | |
user_id = userxml.getElementsByTagName('user')[0].attributes['id'].value | |
return str(user_id) | |
############################# | |
# | |
# fetch xml for a page of owned books | |
# | |
def getOwnedBooks(page): | |
owned_template = Template('${base}/owned_books/user?format=xml&id=${user_id}&page=${page}&per_page=100') | |
body = urllib.urlencode({}) | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
request_url = owned_template.substitute(base=url, user_id=user_id, page=page) | |
response, content = client.request(request_url, 'GET', body, headers) | |
if response['status'] != '200': | |
raise Exception('Failure status: %s for page ' % response['status'] + page) | |
# else: | |
# print 'Page loaded!' | |
return content | |
############################# | |
# | |
# grab id and title from a <book> node | |
# | |
def getBookInfo(book): | |
book_id = book.getElementsByTagName('id')[0].firstChild.nodeValue | |
book_title = book.getElementsByTagName('title')[0].firstChild.nodeValue | |
return book_id, book_title | |
############################# | |
# | |
# ask api to add a book to a shelf | |
# | |
def addBookToList(book_id, shelf_name): | |
body = urllib.urlencode({'name': shelf_name, 'book_id': book_id}) | |
headers = {'content-type': 'application/x-www-form-urlencoded'} | |
response, content = client.request('%s/shelf/add_to_shelf.xml' % url,'POST', body, headers) | |
if response['status'] != '201': | |
raise Exception('Failure status: %s' % response['status']) | |
# else: | |
# print 'Book added!' | |
return True | |
############################# | |
# | |
# loop over each page of owned books | |
# loop over each book | |
# add book to list | |
# | |
user_id = getUserId() | |
print 'User id is: ' + user_id | |
current_page = 0 | |
total_books = 0 | |
while True: | |
current_page = current_page + 1 | |
content = getOwnedBooks(current_page) | |
xmldoc = xml.dom.minidom.parseString(content) | |
page_books = 0 | |
for book in xmldoc.getElementsByTagName('book'): | |
book_id , book_title = getBookInfo(book) | |
try: | |
print 'Book %10s : %s' % (str(book_id), book_title) | |
except UnicodeEncodeError: | |
print 'Book %10s : %s' % (str(book_id), 'Title Messed Up By Unicode Error') | |
page_books += 1 | |
total_books += 1 | |
addBookToList(book_id, target_list) | |
time.sleep(1) | |
print 'Found ' + str(page_books) + ' books on page ' + str(current_page) + ' (total = ' + str(total_books) + ')' | |
time.sleep(1) | |
if (page_books == 0): | |
break; | |
############################# | |
# | |
# so much fun | |
# | |
print 'Found ' + str(total_books) | |
print 'Done.' | |
## END ## |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For those of you who are getting a 301 response when running the file
goodreads-oauth-example.py
, replacehttp
withhttps
in the url of Goodreads :)