La siguiente publicación surge porque muchas personas me han consultado, cómo hacer para que en los tuits que llevan imágenes incrustadas, les aparezca esta imagen y no un enlace como ocurre con muchas aplicaciones para programar tuits, por ejemplo Hootsuite. Cabe destacar que no tenemos nada en contra de estas aplicaciones, las hemos utilizado durante mucho tiempo y cumplen sus funciones de la mejor manera (si compran las versiones "pro" mejor aún), sólo que en este caso les voy a explicar como programar estos tuits desde la relativamente nueva opción de twitter, llamada "Twitter Ads", para que en sus tuits las imágenes aparezcan sin necesidad de abrir un enlace adicional.

Si es la primera vez que están entrando en esta sección, solicitará seleccionar un país y una zona horaria. En nuestro caso no existe la Zona Horaria de Venezuela, pero colocamos la más cercana la cual tiene solo media hora de diferencia. Esto es importante porque al momento de seleccionar la hora para publicar sus tuits deben tener bien especificado la hora de sus país.
Por alguna razón que en este momento desconozco (quizás alguna actualización), la barra de Twitter Ads no me presenta la opción de "Creatividades" que es la sección para programar los tuits, pero como todo tiene solución, solo deberán seguir (por ahora) los siguientes pasos:

1.- Seleccionar en el menú Estadísticas, la opción Eventos. En la barra de menú verán un enlace como este: https://ads.twitter.com/accounts/18ce540lehf/events

2.- Deberán eliminar la palabra "events" y colocar la palabra "tweets" (sin las comillas), el enlace se presentará ahora de la siguiente manera: https://ads.twitter.com/accounts/18ce540lehf/tweets

Listo, ya podrán programar sus tuits como les mostraré a continuación. Es importante que tengan en cuenta que cada usuario de twitter, tendrá un número asociado, por consiguiente los enlaces varían, resalté en color rojo el número que nos corresponde a nosotros para que lo tengan presente.

Al entrar en esta página, podrán comenzar a programar todos sus tuits de la siguiente manera:
1.- Hacer clic en el botón "Nuevo Tweet" (ángulo superior izquierdo de la página)
2.- En la ventana que se despliega escribir el Tuit de la manera tradicional, y seleccionar la camarita que presenta para colocar la imagen (al igual que en la pagina de twiiter)
3.- Seleccionar la opción "Programación" y en esta sección deberán seleccionar la fecha y la hora del (deben estar pendiente de la zona horario)
4.- Hacer clic en el botón "Tweet"
y Listo!!!!

Luego podrás consultar los tuits que hayas programado seleccionando en la 3ra pestaña, la opción "Tweets Programados", y en caso de querer Editar alguno también podrán hacerlo desde esta sección.



Si tienen algún comentario, opinión o sugerencia nos pueden escribir a consulta_friki@kioscofriki.com.ve 
Y recuerda, si esta información te ayudó y quieres colaborarnos económicamente puedes hacer tu donación aquí

No hace mucho fui víctima de cyberbulling con amenazas, insultos y elevadas menciones, retweets y favoritos en Twitter cuando el Gobierno Venezolano confundió mi nombre y profesión por alguien que según ellos es el webmaster de DolarToday.com en un programa de TV donde me dedicaron 15 minutos en la emisora del estado VTV.

Gracias a las experiencias en IRC le reste importancia pero aun persistía la oleada de interacciones que molestaban mis notificaciones en Twitter. Al principio pensé en simplemente proteger mi cuenta y dejar que esto pasara pero sentí que eso era lo que los atacantes querían, La alternativa era silenciar a estas cuentas pero dejar que le lean al mismo tiempo.

La tarea suena sencilla pero cuando tienes cientos de cuentas insultando, amenazando y cientos de cientos mas retuiteando cada minuto, se hace un poco tediosa la tarea así que decidí automatizar esto con este script:

import json
import requests
from requests_oauthlib import OAuth1
import sys
import csv
from time import sleep

whitelist = ['orvtech']

shitlist = ['amaia_roja', 'anat5', 'carollafra', 'contraofensiva',
            'correoorinoco', 'forocandanga', 'guerrillaragua',
            'hectorodriguez', 'izarradeverdad', 'jorgerpsuv',
           'jrodriguezpsuv', 'lahojillaentv', 'laradiodelsur',
            'maperezpirela', 'nicolasmaduro', 'prisciliano_alf',
            'thaivama', 'yndiratorregros', 'PatriciaDorta40']

#credentials from ghost account
consumer_key=''
consumer_secret=''
access_token_key=''
access_token_secret=''

#credentials from actual account
consumer_key2=''
consumer_secret2=''
access_token_key2=''
access_token_secret2=''

def get_retweets(tweetid):
  retweetdata={}
  handles=[]
  api_url="https://api.twitter.com/1.1/statuses/retweets/"+tweetid+".json"
  payload = {'count':'100'}
  auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
  r = requests.get(api_url, stream=False, auth=auth, params=payload)
  try:
    if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
      print("We reached rate limit for ", api_url)
      print("Try again at", r.headers["x-rate-limit-reset"])
      quit()
  except KeyboardInterrupt:
      sys.exit()
  except:
     print "OK"
  retweetsObj = json.loads(r.content)
  for y in range(len(retweetsObj)):
    handles.append(retweetsObj[y]['user']['screen_name'])
  return handles

BLOCK_URL = 'https://api.twitter.com/1.1/blocks/create.json'
MUTE_URL = 'https://api.twitter.com/1.1/mutes/users/create.json'

def getTweets(usuarios):
   api_url="https://api.twitter.com/1.1/statuses/user_timeline.json"
   payload = {'screen_name': usuarios, 'count':'1', 'trim_user':'t', 'include_rts':'false'}
   auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
   r = requests.get(api_url, stream=False, auth=auth, params=payload)
   statusObj = json.loads(r.content)
   return statusObj[0]['id']

def act_on_handle(api_url, auth, payload):
    try:
       r = requests.post(api_url, stream=False, auth=auth, params=payload)
       msgs = json.loads(r.content)
       print r.headers['status'] , payload
       if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
          print('We reached rate limit for {url}'.format(url=api_url))
          print('Try again at {reset}'.format(reset=r.headers["x-rate-limit-reset"]))
          sys.exit()
    except KeyboardInterrupt:
       sys.exit()
    except:
       pass

def main():
    for cuenta in shitlist:
       try:
         tweet = str(getTweets(cuenta))
         print "\nAnalizyng retweeters of" , cuenta , "TweetID:", tweet
         print "https://twitter.com/" + cuenta + "/status/" + tweet
         HANDLES = get_retweets(tweet)
         for user in HANDLES:
            if user not in whitelist:
              auth2 = OAuth1(consumer_key2, consumer_secret2, access_token_key2, access_token_secret2)
              payload = "screen_name=" + user
              #act_on_handle(BLOCK_URL, auth2, payload)
              act_on_handle(MUTE_URL, auth2, payload)
              sleep(1)
            else:
              print "YOU FOLLOW " , user , "WHO RETWEETED" , cuenta
              sleep(40)
         sleep(60)
       except KeyboardInterrupt:
         sys.exit()
       except:
         pass

if __name__ == '__main__':
    main()

Este script usa dos cuentas, La cuenta que esta siendo atacada la cual va a ser protegida y una segunda cuenta que es la que usamos para ver las interacciones de las cuentas que nos están atacando. Al momento de escribir este articulo, no es necesario usar la segunda cuenta pero en un futuro twitter podría prohibir que uno viera las interacciones de tweets de cuentas que no tiene en mudo o bloqueadas por el API así que decidí prepararme para eso. Como siempre los OAuth tokens y llaves las pueden obtener registrando sus apps en apps.twitter.com.

El programa lo que hace es buscar todos los tweets de una lista de cuentas que sabemos nos atacan y tomar acción contra quienes retuitean estos tweets, las acciones pueden ser bloquear y/o enmudecer.

Tras dejarlo correr un par de ciclos el resultado fue total normalidad en mi cuenta de Twitter. Ayudo un poco que los clusters de cuentas automatizadas fueron reportados y suspendidas de Twitter un par de días después.

Para la versión mas reciente de este programa, colaborar y reportar bugs pueden visitar el mi repositorio en GitHub.

Dejar de seguir a quienes no te siguen en Twitter con este script de Python. Hace unas semanas hice un script en Python que permitía saber quienes no te seguían pero con el cambio de la API a la versión 1.1 quedo obsoleto. Entre las peticiones que he recibido aparte de ponerlo a funcionar con la API nueva era para dejar de seguir a esos que no te seguían.

El siguiente script no te dice los nombres de quienes no te siguen como lo hacia el que mencione anteriormente pero cuenta cuantos de los que tu sigues no te siguen y los deja de seguir. Antes de ejecutarlo les recomiendo que organicen las cuentas que ustedes siguen y que tal vez no los sigan en listas, por ejemplo crear una lista con todas sus fuentes de noticia o una de robots y comedia, etc.

Este es el script:

import requests
from requests_oauthlib import OAuth1
import re
from time import sleep
import operator
import sys
import os
import collections


consumer_key=''
consumer_secret=''
access_token_key=''
access_token_secret=''


def get_follower_ids():
  cursor = "-1"
  listadeIDs = []
  while cursor != '0':
    try:
      api_url='https://api.twitter.com/1.1/followers/ids.json'
      payload = {'count':'5000', 'cursor':cursor}
      auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
      r = requests.get(api_url, stream=False, auth=auth, params=payload)
      if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
        time_out = int(r.headers["x-rate-limit-reset"]) - int(time.time())
        print("We reached rate limit for ", api_url)
        print "Try again in", time_out, "seconds"
        quit()
      IDs = json.loads(r.content)
      cursor = IDs['next_cursor_str']
      listadeIDs = listadeIDs + IDs['ids']
      sleep(1)
    except KeyError:
      print "Unable to navigate through cursors, last attempt: ", cursor
      break
  return list(set(listadeIDs))


def get_friends_ids():
  cursor = "-1"
  listadeIDs = []
  while cursor != '0':
    try:
      api_url='https://api.twitter.com/1.1/friends/ids.json'
      payload = {'count':'5000', 'cursor':cursor}
      auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
      r = requests.get(api_url, stream=False, auth=auth, params=payload)
      if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
        print("We reached rate limit for ", api_url)
        print("Try again at", r.headers["x-rate-limit-reset"])
        quit()
      IDs = json.loads(r.content)
      cursor = IDs['next_cursor_str']
      listadeIDs = listadeIDs + IDs['ids']
      sleep(1)
    except KeyError:
      print "Unable to navigate through cursors, last attempt: ", cursor
      break
  return list(set(listadeIDs))



def get_unfollowers_info(unfollowers):
   print len(unfollowers)
   api_url='https://api.twitter.com/1.1/users/lookup.json'
   auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
   user_objs = {}
   sleep(1)
   i = 0
   user_id = []
   for i in unfollowers:
     user_id.append(i)
     if (len(user_id) == 100):
       payload = {'user_id':user_id}
       r = requests.get(api_url, stream=False, auth=auth, params=payload)
       if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
         print("We reached rate limit for ", api_url)
           print("Try again at", r.headers["x-rate-limit-reset"])
         quit()
       tmp_user_objs = json.loads(r.content)
       for y in range(len(tmp_user_objs)):
         print tmp_user_objs[y]['screen_name'] , tmp_user_objs[y]['followers_count'] , tmp_user_objs[y]['friends_count'] , tmp_user_objs[y]['following'] , tmp_user_objs[y]['verified'], tmp_user_objs[y]['default_profile']
       user_objs = user_objs , tmp_user_objs
       user_id = []
   payload = {'user_id':user_id}
   r = requests.get(api_url, stream=False, auth=auth, params=payload)
   if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
     print("We reached rate limit for ", api_url)
     print("Try again at", r.headers["x-rate-limit-reset"])
     quit()
   tmp_user_objs = json.loads(r.content)
   user_objs = user_objs , tmp_user_objs

def unfollow_by_id(user_id):
  api_url='https://api.twitter.com/1.1/friendships/destroy.json'
  payload = {'user_id':user_id}
  auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
  r = requests.post(api_url, stream=False, auth=auth, params=payload)



followers = get_follower_ids()
print "Followers: ", len(followers)
following = get_friends_ids()
print "Following: ", len(following)



unfollower_ids = set(following) - set(followers)
print "unfollower ids: ", unfollower_ids , len(unfollower_ids)


get_unfollowers_info(unfollower_ids)
print "About to unfollow: " , len(unfollower_ids) , "users."
sleep(10)

for user_id in unfollower_ids:
  print "Unfollowing ", user_id
  unfollow_by_id(user_id)

En este script a diferencia de los anteriores que he hecho no use el módulo python-twitter y como ven intento trabajar con el API y su rate-limit En mi caso al ejecutarlo deje de seguir a algunas cuentas de comedia, noticias y cuentas interesantes que enriquecían mi timeline.

Si el tiempo me lo permite, en la próxima versión creo que voy a agregar esos usuarios a una lista privada antes de dejarlos de seguir. He trabajado en otros scripts privados en calcular la importancia de una cuenta en base a la cantidad de seguidores, cantidad de personas que esta sigue, cantidad de tweets, edad de la cuenta y otros factores que tal vez incorpore en un futuro.

Como siempre en todos mis publicaciones que tiene que ver con Python, les agradecería mucho si me dan consejos de como mejorar este script o la lógica del mismo, Incluso pull requests al repo github.com/orvtech/Python-tools-for-twitter/blob/master/unfollow-unfollowers.py.

Sigo en mi travesía por aprender Python y que mejor forma que solucionar problemas en funciona a la privacidad.

Varias personas me comentaron lo tedioso que es eliminar mensajes privados en Twitter así que decidi hacer una herramienta que me permita automatizar todo esto.

Lo primero es crear una app en twitter visitando apps.twitter.com y otorgarle permisos de lectura, escritura y DMs. Allí mismo pueden generar el consumer_key, consumer_secret, access_token_key y el access_token_secret.

El script no es nada complejo y de hecho hay oportunidades para mejorarlo, aqui se los dejo:

# https://github.com/orvtech/Python-tools-for-twitter
import json
import requests
from requests_oauthlib import OAuth1


consumer_key='<YOUR CONSUMER KEY HERE>'
consumer_secret='<YOUR CONSUMER SECRET HERE>'
access_token_key='<YOUR ACCESS TOKEN HERE>'
access_token_secret='<YOUR ACCESS TOKEN SECRET HERE>'


def get_messages_ids():
  api_url='https://api.twitter.com/1.1/direct_messages.json'
  payload = {'count':'200', 'cursor':'-1', 'skip_status':'1'}
  auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
  r = requests.get(api_url, stream=False, auth=auth, params=payload)
  if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
    print("We reached rate limit for ", api_url)
    print("Try again at", r.headers["x-rate-limit-reset"])
    quit()
  DMs = json.loads(r.content)
  message_ids=[]
  for x in range(len(DMs)):
    current_ids=DMs[x]['id']
    message_ids.append(current_ids)
  api_url='https://api.twitter.com/1.1/direct_messages/sent.json'
  payload = {'count':'200'}
  r = requests.get(api_url, stream=False, auth=auth, params=payload)
  if r.headers['x-rate-limit-remaining'] and r.headers['x-rate-limit-remaining'] == "0":
    print("We reached rate limit for ", api_url)
    print("Try again at", r.headers["x-rate-limit-reset"])
    quit()
  DMs = json.loads(r.content)
  for x in range(len(DMs)):
    current_ids=DMs[x]['id']
    message_ids.append(current_ids)
  return message_ids


def nuke_messages(DMs):
  for x in DMs:
    api_url='https://api.twitter.com/1.1/direct_messages/destroy.json'
    payload = {'id':x}
    auth = OAuth1(consumer_key, consumer_secret, access_token_key, access_token_secret)
    r = requests.post(api_url, stream=False, auth=auth, params=payload)


while True:
  DMs = get_messages_ids()
  if DMs and len(DMs) > 0:
    print('Deleting:', DMs)
    nuke_messages(DMs)
  else:
    print('There appears that there are no more DMs', DMs)
    break

Usa solo 2 funciones, una en la que invoca primero los primeros 200 mensajes recibidos y luego los primeros 200 mensajes enviados. Tras evaluar si en realidad existen mensajes, se le pasan los IDs de los mensajes a eliminar a la segunda función y se repite este proceso hasta que no existan mas IDs a eliminar.

Tanto las llamadas de al API para saber los IDs de los mensajes enviados como las de los mensajes enviados tiene un limite así que implemente mecanismos para monitorear si se llego al limite leyendo las cabeceras de las peticiones HTTP.

Por lo pronto pueden hacer un fork de este repositorio de github En un futuro me gustaría convertirlo en una aplicación web usando flask o algo por ese estilo.


Se que suena ilógico, pero si vives en Venezuela, Cuba, Iran, Argentina, China, o cualquier otro país donde sospechas que el gobierno no le agrada mucho tu libertad de expresión debes deshabilitar la verificación de dos factores y desvincular tu celular inmediatamente.

Si tienes duda de como hacerlo, aqui te dejo un video:


El problema es que pocas empresas se imaginan que van a ser de vital importancia en países donde sus ciudadanos son oprimidos y donde el estado tiene acceso a sistemas de mensajería mobil sin orden judicial ni debido proceso como el caso de Venezuela donde Mario Silva en conjunto con Juan Almeida pinchaban teléfonos a diestra y siniestra en vivo en television.

Actualmente son los mismos personajes los que están detrás de la reciente ola de robos de cuentas y lo hacen forzando el mecanismo de verificación de dos factores a que envié un código de 6 dígitos de emergencia (en caso de que pierdas tu dispositivo) al numero de celular apoderándose de tu cuenta en cuestión de segundos.

Por ultimo, recomiendo periódicamente revisar que aplicaciones haz autorizado y revocar cualquiera que ya no uses, que no reconozcas o que sospeches que tiene un comportamiento abusivo.


Modus operandi

Para propagar su ataque dependían un poco de ingeniería social, se hacían pasar por su actual víctima para afectar mas usuarios y de esta forma silenciar sus cuentas.Así operan los robacuentas del gobierno:

  1. Se apoderan de una cuenta importante de la que saben el teléfono asociado vía SMS.
  2. Desde esa cuenta envían un mensaje privado a sus próximas víctimas diciendo que tienen un notición pero prefieren compartirlo via whatsapp para lo que piden "cuenta de de whatsapp" (numero telefónico).
  3. Se mueven a la próxima cuenta y repiten el proceso.

Si tienes alguna otra sugerencia puedes dejarla en los comentarios para irla agregando a este articulo y terminar con una lista solida pero simple de como cuidarnos.

No hace mucho hice un shell script que mostraba la fecha de creación de una cuenta de Twitter pero a las pocas semanas quedo obsoleto por la implementación del API 1.1 que requiere que este tipo de llamas al API sean autenticadas vía OAuth lo cual no es tan sencillo si solo quieres usar bash.

Esta versión esta hecha en Python y a diferencia del anterior proporciona mas información sobre la cuenta. de hecho puede procesar varias cuentas al mismo tiempo, veamos el código fuente de este programa hecho en Python:

from __future__ import print_function, unicode_literals
import requests
from requests\_oauthlib import OAuth1
from urlparse import parse\_qs

handles = raw_input('Enter twitter handles: ').split()

CONSUMER_KEY = " "
CONSUMER_SECRET = " "
OAUTH_TOKEN = " "
OAUTH_TOKEN_SECRET = " "

def get_oauth():
  oauth = OAuth1(CONSUMER_KEY,
  client_secret=CONSUMER_SECRET,
  resource_owner_key=OAUTH_TOKEN,
  resource_owner_secret=OAUTH_TOKEN_SECRET)
  return oauth

if __name__ == "__main__":
  oauth = get_oauth()
  payload={'screen_name':handles}
  r = requests.post(url="https://api.twitter.com/1.1/users/lookup.json",data=payload,auth=oauth)
  user_obj = r.json()
  for line in user_obj:
    print("Handle: " , line['screen_name'])
    print("User ID: " , line['id'])
    print("Verified: " , line['verified'])
    print("Name: " , line['name'])
    print("Account Created: " , line['created_at'])
    print("Followers: " , line['followers_count'])
    print("Following: " , line['friends_count'])
    print("Tweet Count: " , line['statuses_count'])
    print("Favorites: " , line['favourites_count'])
    print('- - - - - - - - - - -\n')

El producto de este script usando mi Twitter handle (orvtech) luce así:

Handle: orvtech
User ID: 4412471
Verified: False
Name: Oliver
Account Created: Thu Apr 12 21:35:06 +0000 2007
Followers: 5710
Following: 558
Tweet Count: 20233
Favorites: 6514


¿Como ver la información de varias cuentas?

Para ver de varias cuentas de Twitter solo debes dárselas a este programa hecho en Python, separadas por espacios en blanco, sin el símbolo de arroba como lo puedes ver aquí:

$ ./user-info.py
Enter twitter handles: orvtech twitter protected


¿Que necesito para correr este script de Python?

Para ejecutar este script necesitas registar tu aplicación y generar unas llaves en apps.twitter.com/app/new para lo que deberás iniciar sesión con tu usuario de Twitter. Una vez registrada tu aplicacion deberas asignar los valores de las constantes CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN y OAUTH_TOKEN_SECRET en el código fuente del script.

Con la ayuda de cron y Python podemos pre-programar el envío de tweets sin que estos se repitan y llevar un registro de los que se han enviado. Este corto script hecho en python es mi segunda aventura con este lenguaje que poco a poco me esta enamorando.

La lógica es simple, el programador de tweets lee un archivo que contiene un tweet por linea, actualiza mi estado en twitter con el contenido de esa linea, registra los resultados en un archivo y por ultimo elimina esa linea del archivo evitando así repetir el mismo tweet. Veamos el código fuente:

#!/usr/bin/python
import twitter
import datetime

now = datetime.datetime.now()

with open('lista.txt', 'r') as f:
  first_line = f.readline()
  first_line = first_line.strip('\n')
  print first_line
f.close()

logfile = open('procesados.txt','a')
fecha=now.strftime("%Y-%m-%d_%H:%M:%S")
logfile.write(fecha + ' ' + first_line + '\n')
logfile.close()

#send tweet
api = twitter.Api(consumer_key='',
  consumer_secret='',
  access_token_key='',
  access_token_secret='')

status = api.PostUpdate(first_line)
print status.text

#removing status from queue
lines = open('lista.txt').readlines()
open('lista.txt', 'w').writelines(lines[1:])

Alimentando el script programador de tweets.

Como vieron en el código fuente, solo necesitamos proporcionarle el archivo lista.txt donde cada tweet dependiendo del tipo tiene limitaciones de longitud distintas. Si no posee un hyper vinculo el limite es de 117 caracteres excluyendo la URL mientras que si no tiene un hiper vinculo el limite es de 140 caracteres. El archivo lista.txt se vería algo así:

Just ran out of bacon, the room seems to be shrinking, please help! ... and bacon
Programador de tweets hecho en python https://orvtech.com/planificador-tweets-python.html

Automatizando el envío de tweets.

Leí un poco y se que se puede hacer un demonio y dejar que python se encargue de esto pero para comenzar decidí hacerlo usando cron. Me decidí a tuitear dos veces por día entre semana mientras que los fines de semana solo una vez. Mi crontab se ve así:

15 15  *  *  0,6  /usr/bin/python /scheduler/reader.py >> /scheduler/reader.log 2>&1
14  6  *  *  1-5  /usr/bin/python /scheduler/reader.py >> /scheduler/reader.log 2>&1
11 20  *  *  1-5  /usr/bin/python /scheduler/reader.py >> /scheduler/reader.log 2>&1

Después de varios años decidí iniciarme en el mundo de Python y jugar un poco con el API de Twitter así que decidí hacer un programa en Python que compara tu lista de seguidores con tu lista de amigos para obtener una lista de las personas que tu sigues pero no te siguen. Es decir, quien te dejo de seguir en Twitter o como dicen en la red, quien te ha dado unfollow.

Como era mi primer intento decidí usar python-twitter que por lo que leí era la mas sencilla de usar. Para instalar este paquete de Python pueden ejecutar:

pip install python-twitter

El programa para listar unfollowers es este:

#!/usr/bin/python
#orvtech_no_me_sigue.py para API 1.0
import twitter

#Prepare the needed data for twitter's oauth

api = twitter.Api(consumer_key='<YOUR_CONSUMER_KEY_HERE>',
                  consumer_secret='<YOUR_CONSUMER_KEY_HERE>',
                  access_token_key='<YOUR_TOKEN_KEY_HERE>',
                  access_token_secret='<YOUR_TOKEN_SECRET_HERE>')

#Get followers by handle
followers = api.GetFollowers()
seguidores =[]

for u in followers:
  seguidores.append(u.screen_name)

#Get friends by handle
friends = api.GetFriends()
siguiendo =[]
for f in friends:
  siguiendo.append(f.screen_name)

#Get the list of people that you follow that but that are not in the followers list
unfollowers = list(set(siguiendo) - set(seguidores))
count_uncool = len(unfollowers)
print "Total friends not following you: " + str(count_uncool)
for uncool in unfollowers:
  print uncool + " " + "https://twitter.com/" + uncool

Como ven para poder ejecutar este programa y ver sus unfollowers deberán obtener una serie de datos de dev.twitter.com para autentificar su programa contra oauth. El producto de este programa se vera algo similar a esto:

Total friends not following you: 61
planetfedora https://twitter.com/planetfedora
twitter https://twitter.com/twitter
TwitterEng https://twitter.com/TwitterEng
twittercomms https://twitter.com/twittercomms
twitterapi https://twitter.com/twitterapi
fedora https://twitter.com/fedora
make https://twitter.com/make
dickc https://twitter.com/dickc
TwitterIO https://twitter.com/TwitterIO
TwitterSF https://twitter.com/TwitterSF
safety https://twitter.com/safety

Por ahora lo que quiero es exportarlo a una aplicacion web, si tienen sugerencias me las pueden dejar en los comentarios, me gustaría un poco de orientación de como hacer de este programa una aplicacion web.


UPDATE: Junio 20 del 2013

Con la salida de el API 1.0 de Twitter el código que esta arriba queda obsoleto y rápidamente alcanza el limite de peticiones de la API. El codigo a continuación trabaja perfectamente con la API versión 1.1 siempre y cuando no tengas mas de 5000 seguidores o mas de 100 personas que no te siguen.

#!/usr/bin/python
#orvtech_no_me_sigue.py para API 1.0
import twitter

#Prepare the needed data for twitter's oauth
api = twitter.Api(consumer_key='<YOUR_CONSUMER_KEY_HERE>',
                  consumer_secret='<YOUR_CONSUMER_KEY_HERE>',
                  access_token_key='<YOUR_TOKEN_KEY_HERE>',
                  access_token_secret='<YOUR_TOKEN_SECRET_HERE>')

followers = api.GetFollowerIDs()
friends = api.GetFriendIDs()

unfollowers = list(set(friends) - set(followers))
count_uncool = len(unfollowers)
nombre = api.UsersLookup(user_id=unfollowers)

print "Total friends not following you: " + str(count_uncool)

counter = 0
for uncool in nombre:
  print nombre[counter].name + " https://twitter.com/" + nombre[counter].screen_name
  counter += 1

El gobierno venezolano se prepara para elecciones regionales con un proxy de Twitter que se presta para ataques de phishing. ¿Que planean al montar un proxy de Twitter?

Como muchos recordaran durante las pasadas elecciones presidenciales de Venezuela parte de la población tuvo problemas para resolver dominios momentáneamente. El usuario final por lo general lo resolvia reiniciando su computadora, simultáneamente muchos sitios que eran favorecidos por opositores sufrieron ataques de DDoS.

Este año con la penetración de las redes sociales y el uso que la comunidad estudiantil de Venezuela le han dado para hacer llegar su mensaje y denuncia de injusticias; el Gobierno Venezolano prepara de nuevo una arremetida.


Repetir como loritos

Como todos saben el candidato presidencial y actual presidente de la república usa el twitter handle @chavezcandanga el cual es controlado por lo que asumo es su comité de P.R.

Este mismo grupo tiene una aplicación compatible con twitter que convierte a cada uno de quienes la usen en robotos (bots) que retuitearan lo que el publique automáticamente. Esto sin contar que cerca del 46% de los seguidores de @chavezcandanga son usuarios que solo tienen un tweet o menos, tienen un seguidor o menos cosa que para mi, los convierte en cuentas falsa y bots.

aplicación RTChavezCandanga alojada en servidores del estado Venezolano para manipular tendencias y generar matrices de opinion.

Para que no quede duda de quien esta detrás de este proxy vamos a consultar la base de datos de registro de dominios la cual la mantiene el mismo estado venezolano.

Pruebas de que es el PSUV el responsable de el dominio detras de todo esto.

Por lo pronto queda claro que es el PSUV (Partido Socialista Unido de Venezuela) el responsable financiero, técnico y administrativo de el dominio detrás de todo esto.


La estocada que se prepara

Lo que me preocupa este momento es que la misma dirección IP que alojael subdominio http://mensajes.chavezcandanga.org.ve/ también aloja un proxy a twitter que hasta ahora no contiene código malicioso (que yo vea). Pero no quiere decir que esto vaya a cambiar días antes de las elecciones o durante.

En estos momentos pueden verlo por ustedes mismos pero en caso de que CONATEL (ente que controla esta IP) tumbe el proxy, la pagina que distribuye la aplicación para enviar enviar spam en twitter y quien sabe que mas, aquí les dejo unas capturas de pantalla.

Proxy a twitter alojado en servidores del gobierno del estado Venezolano

Como ven la IP en cuestion es 190.202.80.20 y que difieren de las IPs de twitter como pueden ver:

host twitter.com | grep address
twitter.com has address 199.59.149.230
twitter.com has address 199.59.150.39
twitter.com has address 199.59.148.82

Investigando un poco mas a fondo podemos ver que de hecho la IP que aloja este proxy a twitter de hecho apunta a otro dominio:

Proxy a twitter alojado en servidores del gobierno del estado Venezolano

Para los que se están preguntando la fuente de esta noticia o como me entere, al parecer un seguidor de un contacto en twitter fue el que dio con esta "coincidencia" como pueden ver en este tweet:



Update: Diciembre 15, 2012

Aun http://190.202.80.20 apunta a un proxy de Twitter aunque sigue sin código malicioso deben estar pendientes para las elecciones regionales en Venezuela a celebrarse el Domingo 16. Recomiendo que sigan atentos a los certificados SSL y eviten usar sus credenciales si "misteriosamente" Twitter.com se las pide y la URL no tiene el prefijo HTTPS.

El fin de semana pasado tuve la oportunidad de entrevistar al líder del proyecto Turpial, Wil Alvarez. Las preguntas variaron entre personales y especificas sobre el popular cliente para identi.ca y Twitter.

Me pareció apropiado hacerle seguimiento a algunas reacciones que obtuve de compartir el vídeo tutorial de Turpial que hice hace poco. En su mayoría fueron positivas pero algunas mostraron cierto descontento con detalles del proyecto. Cuando hice énfasis en que es software Venezolano, la respuesta fue "El único venezolano allí es Wil" y la que mas se repitió era algo así como "Si fuese venezolano, su pagina estaría en castellano".

Esta primera serie de preguntas y respuestas son especificamente de Turpial como tal.



¿Hace cuanto que fue creado Turpial o de donde viene Turpial?

Turpial nace aproximadamente en noviembre de 2008. En octubre, por recomendación de Eleazar Meza (@elshaka), abrí mi cuenta de Twitter y estuve usando varios clientes para Linux de la época. Probé Mutter, Gwibber, DestroyTwitter y otros, pero ninguno cubría mis expectativas.

Para ese entonces Gwibber y Mutter carecían de muchas funcionalidades o de una interfaz simple y si bien DestroyTwitter era una de las mejores opciones, no era libre y eso me generaba cierta incomodidad. Decidí entonces desarrollar un cliente de Twitter para mi uso personal con los conocimientos de Python y Gtk que tenía actualmente. Así fue como nació el proyecto.



La gente se queja de que hay mas material en ingles que en español, entiendo que es para usar un idioma "universal". ¿Que le dirías a esa gente que se queja y como pueden colaborar a traducir?

Azrael (@AzraelCcs) redactó un artículo genial sobre este tema (en inglés) con una explicación muy acertada y varios puntos que valen la pena resaltar, así que tomaré la idea principal de su texto para responder a tu pregunta.

Turpial cada día crece más y para nosotros es importante ayudarlo a seguir creciendo y conquistando nuevos horizontes. Les guste o no, el inglés es un idioma común, tanto en ámbitos de programación como para la interacción de muchos pueblos. No podemos tener una mente tan cerrada como para pensar que el único idioma que se habla es el español ni mucho menos pretender imponer el idioma español como base para la aplicación porque, repito: les guste o no, el inglés es el idioma más hablado fuera de nuestras fronteras.

Gracias a la decisión que tomamos de pasar toda la plataforma a inglés logramos captar a nuestro gran amigo Andrea Stagi (@4ndreaSt4gi) que ha estado trabajando fuertemente con nosotros en el código de Turpial y muchas otras colaboraciones, donaciones e incluso noticias y artículos en blogs de todo el mundo.

Podemos asegurarle a la comunidad lo siguiente:

  • No nos estamos vendiendo a una corporación maligna del imperio que usará Turpial como herramienta para subyugar a los pueblos oprimidos.
  • No estamos dejando de dar soporte en español.
  • Vamos a seguir mejorando Turpial en español, inglés, portugués, chino, alemán y en todos los idiomas que podamos (con la ayuda de la comunidad).

Pueden revisar el Timeline de Turpial y se darán cuenta que respondemos preguntas en ambos idiomas pero nuestra plataforma está y seguirá estando en inglés porque en este momento somos pocas personas aportando al código de Turpial y humanamente el tiempo no nos alcanza para también traducir y mantener la plataforma.

Estamos completamente abiertos a recibir colaboraciones para traducir la plataforma, en ningún momento nos hemos cerrado a esa posibilidad, simplemente no nos alcanza el tiempo. Nuestra amiga Nathalie Colina (@Art3mis4) estuvo con ganas de aportar en esto de las traducciones, si están interesados pueden contactarla y tratar de coordinar para que empiecen cuando quieran.



Veremos Turpial en otras plataformas como moviles incluso en otros sistemas operativos? y de ser así, seguirá siendo libre?

Por supuesto. Estamos trabajando para que la versión 2 esté disponible para Windows y para Mac. Luego tenemos planes de portar Turpial 3 para Android, iPhone e incluso Chrome (y Firefox, ¿por qué no?).

Turpial es y seguirá siendo libre. Esa es nuestra consigna y es parte del Zen de Turpial.



¿Se extenderá Turpial a otras redes sociales como el chat de Facebook, IRC o algo de ese estilo?

Por los momentos el único soporte oficial que tenemos es para Twitter e Identi.ca. Sin embargo, estuvimos en conversaciones con César Cotiz para incluir soporte oficial a Plaxed y estamos analizando el soporte para Status.net. Estas dos redes muy probablemente estarán en versiones futuras.

Para el resto de redes sociales estaremos intentando habilitar un sistema de plugins que permita extender la aplicación, pero por nuestra parte no tenemos intenciones de agrandar más el core de Turpial.



¿Cual es la funcionalidades de Turpial que la gente menosprecia mas o que la mayoría desconoce?

La característica que la gente más denigra es la interfaz gráfica, sobre todo la imposibilidad de hacer clic directamente en los enlaces, hashtags o perfiles. Lamentablemente Gtk tiene sus limitaciones y tuvimos que ajustarnos a ellas, es por eso que Turpial 2.0 fue pensado con base en Webkit y así hemos venido trabajando. El cambio en apariencia es simplemente enorme.


¿Cuantas personas trabajan en este proyecto, esas que tu considerarias "Core contributors"?

Actualmente tres: Carlos Guerrero (@guerrerocarlos), Andrea Stagi (@4ndreaSt4gi) y yo (@satanas82).


¿Como pudieran identi.ca y twitter colaborar con Turpial?

Es una pregunta bastante difícil, creo que la mejor forma de colaborar con Turpial (y con cualquier cliente de terceras partes) es tratando de mantener una API estable a lo largo del tiempo y minimizando los controles o reglas que establecen para los terceros.



Aprovechando un la oportunidad aproveche de hacerle unas preguntas un poco mas personales y ya dejando a Turpial de lado, aquí les dejo esta segunda parte de la entrevista a Wil Alvarez.

¿A que edad y como aprendiste a programar?

Empecé a los 18 años. Mi sueño siempre fue hacer juegos de computadoras y por eso aprendí. En una época desarrollé unos cuantos juegos usando Pygame pero aún no siento mi sueño realizado.


¿Que es lo que mas te consume tiempo de Turpial, esas tareas que quisieras delegar?

Principalmente las que yo llamo "tareas administrativas o de relaciones públicas". Todo lo que es responder correos, atender consultas, escribir noticias, artículos de la wiki; son cosas que me gusta hacerla, sobre todo responder correos, pero el tiempo no me da para todas. Me gusta responder a los usuarios porque de esa forma se rompe un poco esa barrera entre el usuario y el programador, le demuestro a la gente que estamos a la distancia de un correo, que los escuchamos y que realmente nos interesa y nos nutren sus opiniones.


¿Trabajas en otros proyectos que nos puedas comentar un poco?

En estos momentos mi empleo me está consumiendo gran parte del tiempo así que no he podido dedicarme a otras cosas. Tengo pendientes un par de proyectos y algunos juegos (sobre todo cosas tipo frameworks) para generar aplicaciones pero todo eso está en stand-by.

¿identi.ca o Twitter?

Twitter.


¿Entiendo que actualmente estas en Argentina, como ves la movida del software libre y la comunidad por alla?

Bueno, estuve en Argentina hasta hace una semana (ahora estoy en Chile) pero la movida del SL es muy interesante, la comunidad de Python de Argentina es una de las más activas que he podido conocer y tiene un montón de desarrolladores de gran nivel (o "grosos", como dirían allá). También tienen una comunidad de Mozilla bastante activa y pues, el SL se mueve un montón allá.