Одинаково разочарованный отсутствием приличных опций фильтрации / сортировки в Google Play и вдохновленный вашим предположением, что скрипт Greasemonkey может решить эту проблему, я решил написать один, который я загрузил на https://greasyfork.org/en/ scripts / 24667-google-play-review-rating-filter . Он добавляет пять флажков на страницы приложения на play.google.com, которые позволяют фильтровать отзывы с определенными звездными оценками. Я тестировал его с помощью Greasemonkey и Unified Script Injector в Firefox и Tampermonkey в Chrome.
Вместо того, чтобы воспроизвести весь сценарий здесь, я опишу подход, принятый для тех, кто может быть заинтересован. TL; DR: если вам просто нужно решение, установите соответствующий браузер надстройку и загрузите пользовательский скрипт по ссылке выше. Обратите внимание, что если вы хотите использовать его на своем устройстве Android, вам, вероятно, потребуется использовать Firefox с надстройкой USI (а также выбрать «Запросить сайт рабочего стола» в меню), так как большинство других браузеров Android не поддерживают надстройку. ons или пользовательские скрипты, и Greasemonkey в настоящее время не работает в Firefox для Android - он не будет работать в приложении Google Play.
Когда вы просматриваете обзоры, GP (Google Play) загружает данные для дополнительных обзоров через запросы AJAX на URL-адрес, /store/getreviews
используя POST
метод HTTP . Таким образом, перехватывая эти вызовы AJAX, можно изменить данные, возвращаемые в GP.
XMLHttpRequest.prototype.open
можно заменить на функцию, которая будет вызывать оригинал, но сначала, если запрос относится к данным проверки, измените XMLHttpRequest
объект XHR ( ), чтобы POST
тело запроса могло быть захвачено, а ответ - изменен. send
Свойство может быть присвоен объекту XHR в качестве функции в которой будут храниться POST
данные перед вызовом оригинала. onreadystatechange
Свойство может быть назначено в качестве функции , которая будет изменять ответ перед вызовом функции , назначенной GP этого свойства. Поскольку GP будет назначать onreadystatechange
после этого, Object.defineProperty
потребуется использовать его для переопределения свойства, чтобы наборы значений GP сохранялись, а не фактически присваивались внутреннему свойству. И поскольку responseText
свойство доступно только для чтения, Object.defineProperty
потребуется изменить его значение.
Данные, возвращаемые GP, представлены в формате JSON, хотя в начале они содержат несколько символов мусора, которые должны точно воспроизводиться в любых измененных данных.
Следующий код демонстрирует это и выводит в окно консоли разработчика браузера тело запроса и данные ответа (хотя фактически не изменяет его):
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);
Данные, возвращаемые GP, содержат массив из одного элемента, который представляет собой массив из четырех элементов следующим образом:
- Строка
"ecr"
;
1
если есть еще отзывы, 2
если это последняя «страница» отзывов, 3
если произошла ошибка;
- HTML-код, содержащий «страницу» отзывов (и любые ответы разработчиков) - в настоящее время возвращается 40 отзывов на страницу;
- Номер страницы, соответствующий
pageNum
параметру в теле запроса POST.
HTML-код можно изменить, чтобы удалить обзоры (и любые связанные с ними ответы разработчиков) со звездными оценками, кроме тех, которые представляют интерес. Обзоры соответствуют селектору div.single-review
и имеют потомок, соответствующий div.current-rating
встроенному стилю, где свойство ширины CSS представляет собой процент, соответствующий рейтингу ( 20%
для 1 звезды, 40%
для 2 звезд и т. Д.). Ответы разработчика соответствуют селектору div.developer-reply
и являются братьями и сестрами сразу после обзора.
Добавление флажков в пользовательский интерфейс, позволяющее выбрать, какие звездные рейтинги отзывов показывать, довольно просто. Тем не менее, когда их выбор изменяется, обзоры должны быть получены заново. Изменение порядка сортировки приводит к тому, что это происходит, равно как и выбор того же порядка сортировки, что и раньше. Таким образом, чтобы достичь этого автоматически, всякий раз, когда флажок изменяется, click
событие может быть вызвано в текущем выбранном элементе порядка сортировки, который может быть найден с помощью селектора .id-review-sort-filter .dropdown-child.selected
. Когда изначально загружается страница приложения на GP, первая страница отзывов уже включена и не загружается через AJAX, но пока все флажки установлены изначально, это не имеет значения.
Иногда на странице (40) отзывов не будет ни одного с желаемой оценкой. Если в возвращенном HTML нет элементов, GP не будет запрашивать больше страниц. Таким образом, чтобы удовлетворить это, было бы необходимо получить дополнительные страницы отзывов (через тот же AJAX API, но с изменением pageNum
параметра), пока не появятся некоторые отзывы для возврата. А для последующих страниц этот pageNum
параметр нужно будет перевести, чтобы учесть это.
Когда выбран порядок сортировки «Рейтинг», может быть много страниц 5-звездочных обзоров, прежде чем любой с желаемой оценкой. Повторное извлечение и отбрасывание страниц и страниц отзывов будет неэффективным (и может вызвать временную блокировку IP со стороны Google). В этом случае, когда reviewSortOrder
параметр имеет значение 1
, можно использовать бинарный поиск, чтобы намного быстрее найти следующую страницу с отзывами для возврата. Элемент страницы, соответствующий селектору, span.reviews-num
можно проверить, чтобы найти общее количество отзывов и, таким образом, определить верхнюю границу номера страницы. Хотя, как выясняется в настоящее время, запросы на страницы за пределами страницы 111 получают ответ HTTP 400.