Вступление
Добро пожаловать в последний эпизод нашей серии Twitter API . В нашем последнем эпизоде я создал Twixxr.com, который позволит вам обнаружить влиятельных женщин в Твиттере для вашей учетной записи. Сегодня я собираюсь обратить внимание на своих последователей.
Хотя я не пользовался Facebook с 2013 года , я оставался активным в Твиттере — даже несмотря на то, что они загружали мой канал рекламой и раздражали меня, пытаясь алгоритмически оптимизировать его.
Недавно я был проверен и начал собирать подписчиков чуть быстрее. Я надеялся, что смогу увидеть больше ответов на мои твиты. Вообще, я был удивлен тем, как мало людей обычно получают отклик в Твиттере.
У меня почти 1900 подписчиков, но редко люди комментируют или ретвитят фрагменты, которые, на мой взгляд, важны и представляют общий интерес. Например, ни один человек не поделился моей статьей о резком всплеске сообщений об изнасилованиях в Сиэтле или комментариев о Билле Гейтсе в его наиболее вопиющей лицемерности .
В течение долгого времени я хотел более внимательно посмотреть на своих подписчиков в Твиттере и ответить на несколько вопросов: кто именно следит за мной? И почему они не более интерактивны? Возможно ли, что только 10% моих последователей являются настоящими людьми?
У Twitter проблемы с поиском покупателя, и, возможно, это как-то связано с этим.
API Twitter — хороший инструмент для исследования этого. Тем не менее, он имеет множество ограничений скорости, которые делают даже что-то простое, например, анализ ваших подписчиков, довольно сложным. В сегодняшнем эпизоде я покажу вам, как я работал с ограничениями скорости, чтобы оценить и построить табло моих подписчиков.
Если у вас есть какие-либо вопросы или комментарии, пожалуйста, оставьте их ниже в комментариях или свяжитесь со мной в Twitter @reifman .
Проанализируйте наших последователей в Твиттере
Чуть выше вы можете увидеть базовое табло, которое я создал. Сегодняшний эпизод будет посвящен в основном инфраструктуре и подходу, который я выбрал для создания этого. Я надеюсь, что у меня будет возможность написать больше об улучшении механизма оценки.
И да, как вы можете видеть выше, известный лидер прав геев и комментатор по сексуальным советам Дэн Сэвидж следует за мной, но никогда не ретвитит то, что я разделяю. Если сегодня будет время, мы проанализируем это, чтобы ответить на такие важные вопросы, как: он настоящий, бот или просто следует за мной за советом по поводу секса? Что мы можем узнать из его аккаунта, чтобы определить, будет ли он когда-либо взаимодействовать со мной в Твиттере или, если уж на то пошло, с кем-либо из моих последователей?
Код на табло — это, в основном, прототип, который я построил поверх кода Twixxr из последнего эпизода, но это не живая демонстрация для людей. Я делюсь, чтобы вы могли учиться на этом и строить на нем самостоятельно.
Вот основные элементы кода:
- Создание базы данных для хранения моих подписчиков и связанных с ними данных.
- Загрузка моих подписчиков на страницах по 20 подписчиков каждая.
- Отслеживание курсоров для страниц, когда я загружаю 15 страниц в окне с ограниченной скоростью.
- Хранение собранных данных о моих подписчиках в базе данных.
- Построение алгоритма оценки прототипа для оценки всех последователей.
- Построение представления для просмотра табло.
Погружение в кодекс
Создание таблиц базы данных Миграции
Я создал три разных таблицы, чтобы хранить все данные и помогать мне работать с ограничением скорости Twitter API. Если вы не знакомы с миграциями баз данных Yii, см. Раздел «Как программировать с помощью Yii2: работа с базой данных и активной записью» .
Во-первых, я расширил таблицу SocialProfile, чтобы записать намного больше данных из учетных записей подписчиков, например, были ли они проверены, их местоположение и сколько объектов они выбрали:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<?php
use yii\db\Schema;
use yii\db\Migration;
class m161026_221130_extend_social_profile_table extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === ‘mysql’) {
$tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
}
$this->addColumn(‘{{%social_profile}}’,’social_id’,Schema::TYPE_STRING.’ NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’name’,’string NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’screen_name’,Schema::TYPE_STRING.’ NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’description’,Schema::TYPE_TEXT.’ NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’url’,Schema::TYPE_STRING.’ NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’protected’,Schema::TYPE_SMALLINT. ‘ NOT NULL DEFAULT 0’);
$this->addColumn(‘{{%social_profile}}’,’favourites_count’,Schema::TYPE_BIGINT. ‘ NOT NULL DEFAULT 0’);
$this->addColumn(‘{{%social_profile}}’,’verified’,Schema::TYPE_SMALLINT. ‘ NOT NULL DEFAULT 0’);
$this->addColumn(‘{{%social_profile}}’,’location’,Schema::TYPE_STRING.’ NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’profile_location’,Schema::TYPE_STRING.’ NOT NULL’);
$this->addColumn(‘{{%social_profile}}’,’score’,Schema::TYPE_BIGINT. ‘ NOT NULL DEFAULT 0’);
}
|
Затем я создал таблицу индексации SocialFriend
для отслеживания подписчиков для определенных учетных записей. Если я решу официально оформить эту услугу, она мне понадобится. Он связывает таблицу User с подписчиками пользователя в таблице SocialProfile.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
<?php
use yii\db\Schema;
use yii\db\Migration;
class m161026_233916_create_social_friend_table extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === ‘mysql’) {
$tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
}
$this->createTable(‘{{%social_friend}}’, [
‘id’ => Schema::TYPE_PK,
‘user_id’ => Schema::TYPE_BIGINT.’
‘social_profile_id’ => Schema::TYPE_BIGINT.’
], $tableOptions);
}
|
Далее, API Twitter требует, чтобы вы просматривали запросы 20 подписчиков одновременно. Чтобы узнать следующую страницу, вы должны отслеживать курсоры, в основном теги, которые отмечают следующую страницу для извлечения.
Поскольку вам разрешено делать только 15 запросов на подписчиков каждые 15 минут, вы должны хранить эти курсоры в базе данных. Таблица называется SocialCursor
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
<?php
use yii\db\Schema;
use yii\db\Migration;
class m161027_001026_social_cursor_table extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === ‘mysql’) {
$tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
}
$this->createTable(‘{{%social_cursor}}’, [
‘id’ => Schema::TYPE_PK,
‘user_id’ => Schema::TYPE_BIGINT.’
‘next_cursor’ => Schema::TYPE_STRING.’
], $tableOptions);
}
|
В конце концов, я буду создавать фоновые задачи cron для управления всем этим, но для сегодняшнего прототипа я запускаю эти задачи вручную.
Сбор подписчиков и их учетных данных
Затем я создал метод Twitter::getFollowers()
для выполнения запроса. Вот основы кода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public function getFollowers($user_id) {
$sp = new SocialProfile();
$next_cursor = SocialCursor::getCursor($user_id);
…
while ($next_cursor>0) {
$followers = $this->connection->get(«followers/list»,[‘cursor’=>$next_cursor]);
if ($this->connection->getLastHttpCode() != 200) {
var_dump($this->connection);
exit;
}
if (isset($followers->users)) {
foreach ($followers->users as $u) {
$n+=1;
$users[]=$u;
$sp->add($user_id,$u);
}
$next_cursor= $followers->next_cursor;
SocialCursor::refreshCursor($user_id,$next_cursor);
echo $next_cursor.'<br />’;
echo ‘======================================================<br />’;
} else {
exit;
}
}
|
Он получает next_cursor
и неоднократно запрашивает последователей , $followers = $this->connection->get("followers/list",['cursor'=>$next_cursor])
, пока не достигнет ограничения скорости.
Вывод выглядит примерно так, как он проходит через каждую страницу из 20 результатов:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
refresh cursor: 1489380833827620370
======================================================
refresh cursor: 1488086367811119559
======================================================
refresh cursor: 1486452899268510188
======================================================
refresh cursor: 1485593015909209633
======================================================
refresh cursor: 1485330282069552137
======================================================
refresh cursor: 1485256983607000799
======================================================
refresh cursor: 1484594012550322889
======================================================
refresh cursor: 1483359799854574028
======================================================
refresh cursor: 1481615590678791493
======================================================
refresh cursor: 1478424827838161031
======================================================
refresh cursor: 1477449626282716582
======================================================
refresh cursor: 1475751176809638917
======================================================
refresh cursor: 1473539961706830585
======================================================
refresh cursor: 1471375035531579849
======================================================
|
Данные сохраняются этими $sp->add($user_id,$u);
методы. Метод SocialProfile::add()
является другой версией метода fill()
из учебника Twixxr. Он хранит больше данных и управляет индексом SocialFriend:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
public static function add($user_id,$profileObject=null) {
$sp = SocialProfile::find()
->where([‘social_id’=>$profileObject->id_str])
->one();
if (!isset($profileObject->name) || empty($profileObject->name)) {
$profileObject->name=’Nameless’;
}
if (!isset($profileObject->url) || empty($profileObject->url)) {
$profileObject->url=»;
}
if (!isset($profileObject->screen_name) || empty($profileObject->screen_name)) {
$profileObject->screen_name=’error_sn’;
}
if (!isset($profileObject->description) || empty($profileObject->description)) {
$profileObject->description='(empty)’;
}
if (!isset($profileObject->profile_location) || empty($profileObject->profile_location)) {
$profileObject->profile_location=»;
}
if (!isset($profileObject->profile_image_url_https) || empty($profileObject->profile_image_url_https)) {
$profileObject->profile_image_url_https=»;
}
if (!is_null($sp)) {
$sp->social_id = $profileObject->id;
$sp->image_url = $profileObject->profile_image_url_https;
$sp->follower_count= $profileObject->followers_count;
$sp->status_count = $profileObject->statuses_count;
$sp->friend_count = $profileObject->friends_count;
$sp->listed_in = $profileObject->listed_count;
$sp->url=$profileObject->url;
if ($profileObject->protected) {
$sp->protected=1;
} else {
$sp->protected=0;
}
if ($profileObject->verified) {
$sp->verified=1;
} else {
$sp->verified=0;
}
$sp->favourites_count=$profileObject->favourites_count;
$sp->location=$profileObject->location;
$sp->profile_location=$profileObject->profile_location;
$sp->name = $profileObject->name;
$sp->description = $profileObject->description;
$sp->image_url = $profileObject->profile_image_url_https;
if ($sp->validate()) {
$sp->update();
} else {
var_dump($sp->getErrors());
}
} else {
$sp = new SocialProfile();
$sp->social_id = $profileObject->id;
$sp->score = 0;
$sp->header_url=»;
$sp->url=$profileObject->url;
$sp->favourites_count=$profileObject->favourites_count;
if ($profileObject->protected) {
$sp->protected=1;
} else {
$sp->protected=0;
}
if ($profileObject->verified) {
$sp->verified=1;
} else {
$sp->verified=0;
} $sp->location=$profileObject->location;
$sp->profile_location=$profileObject->profile_location;
$sp->name = $profileObject->name;
$sp->description = $profileObject->description;
$sp->screen_name = $profileObject->screen_name;
$sp->image_url = $profileObject->profile_image_url_https;
$sp->follower_count= $profileObject->followers_count;
$sp->status_count = $profileObject->statuses_count;
$sp->friend_count = $profileObject->friends_count;
$sp->listed_in = $profileObject->listed_count;
if ($sp->validate()) {
$sp->save();
} else {
var_dump($sp->getErrors());
}
}
$sf = SocialFriend::find()
->where([‘social_profile_id’=>$sp->id])
->andWhere([‘user_id’=>$user_id])
->one();
if (is_null($sf)) {
$sf = new SocialFriend();
$sf->user_id = $user_id;
$sf->social_profile_id = $sp->id;
$sf->save();
}
return $sp->id;
}
|
Он написан для сохранения новых записей или обновления старых записей, чтобы в будущем вы могли отслеживать данные подписчика и регулярно обновлять его, перезаписывая старые данные.
Этот последний раздел в конце обеспечивает наличие индекса SocialFriend между таблицей User и таблицей SocialProfile.
01
02
03
04
05
06
07
08
09
10
|
$sf = SocialFriend::find()
->where([‘social_profile_id’=>$sp->id])
->andWhere([‘user_id’=>$user_id])
->one();
if (is_null($sf)) {
$sf = new SocialFriend();
$sf->user_id = $user_id;
$sf->social_profile_id = $sp->id;
$sf->save();
}
|
Подсчет очков в Твиттере
У меня было несколько голов для оценки в Твиттере:
- Удалите аккаунты, которые следуют за всеми, кто за ними следует Например, у них есть 12 548 подписчиков и подписаны на 12 392 человека (см. Выше).
- Удалите учетные записи после более чем 1500 учетных записей, которые вряд ли когда-либо увидят то, чем я делюсь. Например, Дэн Сэвидж следует 1536 человек.
- Удалите аккаунты, у которых очень мало постов или очень мало аккаунтов, за которыми они следуют, вероятно, заброшенные аккаунты
- Удалите учетные записи с помощью нескольких избранных — это скорее всего боты, которые на самом деле не используют приложение.
Точно так же я хотел бы выделить некоторые положительные моменты:
- Счета, которые проверены
- Аккаунты с большим количеством подписчиков
- Аккаунты, на которых подписаны менее 1000 человек — приятное место для меня
Вот примерный базовый код из SocialProfile::score()
который выделяет некоторые из положительных моментов:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
foreach ($all as $sp) {
// score sp
$score =0;
// RULE IN
if ($sp->verified==1) {
$score+=1000;
}
// POSITIVE
if ($sp->protected==1) {
$score+=500;
}
if ($sp->follower_count > 10000) {
$score+=500;
} else if ($sp->follower_count > 3500) {
$score+=750;
} else if ($sp->follower_count > 1100) {
$score+=1000;
} else if ($sp->follower_count > 1000) {
$score+=250;
} else if ($sp->follower_count> 500) {
$score+=250;
}
|
Вот некоторый код, который устраняет некоторые плохие учетные записи:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// RULE OUT
// make this a percentage of magnitude
$magnitude = $sp->follower_count/1000;
if ($sp->follower_count> 1000 and abs($sp->follower_count-$sp->friend_count)<$magnitude) {
$score-=2500;
}
if ($sp->friend_count > 7500) {
$score-=10000;
} else
if ($sp->friend_count > 5000) {
$score-=5000;
}
else if ($sp->friend_count > 2500) {
$score-=2500;
}else if ($sp->friend_count > 2000) {
$score-=2000;
} else if ($sp->friend_count > 1000) {
$score-=250;
} else if ($sp->friend_count > 750) {
$score-=100;
}
if ($sp->follower_count<100) {
$score-=1000;
}
if ($sp->status_count < 35) {
$score-=5000;
}
|
Очевидно, здесь есть над чем поиграть, и есть множество способов улучшить это. Я надеюсь, что у меня будет возможность потратить больше времени на это.
Когда метод запускается, он выглядит следующим образом, но обновляет таблицу SocialProfile с оценками:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
DJMany -6300
gai_ltau -7850
Michal92B -900
InvestmentAdvsr -2900
TSSStweets -7500
sandcageapp -1750
dominicpouzin 1950
daletdykaaolch1 -7850
suzamack -8250
writingthrulife -7500
ryvr -1550
RichardAngwin -8300
DanielleMorrill -7300
ReversaCreates 2750
BoKnowsMarkting -7500
TheHMProA -8500
HouseMgmt101 750
itsmeKennethG -1250
drbobbiwegner -8500
Mizzfit_Bianca -7300
wilsonmar 700
CoachVibeke -7300
jhurwitz 0
PiedPiperComms 500
Prana2thePeople -1100
singlemomspower -2250
mouselink -7300
MotivatedGenY -7300
brett7three -7300
JovanWalker 2950
ITSPmagazine 450
RL_Miller -2250
|
Отображение Табло
Сетка Yii по умолчанию позволяет довольно легко отображать таблицу SocialProfile и настраивать столбцы табло.
Вот SocialProfileController::actionIndex()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/**
* Lists all SocialProfile models.
* @return mixed
*/
public function actionIndex()
{
$searchModel = new SocialProfileSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render(‘index’, [
‘searchModel’ => $searchModel,
‘dataProvider’ => $dataProvider,
]);
}
|
И вот настроенный вид сетки:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
/* @var $this yii\web\View */
/* @var $searchModel frontend\models\SocialProfileSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = Yii::t(‘frontend’, ‘Social Profiles’);
$this->params[‘breadcrumbs’][] = $this->title;
?>
<div class=»social-profile-index»>
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render(‘_search’, [‘model’ => $searchModel]);
<?php Pjax::begin();
‘dataProvider’ => $dataProvider,
‘filterModel’ => $searchModel,
‘columns’ => [
[‘class’ => ‘yii\grid\SerialColumn’],
[
‘label’=>’Name’,
‘format’ => ‘raw’,
‘value’ => function ($model) {
return ‘<div><span><strong><a href=»http://twitter.com/’.$model->screen_name.’»>’.$model->name.'</a></strong><br />’.$model->screen_name.’
},
],
‘score’,
[
‘label’=>’Follows’,
‘format’ => ‘raw’,
‘attribute’=>’friend_count’,
],
[
‘label’=>’Followers’,
‘format’ => ‘raw’,
‘attribute’=>’follower_count’,
],
[
‘label’=>’Tweets’,
‘format’ => ‘raw’,
‘attribute’=>’status_count’,
],
[
‘label’=>’Favs’,
‘format’ => ‘raw’,
‘attribute’=>’favourites_count’,
],
[
‘label’=>’Listed’,
‘format’ => ‘raw’,
‘attribute’=>’listed_in’,
],
[
‘label’=>’P’,
‘format’ => ‘raw’,
‘attribute’=>’protected’,
],
[
‘label’=>’V’,
‘format’ => ‘raw’,
‘attribute’=>’verified’,
],
// ‘location’,
// ‘profile_location’,
[
//’contentOptions’ => [‘class’ => ‘col-lg-11 col-xs-10’],
‘label’=>’Pic’,
‘format’ => ‘raw’,
‘value’ => function ($model) {
return ‘<div><span><img src=»‘.$model->image_url.’»>
},
],
],
]);
<?php Pjax::end();
|
Вот как выглядят лучшие результаты моего первоначального алгоритма:
Есть так много способов улучшить и настроить выигрыш. Я с нетерпением жду возможности поиграть с этим больше.
И еще я бы хотел написать код и расширить использование API, например:
- Используйте гендер PHP, чтобы помочь устранить компании из людей (компании не очень много взаимодействуют).
- Посмотрите частоту постов, которые люди делали, и последний раз, когда они использовали Twitter.
- Используйте API поиска в Твиттере, чтобы увидеть, какие подписчики когда-либо взаимодействовали с моим контентом.
- Обеспечить обратную связь с оценкой, чтобы настроить его.
Заглядывая вперед
Я надеюсь, что вы находите подход к выигрышу интригующим. Можно сделать гораздо больше, чтобы улучшить это. Пожалуйста, не стесняйтесь играть с ним и опубликуйте свои идеи ниже.
Если у вас есть какие-либо вопросы или предложения, пожалуйста, оставьте их в комментариях. Если вы хотите быть в курсе моих будущих уроков Envato Tuts + и других серий, пожалуйста, посетите мою страницу инструктора или следуйте @reifman . Обязательно посмотрите мою серию стартапов и Планировщик собраний .
Ссылки по теме
- Twixxr (недавний пример приложения Twitter API для обнаружения влиятельных женщин)
- Твиттер Документация для разработчиков
- Как программировать с помощью серии Yii2 (Envato Tuts +)