Igualmente frustrado com a falta de opções decentes de filtragem / classificação no Google Play, e inspirado por sua sugestão de que um script Greasemonkey poderia resolver o problema, decidi escrever um, que enviei para https://greasyfork.org/en/ scripts / 24667-google-play-review-rating-filter . Ele adiciona cinco caixas de seleção às páginas do aplicativo em play.google.com, que permitem filtrar comentários com classificações por estrelas específicas. Eu testei com o Greasemonkey e o Unified Script Injector no Firefox e o Tampermonkey no Chrome.
Em vez de reproduzir o script inteiro aqui, descreverei a abordagem adotada para aqueles que possam estar interessados. TL; DR: Se você deseja apenas a solução, instale o complemento de navegador apropriado e faça o download do script do usuário no link acima. Observe que, se você quiser usá-lo no seu dispositivo Android, provavelmente precisará usar o Firefox com o complemento USI (e também selecionar Solicitar site da área de trabalho no menu), pois a maioria dos outros navegadores Android não suporta ons ou scripts de usuário e o Greasemonkey atualmente não funciona no Firefox para Android - ele não funciona no aplicativo Google Play.
À medida que você percorre as análises, o GP (Google Play) carrega dados para obter mais análises por meio de solicitações AJAX no URL /store/getreviewsusando o POSTmétodo HTTP . Portanto, conectando essas chamadas AJAX, é possível modificar os dados retornados ao GP.
XMLHttpRequest.prototype.openpode ser substituído por uma função que chamará o original, mas primeiro, se a solicitação for para revisar dados, modifique o XMLHttpRequestobjeto XHR ( ) para que o POSTcorpo da solicitação possa ser capturado e a resposta modificada. Uma sendpropriedade pode ser atribuída ao objeto XHR como uma função que armazenará os POSTdados antes de chamar o original. A onreadystatechangepropriedade pode ser atribuída como uma função que modificará a resposta antes de chamar a função atribuída pelo GP a esta propriedade. Como o GP atribuirá onreadystatechangedepois disso, Object.definePropertyprecisaria ser usado para redefinir a propriedade para que o valor que o GP define seja armazenado em vez de realmente ser atribuído à propriedade interna. E como a responseTextpropriedade é somente leitura, Object.definePropertyseria necessário alterar seu valor.
Os dados retornados pelo GP estão no formato JSON, embora tenham alguns caracteres indesejados no início, que devem ser reproduzidos fielmente em qualquer dado modificado.
O código a seguir demonstra isso e exibirá na janela do console do desenvolvedor do navegador o corpo da solicitação e os dados de resposta (embora na verdade não os modifique):
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);
Os dados retornados pelo GP compreendem uma matriz de um elemento, que é uma matriz de quatro elementos da seguinte maneira:
- A corda
"ecr";
1se houver mais revisões, 2se esta for a última 'página' de revisões, 3se ocorrer um erro;
- O HTML que contém a 'página' de críticas (e qualquer resposta do desenvolvedor) - atualmente 40 críticas são retornadas por página;
- O número da página, correspondente ao
pageNumparâmetro no corpo da solicitação POST.
O HTML pode ser modificado para remover críticas (e qualquer resposta associada do desenvolvedor) com classificações por estrelas diferentes das de interesse. As revisões correspondem ao seletor div.single-reviewe têm um descendente correspondente div.current-ratinga um estilo embutido, onde a propriedade largura do CSS é uma porcentagem correspondente à classificação ( 20%para 1 estrela, 40%para 2 estrelas, etc.). As respostas do desenvolvedor correspondem ao seletor div.developer-replye são irmãos imediatamente após a revisão.
Adicionar caixas de seleção à interface do usuário para permitir a escolha de quais classificações por estrelas das resenhas devem ser exibidas é bastante simples. No entanto, quando suas seleções são alteradas, as revisões precisam ser buscadas novamente. A alteração da ordem de classificação faz com que isso ocorra, assim como a seleção da mesma ordem de antes. Portanto, para conseguir isso automaticamente, sempre que uma caixa de seleção é alterada, um clickevento pode ser acionado no elemento de ordem de classificação atualmente selecionado, que pode ser encontrado com um seletor de .id-review-sort-filter .dropdown-child.selected. Quando uma página de aplicativo no GP é carregada inicialmente, a primeira página de revisões já está incluída e não é carregada via AJAX, mas desde que as caixas de seleção estejam todas marcadas inicialmente, isso não importa.
Às vezes, uma página de (40) críticas não contém nenhuma com a classificação desejada. Se não houver elementos no HTML retornado, o GP não solicitará mais nenhuma página. Portanto, para atender a isso, seria necessário buscar páginas adicionais de revisões (através da mesma API AJAX, mas modificando o pageNumparâmetro) até que haja algumas revisões a serem retornadas. E para páginas subseqüentes, o pageNumparâmetro precisaria ser traduzido para explicar isso.
Quando a ordem de classificação selecionada é 'Classificação', pode haver muitas páginas com críticas de 5 estrelas antes de qualquer uma com a classificação desejada. Buscar e descartar repetidamente páginas e páginas de resenhas seria ineficiente (e poderia desencadear um bloqueio temporário de IP pelo Google). Nesse caso, quando o reviewSortOrderparâmetro é 1, uma pesquisa binária pode ser empregada para encontrar muito mais rapidamente a próxima página com revisões a serem retornadas. Um elemento da página correspondente ao seletor span.reviews-numpode ser inspecionado para encontrar o número total de revisões e, assim, determinar um número de página superior vinculado. Embora, atualmente, os pedidos de páginas além da página 111 recebam uma resposta HTTP 400.