Commit a357aa8d authored by Dr. Daniel Diaz Sánchez's avatar Dr. Daniel Diaz Sánchez
Browse files

Update README.md

parent c3d499c4
......@@ -455,119 +455,119 @@ Observa, depurando paso a paso y usando break points (en ocasiones entrar dentro
### Peticiones con cursores
La función del API descrita en https://dev.twitter.com/rest/reference/get/statuses/user_timeline tiene un límite de 300 peticiones cada 15 minutos. Pero por lo general tiene un límite total de 3200 tweets por cuenta consultada (los 3200 últimos).
La función del API descrita en https://dev.twitter.com/rest/reference/get/statuses/user_timeline tiene un límite de 300 peticiones cada 15 minutos. Pero por lo general tiene un límite total de 1500 tweets por cuenta consultada (los 1500 últimos). Esto varía bastante, por lo que es recomendable leer https://developer.twitter.com/en/docs/twitter-api/v1/rate-limits.
Pese a la limitación dura de 3200, en cada petición se pueden pedir como máximo 200 (parámetro `count` de la llamada al API)
Pese a la limitación, en cada petición se pueden pedir como máximo 200 (parámetro `count` de la llamada al API)
El problema es que los API REST no tienen estado, entonces, **¿cómo bajar los 3200 tweets?**
El problema es que los API REST no tienen estado, entonces, **¿cómo bajar los más de 200 tweets?**
Para ello, es necesario usar **cursores**, elementos que le informen a Twitter a partir de qué Tweet deseas obtener los siguientes 200.
Para ello utilizamos el parámetro `max_id` de la petición, usando la información contenida aquí https://dev.twitter.com/rest/public/timelines
Usemos una cuenta popular, cualquiera con más de 3200 Tweets. Para ello usa cualquiera de las más populares del mundo (yo voy a usar `@realmadrid`).
Usemos una cuenta popular, cualquiera con más de 200 Tweets. Para ello usa cualquiera de las más populares del mundo (yo voy a usar `@realmadrid`).
De todos los tweets recibidos, hay que buscar cuál de ellos tiene menor id y usarlo como parámetro (restándole 1) para la siguiente petición.
```java
package cdistRest;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import com.google.gson.Gson;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.GetRequest;
import com.mashape.unirest.request.body.RequestBodyEntity;
import kong.unirest.GetRequest;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
public class TwitterCrawler {
private static final String oauth_consumer_key = "XXXXXXXXx";
private static final String oauth_consumer_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
private static final String bearer_token = "xxxxxx";
private static final int MAX_TWEET_COUNT_PER_REQUEST = 200;
private long max_id = Long.MAX_VALUE;
private long tweetcount = 0;
private String screen_name = "";
private long pending = 0;
public class BearerToken
public TwitterCrawler(int count, String screen_name )
{
private String access_token;
private String token_type;
this.tweetcount = count;
this.screen_name = screen_name;
}
public static String deserializeJson(String input_json)
{
Gson gson = new Gson();
BearerToken new_bearerToken = gson.fromJson(input_json, BearerToken.class);
return new_bearerToken.access_token;
}
public List<Tweet> gettweets() {
/*
* si los tweets caben en una sóla petición, o bien se piden más de
* MAX_TWEET_COUNT_PER_REQUEST en principio la primera petición hay que hacerla
* para obtener el max_id (máximo id de la secuencia de tweets)
*/
List<Tweet> tweet_list_total = new ArrayList<Tweet>();
pending = tweetcount;
long max_id = Long.MAX_VALUE;
do {
long request_twetcount = 0;
long tweets_obtained = 0;
if (pending > MAX_TWEET_COUNT_PER_REQUEST) {
request_twetcount = MAX_TWEET_COUNT_PER_REQUEST;
} else {
request_twetcount = pending;
}
HttpResponse<String> json_str_Response = null;
GetRequest getReq = null;
getReq = Unirest.get(
"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={screen_name}&count={count}&max_id={max_id}")
.routeParam("screen_name", screen_name).routeParam("count", "" + request_twetcount)
.routeParam("max_id", ""+(max_id-1))
.header("Authorization", "Bearer " + bearer_token);
System.out.println("Request " + request_twetcount + " tweets to: " + getReq.getUrl());
json_str_Response = getReq.asString();
List<Tweet> tweet_list_request = Tweet.deserializeJsonArray(json_str_Response.getBody());
tweets_obtained = tweet_list_request.size();
System.out.println("received " + tweets_obtained + " tweets");
/* actualizamos tweetcount con los recibidos */
pending -= tweets_obtained;
/* actualizamos la lista total de tweets */
tweet_list_total.addAll(tweet_list_request);
public static void main(String args[]) throws IOException {
try {
/* get bearer token according to https://dev.twitter.com/oauth/application-only */
String URLEncoderConsumerKey = URLEncoder.encode(oauth_consumer_key, "UTF-8");
String URLEncoderConsumerSecret = URLEncoder.encode(oauth_consumer_secret, "UTF-8");
String AuthorizationHeader = URLEncoderConsumerKey+":"+URLEncoderConsumerSecret;
String AuthorizationHeaderB64 = Base64.encodeBase64String(AuthorizationHeader.getBytes("UTF8"));
System.out.println(AuthorizationHeaderB64);
RequestBodyEntity postReq = Unirest.post("https://api.twitter.com/oauth2/token")
.header("User-Agent","TwitterApp")
.header("host", "api.twitter.com")
.header("Authorization", "Basic " + AuthorizationHeaderB64)
.header("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
.body("grant_type=client_credentials");
HttpResponse<String> res = postReq.asString();
String bearer_token = TwitterCrawler.deserializeJson(res.getBody());
/*
* PARADA
* si hemos hemos recibido en total de tweets, paramos
*/
if(pending <= 0) break;
/* we now have a brearer token so can make requests to Twitter */
/* PRIMEROS 200 tweets */
/* https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=realmadrid&count=200 */
HttpResponse<String> json_str_Response = null;
GetRequest getReq = null;
getReq = Unirest.get("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={screen_name}&count={count}")
.routeParam("screen_name","realmadrid")
.routeParam("count","200")
.header("Authorization", "Bearer " + bearer_token);
System.out.println("Request to: " + getReq.getUrl());
System.out.println("Authorization header Bearer " + bearer_token);
json_str_Response = getReq.asString();
System.out.println("Json : " + json_str_Response.getBody());
List<Tweet> tweet_list = Tweet.deserializeJsonArray(json_str_Response.getBody());
/* buscamos ahora entre los tweets descargados para averiguar el lowest ID dado que
-la petición por defecto (sin el parámetro max_id) devuelve los últimos 200 (si count=200)
-los últimos tweets tienen los ids más altos y los más antiguos los más bajos
-hay que encontrar cual es el menor de todos para saber cual es el tweet más antiguo que hemos obtenido
*/
long max_id = Long.MAX_VALUE;
for (Tweet tw : tweet_list) {
/*
* PARADA
* si hemos hemos recibido menos de request_twetcount es que no hay más.
* Hay que finalizar
*/
if(tweets_obtained < request_twetcount) break;
for (Tweet tw : tweet_list_request) {
if (tw.id < max_id)
max_id = tw.id;
}
/* obteniedo los siguientes 200 más antiguos */
getReq = Unirest.get("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={screen_name}&count={count}&max_id={max_id}")
.routeParam("screen_name","realmadrid")
.routeParam("count","200")
.routeParam("max_id", ""+(max_id-1))
.header("Authorization", "Bearer " + bearer_token);
json_str_Response = getReq.asString();
System.out.println("Json : " + json_str_Response.getBody());
tweet_list.addAll(Tweet.deserializeJsonArray(json_str_Response.getBody()));
Unirest.shutdown();
} while (true);
return tweet_list_total;
}
public static void main(String args[]) throws IOException {
TwitterCrawler tc = new TwitterCrawler(400, "realmadrid");
tc.gettweets();
} catch (UnirestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
```
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment