Кредит на изображение: Старый средний логотип
Medium имеет большой объем контента, большое количество пользователей и почти подавляющее количество сообщений. Когда вы пытаетесь найти интересных пользователей для взаимодействия, вас захлестывает визуальный шум.
Я определяю интересного пользователя как человека из вашей сети, который активен и пишет ответы, которые, как правило, ценятся средним сообществом.
Я просматривал последние сообщения от пользователей, за которыми я слежу, чтобы узнать, кто ответил этим пользователям. Я подумал, что если они ответили кому-то, за кем я слежу, у них должны быть те же интересы, что и у меня.
Процесс был утомительным. И именно тогда я вспомнил самый ценный урок, который я получил во время своей последней стажировки:
Любая утомительная задача может и должна быть автоматизирована.
Я хотел, чтобы моя автоматизация выполняла следующие действия:
- Получите все пользователи из моего списка “Подписчиков”
- Получите последние сообщения каждого пользователя
- Получите все ответы на каждый пост
- Отфильтруйте ответы, которые старше 30 дней
- Отфильтруйте ответы, содержащие меньше минимального количества рекомендаций
- Получите имя пользователя автора каждого ответа
Давайте начнем тыкать
Сначала я посмотрел на API Medium , но нашел его ограниченным. Это не давало мне много работы. Я мог получить информацию только о своей учетной записи, а не о других пользователях.
Кроме того, последнее изменение API Medium произошло более года назад. Не было никаких признаков недавнего развития событий.
Я понял, что мне придется полагаться на HTTP-запросы, чтобы получить свои данные, поэтому я начал копаться в своих Chrome DevTools .
Первой целью было получить мой список подписчиков.
Я открыл свои DevTools и перешел на вкладку “Сеть”. Я отфильтровал все, кроме XHR , чтобы посмотреть, откуда Medium получает мой список подписчиков. Я нажал кнопку перезагрузки на странице своего профиля и не получил ничего интересного.
Что делать, если я нажму кнопку “Ниже” в своем профиле? Бинго.
Поиск ссылки со списком подписчиков пользователя
Внутри ссылки я нашел очень большой ответ JSON . Это был хорошо отформатированный JSON, за исключением строки символов в начале ответа: ])}while(1);
Я написал функцию, чтобы очистить это и превратить JSON в словарь Python.
import json def clean_json_response(response): return json.loads(response.text.split('])}while(1);')[1])
Я нашел точку входа. Пусть начнется кодирование.
Получение всех пользователей из моего списка подписчиков
Чтобы запросить эту конечную точку, мне нужен был мой идентификатор пользователя (я знаю, что он у меня уже был, но это для образовательных целей).
Ища способ получить идентификатор пользователя, я узнал , что вы можете добавить ?format=json
для большинства средних URL-адресов, чтобы получить ответ JSON с этой страницы. Я попробовал это на своей странице профиля.
О, смотрите, вот идентификатор пользователя.
])}while(1);{"success":true,"payload":{"user": {"userId":"d540942266d0","name":"Radu Raicea","username":"Radu_Raicea",...
Я написал функцию для извлечения идентификатора пользователя из данного имени пользователя. Опять же, мне пришлось использовать clean_json_response
, чтобы удалить нежелательные символы в начале ответа.
Я также создал константу под названием MEDIUM
, которая содержит базу для всех URL-адресов Medium.
import requests MEDIUM = 'https://medium.com' def get_user_id(username): print('Retrieving user ID...') url = MEDIUM + '/@' + username + '?format=json' response = requests.get(url) response_dict = clean_json_response(response) return response_dict['payload']['user']['userId']
С помощью идентификатора пользователя я запросил конечную точку /_/api/users//following
и получил список имен пользователей из моего списка подписчиков.
Когда я сделал это в DevTools, я заметил, что в ответе JSON было только восемь имен пользователей. Странный.
После того, как я нажал на кнопку “Показать больше людей”, я увидел, чего не хватает. Средний использует разбиение на страницы для списка следующих.
Среда использует разбиение на страницы для следующего списка
Разбиение на страницы выполняется путем указания limit
(элементы на странице) и to
(первый элемент следующей страницы). Я должен был найти способ получить идентификатор этого следующего элемента.
В конце ответа JSON от /_/api/users//, следующего за
, виден интересный ключ.
..."paging":{"path":"/_/api/users/d540942266d0/followers","next": {"limit":8,"to":"49260b62a26c"}}},"v":3,"b":"31039-15ed0e5"}
Отсюда было легко написать цикл, чтобы получить все имена пользователей из моего списка подписчиков.
def get_list_of_followings(user_id): print('Retrieving users from Followings...') next_id = False followings = [] while True: if next_id: # If this is not the first page of the followings list url = MEDIUM + '/_/api/users/' + user_id + '/following?limit=8&to=' + next_id else: # If this is the first page of the followings list url = MEDIUM + '/_/api/users/' + user_id + '/following' response = requests.get(url) response_dict = clean_json_response(response) payload = response_dict['payload'] for user in payload['value']: followings.append(user['username']) try: # If the "to" key is missing, we've reached the end # of the list and an exception is thrown next_id = payload['paging']['next']['to'] except: break return followings
Получение последних сообщений от каждого пользователя
Как только у меня появился список пользователей, за которыми я слежу, я захотел получить их последние сообщения. Я мог бы сделать это с просьбой https://medium.com/@<имя пользователя>/последнее?формат=json
Я написал функцию, которая берет список имен пользователей и возвращает список идентификаторов записей для последних записей из всех имен пользователей во входном списке.
def get_list_of_latest_posts_ids(usernames): print('Retrieving the latest posts...') post_ids = [] for username in usernames: url = MEDIUM + '/@' + username + '/latest?format=json' response = requests.get(url) response_dict = clean_json_response(response) try: posts = response_dict['payload']['references']['Post'] except: posts = [] if posts: for key in posts.keys(): post_ids.append(posts[key]['id']) return post_ids
Получение всех ответов с каждого поста
Со списком сообщений я извлек все ответы, используя https://medium.com/_/api/posts//ответы
Эта функция принимает список идентификаторов сообщений и возвращает список ответов.
def get_post_responses(posts): print('Retrieving the post responses...') responses = [] for post in posts: url = MEDIUM + '/_/api/posts/' + post + '/responses' response = requests.get(url) response_dict = clean_json_response(response) responses += response_dict['payload']['value'] return responses
Фильтрация ответов
Сначала я хотел получить ответы, которые получили минимальное количество хлопков. Но я понял, что это, возможно, не очень хорошо отражает оценку сообществом ответа: пользователь может дать более одного хлопка за одну и ту же статью.
Вместо этого я отфильтровал по количеству рекомендаций. Он измеряет то же самое, что и хлопки, но не учитывает дубликаты.
Я хотел, чтобы минимум был динамическим, поэтому я передал переменную с именем recommend_min
.
Следующая функция принимает ответ и переменную recommend_min
. Он проверяет, соответствует ли ответ этому минимуму.
def check_if_high_recommends(response, recommend_min): if response['virtuals']['recommends'] >= recommend_min: return True
Я также хотел получить последние ответы. Я отфильтровал ответы, которые были старше 30 дней, используя эту функцию.
from datetime import datetime, timedelta def check_if_recent(response): limit_date = datetime.now() - timedelta(days=30) creation_epoch_time = response['createdAt'] / 1000 creation_date = datetime.fromtimestamp(creation_epoch_time) if creation_date >= limit_date: return True
Получение имени пользователя автора каждого ответа
Как только у меня были все отфильтрованные ответы, я захватил все идентификаторы пользователей авторов, используя следующую функцию.
def get_user_ids_from_responses(responses, recommend_min): print('Retrieving user IDs from the responses...') user_ids = [] for response in responses: recent = check_if_recent(response) high = check_if_high_recommends(response, recommend_min) if recent and high: user_ids.append(response['creatorId']) return user_ids
Идентификаторы пользователей бесполезны, когда вы пытаетесь получить доступ к чьему-то профилю. Я сделал эту следующую функцию запросом к конечной точке /_/api/users/
, чтобы получить имена пользователей.
def get_usernames(user_ids): print('Retrieving usernames of interesting users...') usernames = [] for user_id in user_ids: url = MEDIUM + '/_/api/users/' + user_id response = requests.get(url) response_dict = clean_json_response(response) payload = response_dict['payload'] usernames.append(payload['value']['username']) return usernames
Складывая все это вместе
После того, как я закончил все функции, я создал конвейер , чтобы получить список рекомендуемых пользователей.
def get_interesting_users(username, recommend_min): print('Looking for interesting users for %s...' % username) user_id = get_user_id(username) usernames = get_list_of_followings(user_id) posts = get_list_of_latest_posts_ids(usernames) responses = get_post_responses(posts) users = get_user_ids_from_responses(responses, recommend_min) return get_usernames(users)
Наконец-то сценарий был готов! Чтобы запустить его, вы должны вызвать конвейер.
interesting_users = get_interesting_users('Radu_Raicea', 10) print(interesting_users)
Кредит на изображение: Знай Свой Мем
Наконец, я добавил возможность добавления результатов в CSV с меткой времени.
import csv def list_to_csv(interesting_users_list): with open('recommended_users.csv', 'a') as file: writer = csv.writer(file) now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') interesting_users_list.insert(0, now) writer.writerow(interesting_users_list) interesting_users = get_interesting_users('Radu_Raicea', 10) list_to_csv(interesting_users)
Исходный код проекта находится на GitHub .
Если вы не знаете Python, перейдите к чтению TK ‘s Изучение Python: от нуля до героя .
Если у вас есть предложения по другим критериям, которые делают пользователей интересными, пожалуйста, напишите их ниже!
Вкратце…
- Я сделал скрипт Python для Medium .
- Скрипт возвращает список интересных пользователей, которые активны и публикуют интересные ответы на последние сообщения людей, за которыми вы следите.
- Вы можете выбрать пользователей из списка и запустить скрипт с их именем пользователя вместо вашего.
Ознакомьтесь с моим |/праймером о лицензиях с открытым исходным кодом и о том, как добавлять их в свои проекты!
Оригинальный пост на |/Medium |/.
Для получения дополнительных обновлений следуйте за мной в Twitter .