Igualmente frustrado por la falta de opciones de filtrado / clasificación decentes en Google Play, e inspirado por su sugerencia de que un script de Greasemonkey podría resolver el problema, decidí escribir uno, que he subido a https://greasyfork.org/en/ scripts / 24667-google-play-review-rating-filter . Agrega cinco casillas de verificación a las páginas de la aplicación en play.google.com que le permiten filtrar las reseñas con calificaciones de estrellas específicas. Lo probé con Greasemonkey y Unified Script Injector en Firefox, y Tampermonkey en Chrome.
En lugar de reproducir el guión completo aquí, describiré el enfoque adoptado para aquellos que puedan estar interesados. TL; DR: si solo desea la solución, instale el complemento de navegador apropiado y descargue el script de usuario desde el enlace de arriba. Tenga en cuenta que si desea usarlo en su dispositivo Android, probablemente necesitará usar Firefox con el complemento USI (y también seleccionar Solicitar sitio de escritorio en el menú), ya que la mayoría de los otros navegadores Android no admiten ons o scripts de usuario y Greasemonkey actualmente no funciona en Firefox para Android, no funcionará en la aplicación Google Play.
A medida que revisa las revisiones, GP (Google Play) carga datos para más revisiones a través de solicitudes AJAX a la URL /store/getreviews
utilizando el POST
método HTTP . Entonces, al conectar estas llamadas AJAX, es posible modificar los datos devueltos a GP.
XMLHttpRequest.prototype.open
se puede reemplazar con una función que llamará al original, pero primero, si la solicitud es para revisar datos, modifique el XMLHttpRequest
objeto XHR ( ) para que POST
se pueda capturar el cuerpo de la solicitud y se modifique la respuesta. Se send
puede asignar una propiedad al objeto XHR como una función que almacenará los POST
datos antes de llamar al original. La onreadystatechange
propiedad se puede asignar como una función que modificará la respuesta antes de llamar a la función asignada por GP a esta propiedad. Como GP asignará onreadystatechange
después de esto, Object.defineProperty
necesitaría usarse para redefinir la propiedad de modo que el valor que GP establece se almacene en lugar de asignarse realmente a la propiedad interna. Y como la responseText
propiedad es de solo lectura, Object.defineProperty
sería necesario cambiar su valor.
Los datos devueltos por GP están en formato JSON, aunque tienen algunos caracteres de basura al inicio que deben reproducirse fielmente en cualquier dato modificado.
El siguiente código demuestra esto, y enviará a la ventana de la consola del desarrollador del navegador el cuerpo de la solicitud y los datos de respuesta (aunque en realidad no lo modifica):
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);
Los datos devueltos por GP comprenden una matriz de un elemento que es una matriz de cuatro elementos de la siguiente manera:
- La cuerda
"ecr"
;
1
si hay más comentarios, 2
si esta es la última 'página' de comentarios, 3
si ocurrió un error;
- El HTML que contiene la 'página' de las revisiones (y las respuestas de los desarrolladores): actualmente se devuelven 40 revisiones por página;
- El número de página, correspondiente al
pageNum
parámetro en el cuerpo de la solicitud POST.
El HTML se puede modificar para eliminar las reseñas (y cualquier respuesta asociada del desarrollador) con calificaciones de estrellas distintas a las de interés. Las revisiones coinciden con el selector div.single-review
y tienen un descendiente que coincide div.current-rating
con un estilo en línea donde la propiedad de ancho CSS es un porcentaje correspondiente a la calificación ( 20%
para 1 estrella, 40%
para 2 estrellas, etc.). Las respuestas del desarrollador coinciden con el selector div.developer-reply
y son hermanos inmediatamente después de la revisión.
Agregar casillas de verificación a la interfaz de usuario para permitir elegir qué clasificación por estrellas de las reseñas mostrar es bastante sencillo. Sin embargo, cuando se cambian sus selecciones, las revisiones deben recuperarse nuevamente. Cambiar el orden de clasificación hace que esto ocurra, al igual que seleccionar el mismo orden de clasificación que antes. Para lograr esto automáticamente, cada vez que se cambia una casilla de verificación, click
se puede activar un evento en el elemento de orden de clasificación seleccionado actualmente, que se puede encontrar con un selector de .id-review-sort-filter .dropdown-child.selected
. Cuando se carga inicialmente una página de aplicación en GP, la primera página de revisiones ya está incluida y no se carga a través de AJAX, pero mientras las casillas de verificación estén marcadas inicialmente, eso no importará.
A veces, una página de (40) reseñas no contendrá ninguna con una calificación deseada. Si no hay elementos en el HTML devuelto, GP no solicitará más páginas. Entonces, para atender esto, sería necesario buscar páginas adicionales de revisiones (a través de la misma API de AJAX, pero modificando el pageNum
parámetro) hasta que haya algunas revisiones para devolver. Y para las páginas subsiguientes, el pageNum
parámetro necesitaría traducción para dar cuenta de esto.
Cuando el orden de clasificación seleccionado es 'Calificación', podría haber muchas páginas de reseñas de 5 estrellas antes que ninguna con una calificación deseada. Recuperar y descartar repetidamente páginas y páginas de reseñas sería ineficiente (y podría provocar un bloqueo temporal de IP por parte de Google). En este caso, cuando el reviewSortOrder
parámetro es 1
, se puede emplear una búsqueda binaria para encontrar mucho más rápidamente la siguiente página con revisiones para regresar. Se span.reviews-num
puede inspeccionar un elemento de página que coincida con el selector para encontrar el número total de revisiones y así determinar un límite de número de página superior. Sin embargo, como resulta actualmente, las solicitudes de páginas más allá de la página 111 reciben una respuesta HTTP 400.