您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Lists all of your reviews with vote and comment tallies, with updates highlighted
当前为
/*=====================================================================================*\ | The Amazon Review Tabulator - TART | | (c) 2016 by Another Floyd | | From your "Public Reviews Written by You" page on Amazon, this script collects and | | tabulates vote tallies and related information, from all of your Amazon reviews. | | Click the "Tabulate" link in the "Your Profile" panel. | \*=====================================================================================*/ // ==UserScript== // @name The Amazon Review Tabulator - TART // @namespace floyd.scripts // @version 1.08 // @author Another Floyd at Amazon.com // @description Lists all of your reviews with vote and comment tallies, with updates highlighted // @include https://www.amazon.com/gp/cdp/member-reviews/* // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM_log // @grant GM_openInTab // ==/UserScript== // Start (function() { var userId = ""; var reviewCount = 0; var reviewerRanking = ""; var helpfulVotes = 0; var urlStart = ""; var urlEnd = ""; var oldStoreItemIDs = []; var oldStoreUpvotes = []; var oldStoreDownvotes = []; var oldStoreComments = []; var newStoreItemIDs = ""; var newStoreUpvotes = ""; var newStoreDownvotes = ""; var newStoreComments = ""; var tallyUpvotes = 0; var tallyDownvotes = 0; var tallyStars = 0; var tallyComments = 0; // use this reference for progress indicator var profileDiv = ""; var profileDivOriginalHTML = ""; var profileDivTabulateHTML = "<br></br><a href='javascript:tabulate();'>Tabulate</a>"; function tabulate() { // reset global accumulators to ensure that repeated script runs remain clean newStoreItemIDs = ""; newStoreUpvotes = ""; newStoreDownvotes = ""; newStoreComments = ""; tallyUpvotes = 0; tallyDownvotes = 0; tallyStars = 0; tallyComments = 0; // set up top of display page var displayBuffer = "<!DOCTYPE html><html lang='en'>" + "<head><meta charset='utf-8'/><title>TART Amazon Review Details</title><style type='text/css'>" + ".tg {border-collapse:collapse;border-spacing:0;width:100%}" + ".tg td{font-family:Arial, sans-serif;font-size:12px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal}" + ".tg th{font-family:Arial, sans-serif;font-size:12px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal}" + ".tg .header-left{font-weight:bold;background-color:#010066;color:#ffffff;text-align:left}" + ".tg .header-right{font-weight:bold;background-color:#010066;color:#ffffff;text-align:right}" + ".tg .cell-left{text-align:left}" + ".tg .cell-right{text-align:right}" + ".tg .hilite-left{text-align:left;background-color:#FFFF12}" + ".tg .hilite-right{text-align:right;background-color:#FFFF12}" + ".t-large {font-size:18px;font-weight:bold;font-family:Arial,sans-serif}" + ".t-small {font-size:8px;font-family:Arial,sans-serif}" + "</style></head><body>" + "<span class='t-large'>Amazon Review Details</span><br>" + "<span class='t-small'>Prepared with The Amazon Review Tabulator - TART</span>" + "<p>Top Reviewer Ranking: " + reviewerRanking + "<br>" + "Reviews Available: " + reviewCount + "<br>" + "Helpful Votes: " + helpfulVotes + "<br>" + "Upvote/Review Ratio: " + (helpfulVotes/reviewCount).toFixed(2) + "</p>" + "<table class='tg'>" + "<tr><th class='header-left'>#</th><th class='header-left'>Item</th><th class='header-left'>Date</th><th class='header-right'>Stars<br></th><th class='header-right'>Upvotes</th><th class='header-right'>Downvotes</th><th class='header-right'>% Helpful<br></th><th class='header-right'>Comments</th></tr>"; // read in stored info from past run, for use in change detection oldStoreItemIDs = GM_getValue("recentItemIDs", "").split(" "); oldStoreUpvotes = GM_getValue("recentUpvotes", "").split(" "); oldStoreDownvotes = GM_getValue("recentDownvotes", "").split(" "); oldStoreComments = GM_getValue("recentComments", "").split(" "); // prepare url with user ID, ready for review page number urlStart = "https://www.amazon.com/gp/cdp/member-reviews/" + userID + "?ie=UTF8&display=public&page="; urlEnd = "&sort_by=MostRecentReview"; // lots of page loading and data retrieval var perPageResponseDiv = []; var pageSetOfTableRows = []; var pageResponseCount = 0; var reviewsProcessed = 0; var pageCount = Math.floor(reviewCount / 10) + ((reviewCount % 10 > 0) ? 1 : 0); //var pageCount = 2; // for testing // initialize the progress indicator // sort of pre-redundant to do this here AND in the loop, but, // looks better, if there is a lag before the first response var progressHTML = "<br></br><b>" + pageCount + "</b>"; profileDiv.innerHTML = profileDivOriginalHTML + progressHTML; var x = 1; while (x <= pageCount) { (function(x){ var urlComplete = urlStart + x + urlEnd; perPageResponseDiv[x] = document.createElement('div'); GM_xmlhttpRequest({ method: "GET", url: urlComplete, onload: function(response) { // save the incoming data perPageResponseDiv[x].innerHTML = response.responseText; pageResponseCount++; // update the progress indicator var progressHTML = "<br></br><b>" + (pageCount - pageResponseCount) + "</b>"; profileDiv.innerHTML = profileDivOriginalHTML + progressHTML; // get parent of any reviewText DIV var findReviews = document.evaluate("//div[@class='reviewText']/..", perPageResponseDiv[x], null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // evaluating the doc DIV made above pageSetOfTableRows[x] = ""; // initialize each member prior to concatenating for (var j = 0; j < findReviews.snapshotLength; j++) { var oneReview = findReviews.snapshotItem(j); var reviewChildren = oneReview.children; var childCount = reviewChildren.length; var commentCount = 0; var itemTitle = "No Title Available"; var itemLink = ""; var permaLink = ""; var starRating = 0; var reviewDate = ""; var upVotes = 0; var downVotes = 0; var itemID = ""; // get number of comments, and permalink var tempText = reviewChildren[childCount-2].textContent; if(tempText.indexOf('Comment (') > -1 || tempText.indexOf('Comments (') > -1) { var paren1 = tempText.indexOf('('); var paren2 = tempText.indexOf(')'); commentCount = tempText.substring(paren1+2,paren2-1); commentCount = parseInt(commentCount.replace(/,/g, '')); // remove commas } var lst = reviewChildren[childCount-2].getElementsByTagName('a'); permaLink = lst[2].getAttribute("href"); // the data items below do not have reliable positions, due to presence // or not, of vine voice tags, verified purchase, votes, etc. // so, are done in a loop with IF checks. Must start loop just above review // text, in case the reviewer has used any of the phrases I am searching for for (var i = childCount - 4; i > -1; i--) { var childHTML = reviewChildren[i].innerHTML; // used 2x, below // get item title and item link var titleClue = childHTML.indexOf('This review is from'); if(titleClue > -1) { var lst = reviewChildren[i].getElementsByTagName('a'); itemLink = lst[0].getAttribute("href"); itemTitle = lst[0].textContent; } // get star rating AND review date var ratingClue = childHTML.indexOf('out of 5 stars'); if(ratingClue > -1) { starRating = childHTML.substring(ratingClue-4,ratingClue-1); reviewDate = reviewChildren[i].lastElementChild.textContent; } // get vote counts var childText = reviewChildren[i].textContent; var voteClue = childText.indexOf('people found the following review helpful'); if(voteClue > -1) { var list = childText.trim().split(" "); // there were extra, invisible spaces! upVotes = parseInt(list[0].replace(/,/g, '')); // remove commas var totalVotes = parseInt(list[2].replace(/,/g, '')); downVotes = totalVotes - upVotes; } } // get item ID var lst = oneReview.parentNode.getElementsByTagName('a'); itemID = lst[0].getAttribute("name"); // get HTML formatted table row pageSetOfTableRows[x] += prepOneTableRow((j+1+(x-1)*10),itemID,itemTitle,permaLink,reviewDate,starRating,upVotes,downVotes,commentCount); // clear the response, to save memory -- // could be critical when there are many review pages perPageResponseDiv[x].innerHTML = ""; reviewsProcessed++; // more reliable than reviewCount, for calculating avg. rating } // see if all data from multiple page loads has arrived if(pageResponseCount==pageCount) { // assemble the sets of table rows for(var y=1; y <= pageCount; y++) { displayBuffer += pageSetOfTableRows[y]; } // add footer and complete the results page displayBuffer += "<tr><td class='header-left'></td><td class='header-left'></td><td class='header-left'></td><td class='header-right'>" + (tallyStars/reviewsProcessed).toFixed(1) + "</td><td class='header-right'>" + tallyUpvotes + "</td><td class='header-right'>" + tallyDownvotes + "</td><td class='header-right'>" + helpfulPercent(tallyUpvotes,tallyDownvotes) + "</td><td class='header-right'>" + tallyComments + "</td></tr></table></body></html>"; // store info to be used in subsequent run, for change detection GM_setValue("recentItemIDs", newStoreItemIDs.trim()); GM_setValue("recentUpvotes", newStoreUpvotes.trim()); GM_setValue("recentDownvotes", newStoreDownvotes.trim()); GM_setValue("recentComments", newStoreComments.trim()); // replace progress indicator with Tabulate link profileDiv.innerHTML = profileDivOriginalHTML + profileDivTabulateHTML; // a display alternative -- put results IN the Amazon page //document.body.innerHTML = displayBuffer; // to open new window, user must allow popups for https://www.amazon.com //var resultsWindow = window.open("data:text/html," + encodeURIComponent(displayBuffer), "_blank", "scrollbars=yes"); // using GM_openInTab does not require exception to be set by user GM_openInTab("data:text/html," + encodeURIComponent(displayBuffer)); } } }); })(x); x++; } } function helpfulPercent(upVotes,downVotes) { var helpfulPercent = ""; upVotes = upVotes; downVotes = downVotes; if(upVotes + downVotes > 0) helpfulPercent = (upVotes/(upVotes+downVotes)*100).toFixed(1); return helpfulPercent; } function prepOneTableRow (row,itemID,itemTitle,permaLink,reviewDate,starRating,upVotes,downVotes,commentCount) { // do these before mangling the values with <b> tags </b> var helpfulPct = helpfulPercent(upVotes,downVotes); itemTitle = "<a href='" + permaLink + "' target='_new'>" + itemTitle.substring(0,65) + "</a>"; // keep tallies to use in table footer tallyUpvotes += upVotes; tallyDownvotes += downVotes; tallyStars += parseInt(starRating); tallyComments += commentCount; // assemble storage info, to use in subsequent run, for change detection newStoreItemIDs += itemID + " "; newStoreUpvotes += upVotes + " "; newStoreDownvotes += downVotes + " "; newStoreComments += commentCount + " "; // see if review for this item has previously been examined var matchIdx = -1; for(var i=0; i<oldStoreItemIDs.length; i++) { if(oldStoreItemIDs[i] == itemID) { // we have a match, an item that has previously been seen matchIdx = i; break; } } var hiliteRow = false; if(matchIdx > -1) { // entry exists; see if any of the numbers have changed if(oldStoreUpvotes[matchIdx] != upVotes) { // for changed number, make it bold, and hilite row upVotes = "<b>" + upVotes + "</b>"; hiliteRow = true; } if(oldStoreDownvotes[matchIdx] != downVotes) { downVotes = "<b>" + downVotes + "</b>"; hiliteRow = true; } if(oldStoreComments[matchIdx] != commentCount) { commentCount = "<b>" + commentCount + "</b>"; hiliteRow = true; } } else { // no match, so, it's a new review; bold the title and hilite the row itemTitle = "<b>" + itemTitle + "</b>"; hiliteRow = true; } var tdLeft = "<td class='cell-left'>"; var tdRight = "<td class='cell-right'>"; if(hiliteRow===true && oldStoreItemIDs[0].length > 0) { tdLeft = "<td class='hilite-left'>"; tdRight = "<td class='hilite-right'>"; } var tableRow = "<tr>" + tdLeft + row + "</td>" + tdLeft + itemTitle + "</td>" + tdLeft + reviewDate + "</td>" + tdRight + starRating + "</td>" + tdRight + upVotes + "</td>" + tdRight + downVotes + "</td>" + tdRight + helpfulPct + "</td>" + tdRight + commentCount + "</td></tr>"; return tableRow; } document.addEventListener('click', function(event) { var tempstr = new String(event.target); if(tempstr.indexOf('tabulate') > -1) { tabulate(); event.stopPropagation(); event.preventDefault(); } }, true); //--- main script block from this point function Tabulate_Amazon_Reviews_Run() { // find profile info panel var findDiv = document.evaluate("//div[contains(.,'Helpful Votes')]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); profileDiv = findDiv.snapshotItem(0); // get reviewer ranking and user ID var lst = profileDiv.getElementsByTagName('a'); reviewerRanking = lst[0].textContent; var charIdx = lst[0].getAttribute("href").indexOf('#'); userID = lst[0].getAttribute("href").substring(charIdx+1); // get helpful votes charIdx = profileDiv.textContent.lastIndexOf(':'); helpfulVotes = profileDiv.textContent.substring(charIdx+2); // get review count var prevSibDiv = profileDiv.previousElementSibling; charIdx = prevSibDiv.textContent.lastIndexOf(':'); reviewCount = prevSibDiv.textContent.substring(charIdx+2); // add Tabulate link; also, save content for use with progress indicator profileDivOriginalHTML = profileDiv.innerHTML; profileDiv.innerHTML += profileDivTabulateHTML; } Tabulate_Amazon_Reviews_Run(); })(); // End
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址