1 Востаннє редагувалося FakiNyan (01.01.2018 19:44:28)

Тема: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Хай. Був захтів я підрахувати, хто поставив мені найбільше подяк, а хто менше.
Для цього потрібно перейти на сторінку подяк, пройтись по кожній з сторінок, та запам'ятовувати, скільки подяк добрі люде вже поставили, і хто саме їх ставив. Після чого потрібно просто порахувати, скільки подяк поставив конкретний подякувач, з того списку.
Для цього всього я вирішив юзати PhantomJs.

Для початку я скажу так, що сторінка з подяками на цьому хворумі досить таки глючна. Кількість подяк на сторінці починається з 25, і на кожній сторінці ця кількість ще зростає на 25, тобто, перша сторінка містить 25 подяк, друга - 50, третя - 75, і так далі.
При цьому лише перші 25 записів на кожній сторінці являються унікальними, далі йдуть записи з наступних сторінок.

Беручи то все до уваги я вирішив розробити ось такий мега алгоритм

1. Спочатку ми отримуємо кількість усіх подяк, це легко зробити на будь-які з сторінок з подяками, я просто завантажую першу сторінку і парсю з неї кількість тих подяк.
2. Далі нам необхідно почати завантажувати сторінки і додавати записи, при цьому потрібно додавати лише перші 25 записів
3. Коли всі унікальні записи з подяками в нашому кармані, то треба підрахувати кількість подяк, котрі був поставив кожен унікальний юзер зі списку всіх подяк, відсортувати ці дані і зберегти.

Кід з коментарями буде нижче, якщо щось не зрозуміло - питайте.

Запустити його мона тако:
1. Завантажте phantomjs
2. Створіть файлик з кодом нижче, наприклад, stats.js
3. Завантажте файлик з jQuery, назвіть його jquery.js (воно потрібне для парсення сторінки, з ним легче), та покладіть його разом з stats.js
4. Запускайте то все через командний рядок отако

phantomjs stats.js "посилання на сторінку з подяками"
Прихований текст
phantom.outputEncoding="cp1251"; // для української мови в консолі
console.log('hello'); // для перевірки, що воно взагалі працює

var system = require('system'); //для отримання аргументів з командного рядка
var startUrl = ''; //ініціалізуємо змінну, котра буде містити посилання

if (system.args.length === 1) { //коли немає аргументів (шлях до .js файлу рахується за аргумент)
  console.log('No arguments were passed in');
  phantom.exit(); //вихід з програми
} else {
  startUrl = system.args[1]; // присвоюємо аргумент змінній
}

console.log('got '+startUrl+' as argument'); //повідомляємо, що аргумент таки отримали

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 save() {
  try {
    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;
      });
      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(fullNumber, found, pageNumber) {
  console.log('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) { //якщо кількість записів в загальному масиві менша, ніж кількість подяк
        counting(fullNumber, fullArr.length, ++pageNumber); //запускаємо цю функцію заново, але з інкрементованим номером сторінки, аби завантажувати наступну сторінку
      } else
      {
        console.log('done, found: '+fullArr.length+"  last page: "+pageNumber);
        save(); // в інакшому разі, обробляємо та зберігаємо дані
        phantom.exit(); //виходимо
      }
    }
  });
}

/*
тут ми завантажуємо першу сторінку, і витягуємо з неї загальну кількість подяк
*/
page.open(startUrl, function(status) {
  console.log("status: "+status);
  try {
    if (page.injectJs('jquery.js')) {
      var number = page.evaluate(function() {
        return parseInt($('.main-head .hn strong').text());
      });

      counting(number, 0, 1); //запускаємо процес завантаження та парсення сторінок, number - кількість подяк, 0 - кількість подяк, котрі вже обробили, 1 - номер сторінки, з котрої починаємо завантажувати
    }
  } catch(e) {
    console.log('error: '+e);
  }
});
Подякували: 0xDADA11C7, 221VOLT, NaharD, /KIT\, Monolith, Altair88006

2

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

лінь розбиратись як воно працює)
втім, в якості оголошення кампанії направленої на боротьбу з власною лінню -
офіційно оголошую наступне -

виклик прийнято !

Подякували: FakiNyan, Monolith2

3

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

ліл, то додайте ще функціоналу, аби воно рахувало, кому і скільки певний юзер поставив подяк

Подякували: 221VOLT1

4

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Гм. Прогуляюся і напишу на Пітоні :)

Подякували: 221VOLT1

5

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

написав user.js,
тестував на greasemonkey 4.1, firefox developer edition 58.0b13 64-bit, linux Ubuntu 16.04.3 LTS

мої результати -

загалом мені подякували 83 людини :)
дякую і вам))

топ 7 =

Monolith = 219
leofun01 = 188
ostap34PHP = 146
0xDADA11C7 = 93
Betterthanyou = 73
bvn = 34
/KIT\\ = 30

Прихований текст
Прихований текст

думав спочатку писати на ерлангу, та полінився - і так на ньому роботу маю,
вирішив пригадати написання user.js
( заодно комусь пригодиться )

Подякували: Monolith, 0xDADA11C72

6

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

FakiNyan написав:

ліл, то додайте ще функціоналу, аби воно рахувало, кому і скільки певний юзер поставив подяк

:)  то простіше зробити з доступом до субд, на sql

Прихований текст

і в user.js я полінився наприкінці згрупувати-посортувати результат, мо хтось, менш лінивий, допише?))

Подякували: Monolith1

7 Востаннє редагувалося FakiNyan (01.01.2018 18:55:00)

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

221VOLT написав:

написав user.js,
тестував на greasemonkey 4.1, firefox developer edition 58.0b13 64-bit, linux Ubuntu 16.04.3 LTS

мої результати -

загалом мені подякували 83 людини :)
дякую і вам))

топ 7 =

Monolith = 219
leofun01 = 188
ostap34PHP = 146
0xDADA11C7 = 93
Betterthanyou = 73
bvn = 34
/KIT\\ = 30

Прихований текст
Прихований текст

думав спочатку писати на ерлангу, та полінився - і так на ньому роботу маю,
вирішив пригадати написання user.js
( заодно комусь пригодиться )

щось не сходиться
хтось з нас криво щось написав, давайте розберемося.

Файлик з подяками я прикріпив, також підрахував вручну загальну кількість подяк з файлу

363+146+119+94+64+48+36+36+25+23+14+12+12+11+11+10+10+7+6+6+6+4+4+4+4+4+3+2+2+2+2+2+2+1+1+1+1 = 1098
Post's attachments

data.txt 1.76 kb, 419 downloads since 2018-01-01 

8

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Коротше, не знаю, як ваше, але моє працює точно невірно. Записи повторюються вже на перших сторінках.
Я перевірив тільки що.
Спочатку йде 25 унікальних записів, на другій сторінці перші 25 записів є також унікальними, а наступні 25 являються першими 25 записами з наступної сторінки.

У пана koala - 4347 подяк. Ці подяки відображені на 174 сторінках.
25 * 174 = 4350.

Гадаю, це більш-менш підтверджує мою думку.
Виходить, що потрібно брати лише перші 25 записів з кожної сторінки.

Подякували: Monolith1

9

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

1098 === 1098

https://gist.github.com/221V/ac94efd97f … 3dc8d27253

все сходиться)

Подякували: Monolith1

10

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

То у вас показує лише по 25 подяк на сторінку? Бо після моїх останніх змін мої дані співпадають з вашими.

Прихований текст

https://cdn.discordapp.com/attachments/333936584481177600/397440248172380160/unknown.png

11 Востаннє редагувалося Monolith (02.01.2018 01:23:57)

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Ось написав скрипт на Python. Бачив, що ми тут про JS балакаємо, але типу створювати цілу тему заради одного скриптика гадаю занадто.

Ось код:

Прихований текст
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# @author Monolith
# @version 1.0
# @create 01.01.2018


import requests
from lxml import html
import time


user_id = 0 # ваш id на форумі
base_url = 'http://replace.org.ua/thanks/view/' + str(user_id) + '/page/%s'
path_name = '//tbody[1]/tr[%s]/td[1]/a'
path_date = '//tbody[1]/tr[%s]/td[3]'
count_of_pages = 0 # кількість сторінок з подяками

result = {}
date_array = []
count_of_gratitudes = 0;


start_time = time.time()


for page in range(1, count_of_pages+1):
    response = requests.get( base_url % page )
    if response.status_code == 200:
        parsed_body = html.fromstring(response.text)
        count_of_rows = len( parsed_body.xpath('//tbody[1]/tr') )
        for row in range(1, count_of_rows+1):
            date_res = parsed_body.xpath( path_date % row )
            date = date_res[0].text
            if date in date_array:
                pass
            else:
                date_array.append(date)
                count_of_gratitudes += 1
                name_res = parsed_body.xpath( path_name % row )
                name = name_res[0].text
                if name in result:
                    result[name] += 1
                else:
                    result[name] = 1


time_execute = round( time.time()-start_time, 1 )


file = open('result.txt', 'w')

file.write( html.fromstring(requests.get(base_url%1).text).xpath('//title/text()')[0] )
file.write( '\nКористувач має подяк: ' + str(count_of_gratitudes) )
file.write( '\nСкрипт виконано за: ' + str(time_execute) + 'сек\n' )

result_array = sorted( result.items(), key=lambda x: x[1], reverse=True )
c = 1
for couple in result_array:
    file.write( '\n' + str(c) + '. ' + couple[0] + ': ' + str(couple[1]) )
    c += 1

file.close()

Вся логіка у 18 рядках, все інше - чисто для "красоти" виводу. Ось у мене як вийшло:

Прихований текст

Мій ТОП10:
1. 221VOLT: 236
2. ostap34PHP: 140
3. 0xDADA11C7: 42
4. leofun01: 41
5. LoganRoss: 16
6. bvn: 15
7. /KIT\: 13
8. NagarD: 13
9. FakiNyan: 11
10. koala: 11

Цікаво до речі дізнатися про швидкодію. Мій скрипт у мене на компі та з моєю кількістю подяк виконується приблизно за 6.5 секунд.

Саму логіку нашкарябав за 20хв, увесь інший час парився, бо по-перше на форумі чомусь подяки дублюються на різних сторінках. По-друге, якщо не існує сторінки з подяками - показується перша. В мене наприклад їх 28, й якщо я запрошую 29-ту, то мені повертається 200 статус й показується перша сторінка. Тому це зменшує гнучкість скрипта (якщо будете у себе тестити, то не забудьте ще й кількість сторінок змінити).

Можливо хтось має критику щодо логіки. Я ще вчуся :)

На днях спробую написати на Erlang. Цікаво чи буде він швидший за Python (хоча це питання розтягнуте, я міг просто коряву логіку написати).

Подякували: 0xDADA11C7, 221VOLT, sensei, leofun014

12

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Моїх буде найменше :(
Немає звички тиснути лайкподяки, ні в соц мережах, ні тут.. навіть коли згоден з думкою автора поста. Але інколи таки ставлю "царський лайк" :D

Подякували: 0xDADA11C7, Monolith, 221VOLT3

13

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

тре було патентувати ідею...

14

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

не царське то діло - php вивчати  :D

Подякували: Monolith1

15

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Як бачите - царське :D

16

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

так я ще не цар  *SCRATCH*

17

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Monolith написав:

Саму логіку нашкарябав за 20хв, увесь інший час парився, бо по-перше на форумі чомусь подяки дублюються на різних сторінках.

Можна записувати окрему подяку в масив об'єктів, де зберігаються айдішка користувача й айдішка посту - тоді звіряючись з масивом можна відбирати лише унікальні записи.
Хоча тут у кожної подяки є час її проставлення, а вище описаний спосіб буде займати багато часу при великих об'ємах, краще буде зберігати масив дат - в такому пошук швидший за масив об'єктів.

Те, що унікальними є перші 25 записів, а потім ідуть дублікати, може згодом змінитись (скажімо, кількість дублів на кожнім сторінці буде рандомним) - ми ж не можемо знати як сторінки будуть виглядати потім, тому костиль "завжди беремо перші 25" в певний момент почне видавати хибну інформацію.

По-друге, якщо не існує сторінки з подяками - показується перша. В мене наприклад їх 28, й якщо я запрошую 29-ту, то мені повертається 200 статус й показується перша сторінка. Тому це зменшує гнучкість скрипта (якщо будете у себе тестити, то не забудьте ще й кількість сторінок змінити).

Можливо хтось має критику щодо логіки. Я ще вчуся :)

Так можна ж витягувати загальну кількість подяк, ділити їх на 25 і округляювати в більшу сторону - і у вас завжди буде обмеження на кількість сторінок, які треба зпарсити.

18

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Фуууух, дописав ото все для отримання статистики про те, хто скільки і кому подяк поставив, озьдо кід

Прихований текст
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 ПОДЯКУ */

А озьдо результати
https://gist.github.com/fncamm/7b8385fd … 38098597f1

Подякували: sensei, 221VOLT, 0xDADA11C7, leofun01, ostap34PHP5

19 Востаннє редагувалося FakiNyan (02.01.2018 23:34:24)

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

Наступне моє творіння буде дякувати певному юзеру за кожне повідомлення, котре ще не отримало подяку (всього за $4.99)  *OK* ех, погано, що не можна подякувати самому собі, були б free money

20

Re: Кількість отриманих подяк на replace.org.ua за допомогою PhantomJs 0.2

FakiNyan написав:

Фуууух, дописав ото все для отримання статистики про те, хто скільки і кому подяк поставив, озьдо кід

з однієї сторони - приємно бачити як хтось успішно навчається,
підкорює нові вершини))

з іншої сторони - так і хочеться покритикувати - у вас там зайвих 200+ строк ))

оптимальніше буде так --
1) беремо тих 50 строк, котрими рахували в одного юзера
2) йдемо на сторінку користувачів http://replace.org.ua/users/ , зберігаємо айдішки користувачів ( це ще 20-35 строк )
3) їздимо по айдішках http://replace.org.ua/thanks/view/5402/ , рахуємо
4) зробити красивий вивід результатів - для прикладу - посортувати і створити-видати html-сторінку на завантаження
( тут ще 5-10 строк )

загалом виходить приблизно 75-95 строчок коду, кожна з яких вміщається на екрані
мова про user.js , в ерлангу на обробку буде менше строк, більше - на парсинг html (хоча, тут знову ж таки - є варіанти)

Подякували: FakiNyan1