phantom.outputEncoding="cp1251"; // для української мови в консолі
console.log('hello'); // для перевірки, що воно взагалі працює
var fs = require('fs'); //отримужмо модуль роботи з файловою системою
var page = require('webpage').create(); //отримуємо модуль для роботи зі сторінкою, та ініалізуємо об'єкт сторінки
page.onError = function(msg, trace) { //для оброблення помилок
console.log(msg); //перенаправляємо повідомлення про помилку в консолю
};
page.onConsoleMessage = function(msg) { //оброблюємо повідомлення відправлені через console.log() в межах завантаженої сторінки
console.log(msg);//перенаправляємо те повідомлення в консоль
}
var fullArr = []; //масив, що буде містити всі записи в форматі {ім'я, тема, дата}
/* ПІДРАХУНОК ПОДЯК ВІД КОРИСТУВАЧІВ */
/*
цей метод викликається після отримання всіх даних
він підраховує кількість подяк від кожного унікального юзера, та сортує ті дані
*/
function processThanks() {
try {
console.log('\nprocessing thanks');
var result = []; //цей масив буде містити кінцеві дані
for(var i = 0; i < fullArr.length; i++) { //проходимо по кожному рядку
const name = fullArr[i].name; //запам'ятовуємо ім'я в поточному рядку
var ind = -1; //ця змінна може містити індекс об'єкту в кінцевому масиві
for(var j = 0; j < result.length; j++) { //проходимось по кінцевому масиву
if(result[j].name==name) { //якщо ім'я юзера в кінцевому масиві співпадає з ім'ям юзера з загального масиву
ind=j; //запам'ятовуємо індекс об'єкту з кінцевого масива
break; //кінчаємо цикл
}
}
if (ind >= 0) { //якщо в кінцевому масиві ми знайшли об'єкт з таким же ім'ям, як в загальному масиві
result[ind].count+=1; //збільшуємо кількість подяк на 1 на об'єкті, що в кінцевому масиві
} else {
result.push({'name': name, 'count': 1}); // або додаємо об'єкт з відповідним іменем і кількістю подяк рівною 1 в кінцевий масив
}
}
try {
result.sort(function(a, b) { //сортуємо об'єкти в кінцевому масиві по спаданню
return b.count - a.count;
});
console.log('returning result');
return result;
//fs.write('data.txt', JSON.stringify(result, null, ' '), 'w'); //записуємо дані в форматі JSON в файлик в поточній директоріх, з іменем data.txt
} catch(e) {
console.log(e);
}
} catch(err) {
console.log(err);
}
}
/*
цей метод рекурсивно завантажує сторінки, що містять записи про подяки, та додає ті записи в загальний масив
fullNumber - загальна кількість подяк
found - кількість записів з подяками, котра була додана в загальний масив
pageNumber - номер сторінки, котру потрібно завантажити та обробити
*/
function counting(startUrl, fullNumber, found, pageNumber, callback) {
console.log('\nstartUrl: ' +startUrl+ ' fullNumber: '+fullNumber+' found: '+found+' pageNumber: '+pageNumber);
page.open(startUrl+'page/'+pageNumber, function(status) { //починаємо завантаження сторінки
console.log('status: '+status); //показуємо статус завантаження, success, якщо все окей, і fail, якщо не вдалось завантажити
if(page.injectJs('jquery.js')) { //підключаємо jQuery, що знаходиться в тій самій директорії, що й головний .js файл
// код в цій функції виконується в області змінних сторінки, в цій функції ми не маємо доступу до змінних, що визначені не за межами цієї функції
var arr = page.evaluate(function() {
var arr = []; //локальний масив. котрий буде містити записи з подяками з цієї конкретної сторінки
$('.ct-group tbody tr:lt(25)').each(function(index, el) { // дістаємо рядок таблиці, що містить дані про подяку, :lt(25) дозволяє обрати перші 25 записів
var name = $(el).find('td:nth-child(1) a').text(); // витягуємо перший td елемент, котрий містить ім'я того, хто подякував
var theme = $(el).find('td:nth-child(2) a').text(); // витягуємо другий td елемент, містить назву теми, в котрій подякували
var date = $(el).find('td:nth-child(3)').text(); // витягуємо дату подяки, але в форматі тексту, можете її парсити в об'єкт Data, якщо хочете
arr.push({'name': name, 'theme': theme, 'date': date}); //додаємо запис з даними про подяку в локальний масив
});
return arr; //повертаємо локальний масив з даними про подяки на цій сторінці
});
console.log('found: '+arr.length);
try {
fullArr = fullArr.concat(arr); //додаємо масив з записами конкретної сторінки в загальний масив, котрий буде містити записи з усіх сторінок
} catch(e) {
console.log(e);
}
console.log('fullArr: '+fullArr.length);
if(fullArr.length<fullNumber) { //якщо кількість записів в загальному масиві менша, ніж кількість подяк
console.log('calling counting again...');
counting(startUrl, fullNumber, fullArr.length, ++pageNumber, callback); //запускаємо цю функцію заново, але з інкрементованим номером сторінки, аби завантажувати наступну сторінку
} else {
console.log('done, found: '+fullArr.length+" last page: "+pageNumber);
var thanks = processThanks();
console.log('got thanks after processing '+thanks.length);
callback(thanks);
}
}
});
}
/*
тут ми завантажуємо першу сторінку, і витягуємо з неї загальну кількість подяк
*/
const thanksUrl = 'http://replace.org.ua/thanks/view/'; //посилання на сторінку з лайками
var finishedData = []; //тут будуть знаходитись дані про юзерів без даних про те. скільки і кому подяк вони поставили, а потім ці дані додадуться, і цей масив буде збережений в файлик
/*
рахуємо, хто скільки кому лайків поставив, додаємо ці дані до вже існуючих даних, і зберігаємо в файлик
*/
function countMostLiked() {
var mostLikes = []; //цей масив буде зберігати лише дані про те, кому і скільки загалом подяе поставив кожен озер
for (var i = 0; i < finishedData.length; i++) { //проходимось по масиву з усіма юзерами, котрі отримали хоча б одну подяку
var currUser = finishedData[i];
console.log('\ncounting thanks for user: '+currUser.name);
for(var j = 0; j < currUser.fans.length; j++) { //проходимось по спику юзерів, котрі подякували поточному юзеру
var aFan = currUser.fans[j];
var index = -1;
for (var k = 0; k < mostLikes.length; k++) { //шукаємо ім'я того, хто подякував, в масиві
if (mostLikes[k].name===aFan.name) {
index = k;
break;
}
}
if (index >= 0) { //якщо ім'я юзера було знайдено в масиві
var liker = mostLikes[index];
var idolIndex = -1;
for (var m = 0; m < liker.thanked.length; m++) { //шукаємо ім'я поточного юзера (котрому поставили подяку), в масиві подяк від поточного юзера зі списку юзерів, що подякували
if (liker.thanked[m].name===currUser.name) {
idolIndex = m;
break;
}
}
if (idolIndex >= 0) { //якщо ім'я такого юзера було знайдене
liker.thanked[idolIndex].count+=aFan.count; //додаємо до загальної кількості подяк поставлених цим юзером ті подяки, котрі були поставлені поточного юзеру зі списку тих, кому подякували
console.log(aFan.name+' : '+aFan.count);
} else { //якщо ім'я не знайшли
liker.thanked.push({'name': currUser.name, 'count': aFan.count}); //додаємо дані про юзера, котрому поставили подяку, і кількість подяк, котру отримав цей юзер від поточного юзера
console.log('first: '+aFan.name+' : '+aFan.count);
}
} else { //якщо ім'я не було знайдене
mostLikes.push({'name': aFan.name, 'thanked': [{'name': currUser.name, 'count': aFan.count}]}); //додаємо до масиву інформацію про те, хто, комі і скільки подяк поставив
console.log('most first: '+aFan.name+' : '+aFan.count);
}
}
}
try {
for (var i = 0; i < mostLikes.length; i++) {
mostLikes[i].thanked.sort(function(a, b) { //сортуємо подяки від конкретного юзера за спаданням
return b.count - a.count;
});
mostLikes[i]['total thanks'] = mostLikes[i].thanked.reduce(function(accum, val) { //підраховуємо загальну кількість подяк
return accum+val.count;
}, 0);
}
mostLikes.sort(function(a, b) { //сортуємо масив з юзерами, що поставили подяк за спаданням
return b['total thanks'] - a['total thanks'];
});
console.log('joining data...');
for(var i = 0; i < finishedData.length; i++) { //а тут ми просто додаємо в масив, що містить інфу про юзерів, але не містить інфи про те, скільки і кому подяк вони поставили, з масивом, котрий містить інфу про подяки
for(var j = 0; j < mostLikes.length; j++) {
if (finishedData[i].name === mostLikes[j].name) {
finishedData[i]['thanked'] = mostLikes[j]['thanked'].slice(0, 10); //обмежуємо список юзерів, кому поставили подяку до 10
finishedData[i]['total thanks'] = mostLikes[j]['total thanks'];
finishedData[i]['fans'] = finishedData[i]['fans'].slice(0, 10); //обмежуємо список юзверів, хто поставив подяку до 10
break;
}
}
}
} catch (err) {
console.log('error: '+error);
}
console.log('end of processing, saving data...');
fs.write('data.json', JSON.stringify(finishedData, null, ' '), 'w'); //записуємо дані в хвайл, дідько його б побрав, трясця його матері, задовбався то все розписувати!
phantom.exit();
}
/*
рекурсивно отримуємо дані про те, який юзер скільки подяк і від кого отримав
*/
function processUsers() {
function processUser(index, count) { //ось цей метод буде викликатись рекурсивно, через колбек, котрий буде викликатись в функції `counting` після того, як отримаємо всі записи з подяками, що отримав певний юзер
console.log('\nprocessing user, index: '+index+" count: "+count);
if (index == allUsers.length) { //якщо наступний індекс юзера виходить за межі масиву
console.log('saving data at start of processing a user');
countMostLiked(); //обраховуємо лайки, що поставили юзери
}
var currentUser = allUsers[index];
var userId = currentUser.userId;
page.open(thanksUrl+userId+'/page/1', function(status) { //завантажуємо сторінку з подяками, що отримав поточний юзер
console.log('status: '+status);
if(page.injectJs('jquery.js')) {
var number = page.evaluate(function() {
return parseInt($('.main-head .hn strong').text()); //отримуємо загальну кількість подяк, що отримав поточний юзер
});
fullArr=[]; //обнуляємо масив, котрий буде містити в собі все, окрім кількості лайків, котрий поточний юзер отримав
counting(thanksUrl+userId, number, 0, 1, function(thanks) { //отримуємо дані про подяки, що отримав юзер, в кінці буде викликана функція, котра передається останньою
console.log('callback has been called');
currentUser['fans'] = thanks; //додаємо до об'єкту, що представляє поточного юзера дані про подяки, котрі він отримав
finishedData.push(currentUser); //додаємо юзера з інфою про отримані подяки в кінцевий масив
console.log('recursive call of processUser');
processUser(++index, ++count); //запускаємо всю цю фігню, але вже для слідуючого юзера
});
}
});
}
processUser(0, 0);
}
/* КІНЕЦЬ ПІДРАХУНКУ ПОДЯК ВІД КОРИСТУВАЧІВ */
/* ОТРИМАННЯ ДАНИХ ПРО ВСІХ КОРИСТУВАЧІВ, КОТРІ ОТРИМАЛИ ХОЧА Б 1 ПОДЯКУ */
const usersUrl = 'http://replace.org.ua/users/-/-1/thanks/DESC/page/';
var allUsers = [];
function fetchUsers(baseUrl, pageNumber) {
var url = baseUrl+pageNumber;
console.log('loading: '+url);
page.open(url, function(status) {
console.log('status: '+status);
try {
if (page.injectJs('jquery.js')) {
console.log('jquery has been injected');
var arr = page.evaluate(function() {
console.log('hey it\'s evaluating!');
var arr = [];
var isEnd = false;
$('.ct-group tbody tr').each(function(index, el) {
var name = $(el).find('td:nth-child(1) span a').text();
var userId = /(\d+)/.exec($(el).find('td:nth-child(1) span a').attr('href'))[1];
var group = $(el).find('td:nth-child(2)').text();
var posts = parseInt($(el).find('td:nth-child(3)').text().replace(' ', ''));
var thanks = parseInt($(el).find('td:nth-child(4)').text().replace(' ', ''));
var date = $(el).find('td:nth-child(5)').text()
if (thanks > 0) {
arr.push({'name': name,
'userId': userId,
'group': group,
'posts': posts,
'thanks': thanks,
'date': date});
} else {
isEnd=true;
return false;
}
});
return [arr, isEnd];
});
allUsers = allUsers.concat(arr[0]);
if (arr[1]) {
processUsers();
} else {
fetchUsers(usersUrl, ++pageNumber);
}
}
} catch(e) {
console.log('error: '+e);
}
});
}
fetchUsers(usersUrl, 1)
/* КІНЕЦЬ ОТРИМАННЯ ДАНИХ ПРО ВСІХ КОРИСТУВАЧІВ, КОТРІ ОТРИМАЛИ ХОЧА Б 1 ПОДЯКУ */