Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)



Это вторая часть серии из двух частей, посвященная использованию социальных сетей для поиска очевидцев важных событий. В первой части я показал вам, как использовать API Instagram, чтобы найти свидетелей живой видеосессии Макклемора в Сиэтле. В этой части мы будем использовать API Twitter для поиска участников выступления президента Обамы в Сельме на мосту Эдмунда Петтуса.
Вы можете загрузить код для обоих эпизодов, используя ссылку репозитория GitHub на боковой панели. Вы также можете быть заинтересованы в моей серии Tuts +, Работа с Twitter API.
Возможности геопоиск Twitter более ограничены и поэтому требуют более подробного кода для использования. Geotagged сообщения в Twitter можно найти только за последние семь дней. И они доступны только по дате (а не по времени), поэтому вам нужно фильтровать результаты API для точности.
Я участвую в обсуждениях ниже. Если у вас есть вопрос или предложение, пожалуйста, напишите комментарий ниже. Вы также можете связаться со мной в Twitter @reifman или напрямую отправить мне электронное письмо.
Что мы рассмотрели в первой части
Телефоны, которые мы носим в наших карманах, записывают каждый наш шаг, делясь им с поставщиками сотовых телефонов и часто сторонними компаниями-разработчиками программного обеспечения, чьи мотивации в основном фокусируются на прибыли.
Многие люди не понимают, что они оставили геотаггинг в своих приложениях в социальных сетях, полностью предоставляя свое местоположение с каждым сообщением в социальных сетях. Это включало конгрессмена Республиканской партии Аарона Шока. AP использовала геотаг своей учетной записи Instagram, чтобы показать использование средств налогоплательщиков для экстравагантных частных рейсов и других роскошных мероприятий.
Таким образом, геотаггинг можно использовать для благих целей. В этой серии мы изучаем то, как журналисты и правоохранительные органы могут найти потенциальных свидетелей для важных событий, таких как преступление или происшествие с использованием социальных сетей.
Однако геотаггинг также можно использовать и с плохими намерениями. В Беркли компьютерные ученые и педагоги написали приложение Ready или нет?, чтобы продемонстрировать, как геотаггинг в Twitter и Instagram записывают каждый наш шаг.
Вот Twitter-аккаунт соаснователя Apple Стив Возняка в этом приложении:



Геотегинг на Instagram и Twitter достаточно точен, чтобы позволить кому-то легко определить ваше место жительства, место работы и маршрут путешествия.
В этом эпизоде я проведу вас через API Twitter. Я предоставил репозиторий GitHub (ссылка находится на боковой панели), чтобы скачать его и самим попробовать этот код. Мое приложение Свидетель написано на Yii Framework для PHP, о котором вы можете узнать больше в моей серии статей Программирование на Yii2 на Tuts+.
Если вы не хотите делиться своим местоположением с общественностью, приложение Готов или нет? предлагает ссылки и руководства по отключению этих функций (найдите ссылку на своей домашней странице). Честно говоря, я отключил их у себя себя, и я призываю вас тоже это сделать.
Если вы являетесь членом правоохранительных органов или журналистом, который хотел бы получить больше информации, пожалуйста, свяжитесь со мной напрямую. Я также был бы заинтересован в любом успешном использовании этого кода (в благих целях).
Что мы сделали с Instagram
В последнем эпизоде, мы использовали API Instagram, чтобы найти очевидцев для видеоролика Mackelmore в 2013 году для White Cadillac. Довольно легко нам удалось найти фотографию пользователя Instagram Джошуа Льюиса, на которой Маклемор вышел из своего автомобиля (круто, да?):



Теперь давайте начнем использовать API Twitter.
Использование API Twitter
Как и в случае с Instagram, вам необходимо войти в свою учетную запись Twitter и зарегистрировать приложение разработчика. Вы должны зарегистрировать такое приложение:



Twitter покажет вам данные о вашем приложении:



Вот страница настроек:



Вот ключи и токены доступа для приложения. Обратите внимание на это.



Затем прокрутите вниз и создайте токены доступа для своей учетной записи. Запишите их.
Добавьте все четыре этих ключа конфигурации и секреты в файл /var/secure/eyew.ini
:
1 |
mysql_host="localhost" |
2 |
mysql_db="eyew" |
3 |
mysql_un="xxxxxxxxx" |
4 |
mysql_pwd="xxxxxxxxxxxx" |
5 |
instagram_client_id = "4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7" |
6 |
instagram_client_secret = "1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4" |
7 |
twitter_key = "zxxxxxxxxxxxxxxxxxxxx2" |
8 |
twitter_secret ="4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxp" |
9 |
twitter_oauth_token="1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxs" |
10 |
twitter_oauth_secret="exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxV" |
Затем мы создадим миграцию Active Record, чтобы создать нашу модель Twitter. Она сохранит твиты, которые мы получаем от вызовов API.
1 |
<?php |
2 |
|
3 |
use yii\db\Schema; |
4 |
use yii\db\Migration; |
5 |
|
6 |
class m150309_174014_create_twitter_table extends Migration |
7 |
{
|
8 |
public function up() |
9 |
{
|
10 |
$tableOptions = null; |
11 |
if ($this->db->driverName === 'mysql') { |
12 |
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; |
13 |
}
|
14 |
|
15 |
$this->createTable('{{%twitter}}', [ |
16 |
'id' => Schema::TYPE_PK, |
17 |
'moment_id' => Schema::TYPE_INTEGER . ' NOT NULL', |
18 |
'tweet_id' => Schema::TYPE_BIGINT . ' NOT NULL', |
19 |
'twitter_id' => Schema::TYPE_BIGINT . ' NOT NULL', |
20 |
'screen_name' => Schema::TYPE_STRING . ' NOT NULL DEFAULT 0', |
21 |
'text' => Schema::TYPE_TEXT . ' NOT NULL ', |
22 |
'tweeted_at' => Schema::TYPE_INTEGER . ' NOT NULL', |
23 |
'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', |
24 |
'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', |
25 |
], $tableOptions); |
26 |
$this->addForeignKey('fk_twitter_moment', '{{%twitter}}', 'moment_id', '{{%moment}}', 'id', 'CASCADE', 'CASCADE'); |
27 |
}
|
28 |
|
29 |
|
30 |
public function down() |
31 |
{
|
32 |
$this->dropForeignKey('fk_twitter_moment','{{%twitter}}'); |
33 |
$this->dropTable('{{%twitter}}'); |
34 |
}
|
35 |
}
|
Как и в первой части, вам нужно выполнить миграцию:
1 |
./yii migrate/up |
2 |
Yii Migration Tool (based on Yii v2.0.3) |
3 |
|
4 |
Total 1 new migration to be applied: |
5 |
m150309_174014_create_twitter_table |
6 |
|
7 |
Apply the above migration? (yes|no) [no]:yes |
8 |
*** applying m150309_174014_create_twitter_table
|
9 |
> create table {{%twitter}} ... done (time: 0.008s) |
10 |
> add foreign key fk_twitter_moment: {{%twitter}} (moment_id) references {{%moment}} (id) ... done (time: 0.007s) |
11 |
*** applied m150309_174014_create_twitter_table (time: 0.019s) |
12 |
|
13 |
Migrated up successfully. |
Затем я использовал генератор кода Yii2, Gii, чтобы создать модель и CRUD-контроллеры для модели Twitter. Если вы скачаете код репозитория GitHub, используя ссылку боковой панели в этом учебнике, вы также получите этот код.
Создаем новый момент
Поскольку Twitter ограничивает поиски геолокации максимум на 7 дней, я в конечном итоге выбрал пятилетнюю юбилейную речь президента Обамы на мосту Эдмунда Петтуса.
Я снова использовал Карты Google, чтобы получить координаты GPS для моста:



Затем я создал Момент для для поиска речи. Я обновил его несколько раз, чтобы настроить географический радиус поиска (это мост) и временной диапазон:



Поиск с помощью API Twitter
Ограничения API Twitter - в том, что он позволяет вам искать по дате, например. 2015-03-07, тогда как Instagram индексируется точными отметками времени Unix. Поэтому мы должны начать наш поиск в Twitter на целый день вперед и искать назад.
Поскольку мы, скорее всего, получим много твитов за пределами желаемого временного диапазона, мы должны повторять вызовы в API Twitter. Twitter возвращает до 100 твитов за запрос API и позволяет 180 запросов в 15-минутном окне.
Я использую библиотеку API Twitter Джеймса Мэллисона для PHP. Вот как мы настраиваем библиотеку для вызовов:
1 |
<?php
|
2 |
|
3 |
namespace app\models; |
4 |
|
5 |
use Yii; |
6 |
use yii\db\ActiveRecord; |
7 |
use app\models\Gram; |
8 |
use Instagram; |
9 |
use TwitterAPIExchange; |
10 |
|
11 |
...
|
12 |
|
13 |
public function searchTwitter() { |
14 |
date_default_timezone_set('America/Los_Angeles'); |
15 |
Yii::trace('start searchTwitter '.date('y-m-d h:m ')); |
16 |
// Load your Twitter application keys
|
17 |
$settings = array( |
18 |
'oauth_access_token' => \Yii::$app->params['twitter']['oauth_token'], |
19 |
'oauth_access_token_secret' => \Yii::$app->params['twitter']['oauth_secret'], |
20 |
'consumer_key' => \Yii::$app->params['twitter']['key'], |
21 |
'consumer_secret' => \Yii::$app->params['twitter']['secret'], |
22 |
);
|
23 |
// Connect to Twitter
|
24 |
$twitter = new TwitterAPIExchange($settings); |
Первоначально мы запрашиваем 100 результатов от Twitter по нашим GPS-координатам до определенной даты.
1 |
public function searchTwitter() { |
2 |
date_default_timezone_set('America/Los_Angeles'); |
3 |
Yii::trace('start searchTwitter '.date('y-m-d h:m ')); |
4 |
// Load your Twitter application keys
|
5 |
$settings = array( |
6 |
'oauth_access_token' => \Yii::$app->params['twitter']['oauth_token'], |
7 |
'oauth_access_token_secret' => \Yii::$app->params['twitter']['oauth_secret'], |
8 |
'consumer_key' => \Yii::$app->params['twitter']['key'], |
9 |
'consumer_secret' => \Yii::$app->params['twitter']['secret'], |
10 |
);
|
11 |
// Connect to Twitter
|
12 |
$twitter = new TwitterAPIExchange($settings); |
13 |
// Query settings for search
|
14 |
$url = 'https://api.twitter.com/1.1/search/tweets.json'; |
15 |
$requestMethod = 'GET'; |
16 |
// rate limit of 180 queries
|
17 |
$limit = 180; |
18 |
$query_count=1; |
19 |
$count = 100; |
20 |
$result_type = 'recent'; |
21 |
// calculate valid timestamp range
|
22 |
$valid_start = $this->start_at; |
23 |
// $until_date and $valid_end = // start time + duration
|
24 |
$valid_end = $this->start_at + ($this->duration*60); |
25 |
Yii::trace( 'Valid Range: '.$valid_start.' -> '.$valid_end); |
26 |
$until_date = date('Y-m-d',$valid_end+(24*3600)); // add one day |
27 |
$distance_km = $this->distance/1000; // distance in km |
28 |
// Unused: &since=$since_date
|
29 |
// $since_date = '2015-03-05';
|
30 |
// Perform first query with until_date
|
31 |
$getfield ="?result_type=$result_type&geocode=".$this->latitude.",".$this->longitude.",".$distance_km."mi&include_entities=false&until=$until_date&count=$count"; |
Мы записываем только твиты в пределах нашего точного диапазона времени, игнорируя другие результаты. Когда мы обрабатываем их, мы учитываем самый низкий идентификатор твита.
1 |
$tweets = json_decode($twitter->setGetfield($getfield) |
2 |
->buildOauth($url, $requestMethod) |
3 |
->performRequest()); |
4 |
if (isset($tweets->errors)) { |
5 |
Yii::$app->session->setFlash('error', 'Twitter Rate Limit Reached.'); |
6 |
Yii::error($tweets->errors[0]->message); |
7 |
return; |
8 |
}
|
9 |
$max_id = 0; |
10 |
Yii::trace( 'Count Statuses: '.count($tweets->statuses)); |
11 |
Yii::trace( 'Max Tweet Id: '.$max_id); |
12 |
foreach ($tweets->statuses as $t) { |
13 |
// check if tweet in valid time range
|
14 |
$unix_created_at = strtotime($t->created_at); |
15 |
Yii::trace('Tweet @ '.$t->created_at.' '.$unix_created_at.':'.$t->user->screen_name.' '.(isset($t->text)?$t->text:'')); |
16 |
if ($unix_created_at >= $valid_start && $unix_created_at <= $valid_end) |
17 |
{
|
18 |
// print_r($t);
|
19 |
$i = new Twitter(); $i->add($this->id,$t->id_str,$t->user->id_str,$t->user->screen_name,$unix_created_at,(isset($t->text)?$t->text:'')); |
20 |
}
|
21 |
if ($max_id ==0) { |
22 |
$max_id = intval($t->id_str); |
23 |
} else { |
24 |
$max_id = min($max_id, intval($t->id_str)); |
25 |
}
|
26 |
}
|
Затем мы делаем цикл, повторяя запросы в Twitter (до 179 раз), запрашивая дополнительные записи, которые были сделаны раньше, чем предыдущий идентификатор твита предыдущей партии. Другими словами, при последующих запросах вместо запроса до определенной даты мы запрашиваем max_id самого низкого идентификатора твита, который мы получили.
Мы останавливаемся, когда возвращается менее 100 записей или когда возвращенные твиты раньше нашего реального диапазона.
Если вам нужен доступ к более чем 18 000 твитов, вам нужно будет выполнить задание в фоне для вызова API Twitter, как это было сделано в нашей другой серии API Twitter.
Когда мы обрабатываем результаты API, нам необходимо фильтровать твиты, записывая только те, которые попадают в наше фактическое время начала и окончания.
Примечание. В API Twitter есть много разочаровывающих причуд, которые делают пейджинг сложнее, чем он должен быть. Довольно часто Twitter не возвращает никаких результатов без кода ошибки. В других случаях я обнаружил, что он возвращал небольшое количество результатов, но это не означает, что другой запрос не вернет больше. Нет четких способов узнать, когда Twitter вернул все результаты. Очень непоследовательно. Таким образом, вы можете заметить, что мой код содержит несколько интересных обходных решений, например, изучите $count_max_repeats.
1 |
$count_repeat_max =0; |
2 |
// Perform all subsequent queries with addition of updated maximum_tweet_id
|
3 |
while ($query_count<=$limit) { |
4 |
$prior_max_id = $max_id; |
5 |
$query_count+=1; |
6 |
Yii::trace( 'Request #: '.$query_count); |
7 |
|
8 |
// Perform subsequent query with max_id
|
9 |
$getfield ="?result_type=$result_type&geocode=".$this->latitude.",".$this->longitude.",".$distance_km."mi&include_entities=false&max_id=$max_id&count=$count"; |
10 |
|
11 |
$tweets = json_decode($twitter->setGetfield($getfield) |
12 |
->buildOauth($url, $requestMethod) |
13 |
->performRequest()); |
14 |
|
15 |
if (isset($tweets->errors)) { |
16 |
Yii::$app->session->setFlash('error', 'Twitter Rate Limit Reached.'); |
17 |
Yii::error($tweets->errors[0]->message); |
18 |
return; |
19 |
}
|
20 |
// sometimes twitter api fails
|
21 |
if (!isset($tweets->statuses)) continue; |
22 |
|
23 |
Yii::trace( 'Count Statuses: '.count($tweets->statuses)); |
24 |
Yii::trace( 'Max Tweet Id: '.$max_id); |
25 |
foreach ($tweets->statuses as $t) { |
26 |
// check if tweet in valid time range
|
27 |
$unix_created_at = strtotime($t->created_at); |
28 |
if ($unix_created_at >= $valid_start && $unix_created_at <= $valid_end) |
29 |
{
|
30 |
$i = new Twitter(); $i->add($this->id,$t->id_str,$t->user->id_str,$t->user->screen_name,$unix_created_at,(isset($t->text)?$t->text:'')); |
31 |
} else if ($unix_created_at < $valid_start) { |
32 |
// stop querying when earlier than valid_start
|
33 |
return; |
34 |
}
|
35 |
$max_id = min($max_id,intval($t->id_str))-1; |
36 |
}
|
37 |
if ($prior_max_id - $max_id <=1 OR count($tweets->statuses)<1) { |
38 |
$count_repeat_max+=1; |
39 |
}
|
40 |
if ($count_repeat_max>5) { |
41 |
// when the api isn't returning more results
|
42 |
break; |
43 |
}
|
44 |
} // end while |
Один из первых результатов, которые были возвращены, включал твит ниже Фреда Дэвенпорта, демонстрирующего президента Обаму на сцене:



Вот это на Twitter:



Затем, когда вы просматриваете результаты дальше, вы можете найти еще много людей, которые написали об Обаме, включая средства массовой информации:



Теперь давайте сделаем более локальный поиск.
Второй, более локальный поиск
Key Arena - крупная концертная и спортивная арена в Сиэтле. В минувшие выходные они провели турнир по баскетболу среди женщин Pac-12:



Давайте получим наши GPS-координаты для Key Arena с помощью Google Maps:



Затем я создал и изменил момент, чтобы найти более длинный диапазон времени для твитов:



И вот некоторые из результатов. Мой любимый:
«Я хочу оставить эту игру в баскетбол. Я ненавижу баскетбол."



По большей части мне кажется, что API Instagram намного мощнее, чем Twitter, и дает в целом более интригующие результаты. Однако это зависит от того, кого вы ищете. Если вы просто хотите идентифицировать людей, которые там были, любой API работает хорошо.
Что мы узнали
Надеюсь, вам понравилась эта серия. Я нашел ее увлекательной и был впечатлен результатами. И в ней подчеркивается, что мы все должны заботиться о нашем уровне конфиденциальности в этой взаимосвязанной цифровой эпохе.
API для Instagram и Twitter - это невероятно мощные сервисы для поиска пользователей социальных сетей, которые находились поблизости от определенных мест в определенное время. Эта информация может быть использована как в благих так и не очень целях. Вероятно, вам стоит подумать об отключении геолокации - следуйте ссылкам в приложении Готов или нет?
Вы также можете ознакомиться с моей серией статей Работаем с API Twitter на Tuts +.
Пожалуйста, не стесняйтесь оставлять свои вопросы и комментарии ниже. Вы также можете связаться со мной в Twitter @reifman или напрямую отправить мне электронное письмо. Я особенно хотел бы услышать комментарии от журналистов и правоохранительных органов, которые используют эти примеры.
Вы также можете просмотреть мою страницу инструктора Tuts +, чтобы найти другие учебники, которые я написал.