Сделал инструмент статистического анализа для Nuggets.

задняя часть
Сделал инструмент статистического анализа для Nuggets.

Эта статья участвовала в приказе о созыве Haowen, нажмите, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!

Взгляните на результаты

Данные на 1 июля в качестве примера

1 июля 10 лучших по общему количеству лайков

Пользователь Всего лайков
Наггетс Энтони 234
chokcoco 185
Рука разрывает красное и черное дерево 148
Хай Йонг 114
Программист Сяоцзе 104
спутник луны летучая рыба 103
LBJ 100
Фронт-энд команда Сямэнь 92
островной фермер 89
облачный мир 80

1 июля Топ-10 по общему времени просмотра

Пользователь общий просмотр
Рука разрывает красное и черное дерево 6037
chokcoco 5689
Луожу 5495
Маленький Y, который набрал код 5254
Форум разработчиков Huawei 4829
Наггетс Энтони 4445
мой старый Лю 3967
Хай Йонг 3784
alphardex 3459
Фронт-энд команда Сямэнь 3448

1 июля Топ-10 лайков за один период времени

Пользователь период Понравилось
спутник луны летучая рыба 07-01 00:41 - 07-01 00:46 45
Программист Сяоцзе 07-01 09:59 - 07-01 10:04 37
Красная пыль очищает сердце 07-01 21:42 - 07-01 21:47 27
LBJ 07-01 21:32 - 07-01 21:37 26
Толстый Д.А. 07-01 17:41 - 07-01 17:46 20
Небольшая деревня 07-01 01:31 - 07-01 01:36 17
островной фермер 07-01 08:43 - 07-01 08:49 15
Сяолэй 07-01 22:07 - 07-01 22:12 13
очищаю мою оболочку 07-01 17:31 - 07-01 17:36 10
мой старый Лю 07-01 19:01 - 07-01 19:06 10

1 июля Просмотрите 10 лучших за один период времени

Пользователь период просмотрел
Форум разработчиков Huawei 07-01 11:14 - 07-01 11:19 874
Рыболовный эксперт 07-01 15:25 - 07-01 20:52 210
Honest1y 07-01 16:45 - 07-01 16:50 157
mPaaS 07-01 11:44 - 07-01 20:06 103
мой старый Лю 07-01 13:15 - 07-01 13:20 101
Луожу 07-01 09:44 - 07-01 09:49 89
chokcoco 07-01 13:47 - 07-01 13:55 89
Рука разрывает красное и черное дерево 07-01 09:34 - 07-01 09:39 89
alphardex 07-01 10:24 - 07-01 10:29 85
Программист, который любит возиться 07-01 11:29 - 07-01 11:34 84

Являются ли данные точными? A: Очень точнымиimage.pngimage.png

Вам интересно, как это сделать?

Начало

  1. Отслеживайте авторов, извлекайте данные, где найти авторов, вот рейтинг авторов,
    • Недостатком является то, что некоторые авторы, которых нет в списке, будут потеряны.

image.png

  1. посвятить данные

    • Мы видим, что категорий много, поэтому давайте сначала возьмем категорию.
    • Это мало что объяснит, посмотрите на кодimage.png
        private static List<Category> getAllCategory() {
            String res = Http.get("https://api.juejin.cn/tag_api/v1/query_category_briefs?show_type=1");
            //取到所以标签
            JSONArray data = JSONUtil.parseObj(res).getJSONArray("data");
            return JSONUtil.toList(data, Category.class);
        }
    
        //用的是内部类
        static class Category implements Serializable {
    
            private String category_id;
            private String category_name;
            private String category_url;
    
            //省略get set 方法
        }
    
    
    • вытащить всех авторов

    image.png

    public static void run() {
        System.out.println("拉取分类");
        List<Category> categoryList = getAllCategory();
        while (true) {
            String now = LocalDateTime.now().format(dateFormat);
            HashMap<String, Author> authorHashMap = new HashMap<>();
    
            System.out.println("开始拉取数据:" + now);
    
    //      获取所以作者
            for (Category category : categoryList) {
                try {
                    List<Author> authorList = getAllAuthor(category);
                    for (Author author : authorList) {
                        author.setTime(now);
                        authorHashMap.put(author.getUser_id(), author);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            //保存数据 authorHashMap
            //这里使用的是追加到文件末尾,不然内存不够
            try {
                String path = "./j-" + LocalDate.now().format(dayFormat) + ".json";
                initFile(path);
                FileWriter fw = new FileWriter(path, true);
                PrintWriter pw = new PrintWriter(fw);
                pw.println(JSONUtil.toJsonStr(MapUtil.of(now, authorHashMap.values())));  //字符串末尾不需要换行符
                pw.close();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
               
            //等待一会继续拉取
            System.out.println("拉取数据结束:" + now);
            try {
                Thread.sleep(pullTime * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    //获取所有作者
    private static String getUrl(String categoryId) {
        return "https://api.juejin.cn/user_api/v1/author/recommend?category_id=" + categoryId + "&cursor=0&limit=100";
    }
    private static List<Author> getAllAuthor(Category category) {
        try {
            String res = Http.get(getUrl(category.getCategory_id()));
            JSONArray data = JSONUtil.parseObj(res).getJSONArray("data");
            return JSONUtil.toList(data, Author.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }
    
    static class Author implements Serializable {
        private String user_id;
        private String user_name;
        private String got_digg_count;
        private String got_view_count;
        private String avatar_large;
        private String company;
        private String job_title;
        private String level;
        private String description;
        private String author_desc;
        private String time;
    
        //get set 。。。。。。
    }
    
    
    • Получение данных завершено

анализировать данные

Разбор тут scala, java слишком безвкусный и неудобный

Данные за один день составляют около 60М, а результаты получаются за секунды

  • Первым шагом является чтение файла данных
    val map: mutable.Map[String, List[Author]] = mutable.ListMap()

    def load(): Unit = {
        val lineList = new util.ArrayList[String]()
        IoUtil.readLines(new FileInputStream("./j-20210630.json"), StandardCharsets.UTF_8, lineList)
        lineList.forEach(line => {
            val type1: Type = new TypeReference[util.Map[String, util.List[Author]]] {}.getType
            val bean: util.Map[String, util.List[Author]] = JSONUtil.toBean(line, type1, true)
            bean.asScala.foreach(entry => map.put(entry._1, entry._2.asScala.toList))
        })
    }
  • Больше данных для анализа потребностей
    // 有很多地方可以优化,懒得搞,反正数据很小
    def main(args: Array[String]): Unit = {
        // 加载数据 就是上面的方法
        load()
        //1.获取所有value(每个时间段,所有作者)
        //2.扁平化
        //3.更具用户分组
        //4.每个用户的所以数据,更具时间排序
        //5.计算数据
        val map1 = map.values.flatten.groupBy(_.getUser_id).map(m => {
            (m._1, m._2.toList.sortBy(_.getTime))
        }).map(m => {
            val value: List[Author] = m._2
            //求出 总点赞数和总浏览数
            val day_got_digg_count = value.last.getGot_digg_count.toInt - value.head.getGot_digg_count.toInt
            val day_got_view_count = value.last.getGot_view_count.toInt - value.head.getGot_view_count.toInt
            //求出 获赞和获浏览数最多的 时间段
            var max_got_digg_count = 0;
            var max_got_digg_count_time = ""
            value.sliding(2, 2).foreach(l => {
                val head = l.head
                val last = l.last
                val value1 = last.getGot_digg_count.toInt - head.getGot_digg_count.toInt
                if (value1 > max_got_digg_count) {
                    max_got_digg_count = value1
                    max_got_digg_count_time = s"${getOutTime(head.getTime)} - ${getOutTime(last.getTime)}"
                }
            })
            var max_got_view_count = 0
            var max_got_view_count_time = ""
            value.sliding(2, 2).foreach(l => {
                val head = l.head
                val last = l.last
                val value1 = last.getGot_view_count.toInt - head.getGot_view_count.toInt
                if (value1 > max_got_view_count) {
                    max_got_view_count = value1
                    max_got_view_count_time = s"${getOutTime(head.getTime)} - ${getOutTime(last.getTime)}"
                }
            })
            //包装结果
            val head = value.head
            (m._1, Map(
                "user_name" -> head.getUser_name,
                "user_id" -> head.getUser_id,
                "day_got_digg_count" -> day_got_digg_count,
                "day_got_view_count" -> day_got_view_count,
                "max_got_digg_count" -> max_got_digg_count,
                "max_got_digg_count_time" -> max_got_digg_count_time,
                "max_got_view_count" -> max_got_view_count,
                "max_got_view_count_time" -> max_got_view_count_time,
            ))
        })
        
        //这里是,拿到所有结果,按需求倒排,然后取出 Top10
        
        println("\n-----------------当天总获赞Top10------------------")
        printf("|%-12s\t|%-5s|\n", "用户", "总获赞")
        printf("|%-12s\t|%-5s|\n", "-" * 12, "-" * 5)
        map1.values.toList.sortBy(value => value("day_got_digg_count").asInstanceOf[Int])(Ordering.Int.reverse).take(10).foreach(value => {
            printf("|%-12s\t|%-5s|\n", value("user_name"), value("day_got_digg_count"))
        })

        println("\n-----------------当天总浏览Top10------------------")
        printf("|%-12s\t|%-5s|\n", "用户", "总浏览")
        printf("|%-12s\t|%-5s|\n", "-" * 12, "-" * 5)
        map1.values.toList.sortBy(value => value("day_got_view_count").asInstanceOf[Int])(Ordering.Int.reverse).take(10).foreach(value => {
            printf("|%-12s\t|%-5s|\n", value("user_name"), value("day_got_view_count"))
        })

        println("\n-----------------当天单时间段获赞Top10------------------")
        printf("|%-12s\t|%-25s\t|%-5s|\n", "用户", "时间段", "获赞")
        printf("|%-12s\t|%-25s\t|%-5s|\n", "-" * 12, "-" * 25, "-" * 5)
        map1.values.toList.sortBy(value => value("max_got_digg_count").asInstanceOf[Int])(Ordering.Int.reverse).take(10).foreach(value => {
            printf("|%-12s\t|%-25s\t|%-5s|\n", value("user_name"), value("max_got_digg_count_time"), value("max_got_digg_count"))
        })

        println("\n-----------------当天单时间段浏览Top10------------------")
        printf("|%-12s\t|%-25s\t|%-5s|\n", "用户", "时间段", "获浏览")
        printf("|%-12s\t|%-25s\t|%-5s|\n", "-" * 12, "-" * 25, "-" * 5)
        map1.values.toList.sortBy(value => value("max_got_view_count").asInstanceOf[Int])(Ordering.Int.reverse).take(10).foreach(value => {
            printf("|%-12s\t|%-25s\t|%-5s|\n", value("user_name"), value("max_got_view_count_time"), value("max_got_view_count"))
        })
    }

окончательный эффект

image.png

Если вам интересно, вы можете обсудить и обсудить вместе 🥰 Добро пожаловать к большим парням

Если вы хотите быть дисплеем в реальном времени, есть фронтенд-боссы, которые хотят помочь, добро пожаловать DD