# Utility module for using Amazon's XML services. # Adam Sampson import os, urllib, xml.dom.minidom, time, hmac, hashlib, lxml.html, re import subprocess import urllib2 from lxml import etree from offog import die, warn def get_token(): """Return (token, secret_key, associate_tag).""" f = open(os.environ["HOME"] + "/.amazon_token") fields = f.read().strip().split() f.close() return (fields[0], fields[1], fields[2]) def call(args): """Call an Amazon API with the given args, returning an xml.dom.minidom-parsed version of the response.""" (token, secret_key, associate_tag) = get_token() all_args = {} all_args.update(args) all_args["Service"] = "AWSECommerceService" all_args["SubscriptionId"] = token all_args["AssociateTag"] = associate_tag all_args["Timestamp"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) def aquote(s): return urllib.quote(s, "~") uri_args = [(aquote(k) + "=" + aquote(v)).encode("UTF-8") for k, v in all_args.items()] uri_args.sort() uri_host = "webservices.amazon.co.uk" uri_path = "/onca/xml" uri_query = "&".join(uri_args) uri = "https://%s%s?%s" % (uri_host, uri_path, uri_query) sign_data = chr(10).join(["GET", uri_host, uri_path, uri_query]) signature = hmac.new(secret_key, sign_data, hashlib.sha256).digest() uri += "&Signature=" + aquote(signature.encode("base64").strip()) f = urllib.urlopen(uri) data = xml.dom.minidom.parse(f) f.close() return data def isbn_to_asin(isbn): if len(isbn) == 10: return isbn elif len(isbn) == 13 and isbn.startswith("978"): # Convert to ISBN-10. # See: https://en.wikipedia.org/wiki/ISBN csum = 0 for i, c in enumerate(isbn[3:-1]): csum += int(c) * (10 - i) x = isbn[3:-1] + "0123456789X0"[11 - (csum % 11)] return x else: raise ValueError("Bad ISBN: " + isbn) def item_url(asin): """Return the URL for an item.""" return "https://www.amazon.co.uk/dp/" + asin def get_text(node): """Return the contents of the first text node encountered in a minidom subtree.""" for cn in node.childNodes: if cn.nodeType == node.TEXT_NODE: return cn.data return None def get_wishlist_items(wishlist_id): """Return a dictionary mapping item IDs to titles from the given wishlist.""" # Amazon used to have an API call for this (ListLookup), but it # disappeared some time in 2010... # And in 2016 it stopped accepting requests without a fake User-Agent. # And in 2017 it turned into some horrific AJAX disaster. url = "https://www.amazon.co.uk/hz/wishlist/ls/%s?type=wishlist&filter=all&sort=default" % wishlist_id items = {} while True: print "Fetching", url request = urllib2.Request(url) request.add_header("User-Agent", "User-Agent: Mozilla/5.0 (X11; Linux.x86_64; rv:48.0) Gecko/20100101 Firefox/48.0") f = urllib2.urlopen(request) page = lxml.html.parse(f).getroot() f.close() page.make_links_absolute(url) found_any = False for anchor in page.cssselect("a.a-link-normal"): aid = anchor.get("id", "") if not aid.startswith("itemName_"): continue m = re.search(r'/dp/([^\?/]+)', anchor.get("href", "")) if m is not None: items[m.group(1)] = anchor.get("title") found_any = True # Find the next page. for anchor in page.cssselect("a.wl-see-more"): if anchor.text_content().find("See More") != -1: url = anchor.get("href") break else: # No more pages. break if not found_any: die("No items found") return items def load_hux_wishlist(filename): """Parse a hux file containing wishlist items for ones that Amazon can find. (This is the source for the wishlist on my web site.) Return a dict mapping item IDs to titles.""" items = {} f = subprocess.Popen(["hux", filename], stdout=subprocess.PIPE).stdout wishlist = etree.parse(f).getroot() f.close() for tag in ("isbn", "amazon", "amazonde", "amazonus"): for el in wishlist.iter(tag=tag): if tag == "isbn": asin = isbn_to_asin(el.text) if asin != el.text: warn("ISBN ", el.text, " should be ", asin) else: asin = el.text items[asin] = el.getparent().find("title").text return items if __name__ == "__main__": assert isbn_to_asin("0356511081") == "0356511081" assert isbn_to_asin("9780099449256") == "0099449250" assert isbn_to_asin("9780356511085") == "0356511081" assert isbn_to_asin("9780356511689") == "0356511685"

AltStyle によって変換されたページ (->オリジナル) /