Статьи

Создание с помощью API Twitter: анализ ваших последователей

Конечный продукт
Что вы будете создавать

Добро пожаловать в последний эпизод нашей серии Twitter API . В нашем последнем эпизоде ​​я создал Twixxr.com, который позволит вам обнаружить влиятельных женщин в Твиттере для вашей учетной записи. Сегодня я собираюсь обратить внимание на своих последователей.

Хотя я не пользовался Facebook с 2013 года , я оставался активным в Твиттере — даже несмотря на то, что они загружали мой канал рекламой и раздражали меня, пытаясь алгоритмически оптимизировать его.

Недавно я был проверен и начал собирать подписчиков чуть быстрее. Я надеялся, что смогу увидеть больше ответов на мои твиты. Вообще, я был удивлен тем, как мало людей обычно получают отклик в Твиттере.

Построение с помощью профиля reifman в Twitter API с проверенной галочкой

У меня почти 1900 подписчиков, но редко люди комментируют или ретвитят фрагменты, которые, на мой взгляд, важны и представляют общий интерес. Например, ни один человек не поделился моей статьей о резком всплеске сообщений об изнасилованиях в Сиэтле или комментариев о Билле Гейтсе в его наиболее вопиющей лицемерности .

В течение долгого времени я хотел более внимательно посмотреть на своих подписчиков в Твиттере и ответить на несколько вопросов: кто именно следит за мной? И почему они не более интерактивны? Возможно ли, что только 10% моих последователей являются настоящими людьми?

У Twitter проблемы с поиском покупателя, и, возможно, это как-то связано с этим.

API Twitter — хороший инструмент для исследования этого. Тем не менее, он имеет множество ограничений скорости, которые делают даже что-то простое, например, анализ ваших подписчиков, довольно сложным. В сегодняшнем эпизоде ​​я покажу вам, как я работал с ограничениями скорости, чтобы оценить и построить табло моих подписчиков.

Если у вас есть какие-либо вопросы или комментарии, пожалуйста, оставьте их ниже в комментариях или свяжитесь со мной в Twitter @reifman .

Сборка с помощью Twitter API Первоначальное табло

Чуть выше вы можете увидеть базовое табло, которое я создал. Сегодняшний эпизод будет посвящен в основном инфраструктуре и подходу, который я выбрал для создания этого. Я надеюсь, что у меня будет возможность написать больше об улучшении механизма оценки.

И да, как вы можете видеть выше, известный лидер прав геев и комментатор по сексуальным советам Дэн Сэвидж следует за мной, но никогда не ретвитит то, что я разделяю. Если сегодня будет время, мы проанализируем это, чтобы ответить на такие важные вопросы, как: он настоящий, бот или просто следует за мной за советом по поводу секса? Что мы можем узнать из его аккаунта, чтобы определить, будет ли он когда-либо взаимодействовать со мной в Твиттере или, если уж на то пошло, с кем-либо из моих последователей?

Код на табло — это, в основном, прототип, который я построил поверх кода 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();
     }
Создание с помощью API Twitter - аккаунты с огромным количеством друзей вряд ли будут читать мои твиты

У меня было несколько голов для оценки в Твиттере:

  • Удалите аккаунты, которые следуют за всеми, кто за ними следует Например, у них есть 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();

Вот как выглядят лучшие результаты моего первоначального алгоритма:

Создание с помощью Twitter API - Лучшие учетные записи

Есть так много способов улучшить и настроить выигрыш. Я с нетерпением жду возможности поиграть с этим больше.

И еще я бы хотел написать код и расширить использование API, например:

  • Используйте гендер PHP, чтобы помочь устранить компании из людей (компании не очень много взаимодействуют).
  • Посмотрите частоту постов, которые люди делали, и последний раз, когда они использовали Twitter.
  • Используйте API поиска в Твиттере, чтобы увидеть, какие подписчики когда-либо взаимодействовали с моим контентом.
  • Обеспечить обратную связь с оценкой, чтобы настроить его.

Я надеюсь, что вы находите подход к выигрышу интригующим. Можно сделать гораздо больше, чтобы улучшить это. Пожалуйста, не стесняйтесь играть с ним и опубликуйте свои идеи ниже.

Если у вас есть какие-либо вопросы или предложения, пожалуйста, оставьте их в комментариях. Если вы хотите быть в курсе моих будущих уроков Envato Tuts + и других серий, пожалуйста, посетите мою страницу инструктора или следуйте @reifman . Обязательно посмотрите мою серию стартапов и Планировщик собраний .