Ebenso frustriert über das Fehlen anständiger Filter- / Sortieroptionen in Google Play und inspiriert von Ihrem Vorschlag, dass ein Greasemonkey-Skript das Problem lösen könnte, habe ich beschlossen, eines zu schreiben, das ich auf https://greasyfork.org/en/ hochgeladen habe. scripts / 24667-google-play-review-bewertungsfilter . App-Seiten auf play.google.com werden mit fünf Kontrollkästchen versehen, mit denen Sie nach Bewertungen mit bestimmten Sternebewertungen filtern können. Ich habe es mit Greasemonkey und Unified Script Injector in Firefox und Tampermonkey in Chrome getestet .
Anstatt das gesamte Skript hier zu reproduzieren, beschreibe ich den Ansatz für diejenigen, die interessiert sein könnten. TL; DR: Wenn Sie nur die Lösung wünschen, installieren Sie das entsprechende Browser-Add-On und laden Sie das Benutzerskript über den obigen Link herunter. Beachten Sie, dass Sie, wenn Sie es auf Ihrem Android-Gerät selbst verwenden möchten, wahrscheinlich Firefox mit dem USI-Add-On verwenden müssen (und im Menü auch Desktop-Site anfordern auswählen müssen), da die meisten anderen Android-Browser das Add-On nicht unterstützen. Ons oder Benutzerskripte und Greasemonkey funktioniert derzeit nicht in Firefox für Android - es funktioniert nicht in der Google Play App.
Während Sie durch die Bewertungen blättern, lädt GP (Google Play) /store/getreviews
mithilfe der HTTP- POST
Methode Daten für weitere Bewertungen über AJAX-Anforderungen an die URL . Durch das Verknüpfen dieser AJAX-Aufrufe können die an GP zurückgegebenen Daten geändert werden.
XMLHttpRequest.prototype.open
kann durch eine Funktion ersetzt werden, die das Original aufruft. Wenn die Anforderung jedoch Überprüfungsdaten enthält, ändern Sie zuerst das XHR ( XMLHttpRequest
) -Objekt, damit der POST
Anforderungshauptteil erfasst und die Antwort geändert werden kann. Dem send
XHR-Objekt kann eine Eigenschaft als Funktion zugewiesen werden, die die POST
Daten speichert , bevor das Original aufgerufen wird . Die onreadystatechange
Eigenschaft kann als Funktion zugewiesen werden, die die Antwort ändert, bevor die von GP dieser Eigenschaft zugewiesene Funktion aufgerufen wird. Da GP danach zuweisen onreadystatechange
wird, Object.defineProperty
müsste es verwendet werden, um die Eigenschaft neu zu definieren, damit der Wert, den GP setzt, gespeichert wird, anstatt tatsächlich der internen Eigenschaft zugewiesen zu werden. Und da die responseText
Eigenschaft schreibgeschützt ist, Object.defineProperty
wäre sie erforderlich, um ihren Wert zu ändern.
Die von GP zurückgegebenen Daten sind im JSON-Format, enthalten jedoch zu Beginn einige Junk-Zeichen, die in allen geänderten Daten originalgetreu wiedergegeben werden sollten.
Der folgende Code demonstriert dies und gibt den Anforderungshauptteil und die Antwortdaten an das Entwicklerkonsolenfenster des Browsers aus (ändert sie jedoch nicht):
XMLHttpRequest.prototype.open = (function(open) {
return function(method, url) {
if (
method === 'POST' &&
url &&
url.replace(/^https?:\/\/play\.google\.com/, '').split('?', 1)[0] ===
'/store/getreviews'
) {
var requestBody;
var orgSend = this.send;
var orgOnReadyStateChange = this.onreadystatechange;
this.send = function(data) {
requestBody = data;
return orgSend.apply(this, arguments);
};
this.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
var responseText = this.responseText;
var nJunkChars = responseText.indexOf('[');
try {
var jsonData = JSON.parse(
nJunkChars ? responseText.substr(nJunkChars) : responseText
);
// TODO: modify jsonData here
console.log('Request: %o\nResponse: %o', requestBody, jsonData);
Object.defineProperty(this, 'responseText', {
value: responseText.substr(0, nJunkChars) +
JSON.stringify(jsonData),
configurable: true,
enumerable: true
});
} catch (e) {
console && console.log && console.log(e);
}
}
if (orgOnReadyStateChange) {
return orgOnReadyStateChange.apply(this, arguments);
}
};
Object.defineProperty(this, 'onreadystatechange', {
get: function() { return orgOnReadyStateChange; },
set: function(v) { orgOnReadyStateChange = v; },
configurable: true,
enumerable: true
});
}
return open.apply(this, arguments);
};
})(XMLHttpRequest.prototype.open);
Die von GP zurückgegebenen Daten umfassen ein Array aus einem Element, das wie folgt aus vier Elementen besteht:
- Die Zeichenfolge
"ecr"
;
1
Wenn es mehr Bewertungen gibt, 2
wenn dies die letzte "Seite" der Bewertungen ist, 3
wenn ein Fehler aufgetreten ist;
- Der HTML-Code, der die "Seite" der Bewertungen (und alle Antworten der Entwickler) enthält. Derzeit werden 40 Bewertungen pro Seite zurückgegeben.
- Die Seitenzahl, die dem
pageNum
Parameter im POST-Anforderungshauptteil entspricht.
Der HTML-Code kann geändert werden, um Bewertungen (und alle damit verbundenen Entwicklerantworten) mit anderen als den interessierenden Sternebewertungen zu entfernen. Die Bewertungen stimmen mit dem Selektor überein div.single-review
und haben einen Nachkommen, der div.current-rating
mit einem Inline-Stil übereinstimmt, wobei die CSS-Breiten-Eigenschaft ein Prozentsatz ist, der der Bewertung entspricht ( 20%
für 1 Stern, 40%
für 2 Sterne usw.). Entwicklerantworten stimmen mit dem Selektor überein div.developer-reply
und sind Geschwister, die unmittelbar auf die Überprüfung folgen.
Das Hinzufügen von Kontrollkästchen zur Benutzeroberfläche, um die Auswahl der Sternebewertungen der anzuzeigenden Bewertungen zu ermöglichen, ist ziemlich einfach. Wenn jedoch ihre Auswahl geändert wird, müssen die Bewertungen erneut abgerufen werden. Das Ändern der Sortierreihenfolge führt dazu, dass dies auftritt, ebenso wie das Auswählen derselben Sortierreihenfolge wie zuvor. Um dies automatisch zu erreichen, kann bei jedem Ändern eines Kontrollkästchens ein click
Ereignis für das aktuell ausgewählte Sortierreihenfolgeelement ausgelöst werden, das mit einem Selektor von gefunden werden kann .id-review-sort-filter .dropdown-child.selected
. Wenn eine App-Seite auf GP zum ersten Mal geladen wird, ist die erste Seite der Bewertungen bereits enthalten und wird nicht über AJAX geladen. Solange jedoch alle Kontrollkästchen aktiviert sind, spielt dies keine Rolle.
Manchmal enthält eine Seite mit (40) Bewertungen keine mit einer gewünschten Bewertung. Wenn im zurückgegebenen HTML-Code keine Elemente vorhanden sind, fordert GP keine weiteren Seiten an. Um dies zu berücksichtigen, müssten zusätzliche Überprüfungsseiten abgerufen werden (über dieselbe AJAX-API, jedoch unter Änderung des pageNum
Parameters), bis einige Überprüfungen zurückgegeben werden müssen. Und für nachfolgende Seiten pageNum
müsste der Parameter übersetzt werden, um dies zu berücksichtigen.
Wenn die ausgewählte Sortierreihenfolge "Bewertung" lautet, gibt es möglicherweise viele Seiten mit 5-Sterne-Bewertungen vor jeder mit einer gewünschten Bewertung. Das wiederholte Abrufen und Verwerfen von Seiten und Seiten mit Bewertungen wäre ineffizient (und könnte eine vorübergehende IP-Blockierung durch Google auslösen). In diesem Fall, wenn der reviewSortOrder
Parameter ist 1
, kann eine binäre Suche verwendet werden, um die nächste Seite mit den zurückzugebenden Überprüfungen viel schneller zu finden. Ein mit dem Selektor übereinstimmendes Seitenelement span.reviews-num
kann überprüft werden, um die Gesamtzahl der Überprüfungen zu ermitteln und so eine obere Seitenzahl zu bestimmen. Wie sich derzeit herausstellt, erhalten Anforderungen für Seiten über Seite 111 hinaus eine HTTP 400-Antwort.