Análise de sentimento no Twitter em Python
A análise de sentimento no Twitter classifica cada tweet como positivo, negativo ou neutro com um modelo de pontuação. Em 12,3 mil tweets rotulados por pessoas, um modelo RoBERTa treinado com tweets acertou 72,3%; as regras populares do VADER acertaram 53,0%.
Resposta curta: Colete uma amostra de tweets com uma consulta de busca e depois pontue cada um: um modelo transformer é o pontuador mais preciso, e o VADER o mais rápido. A API oficial do X cobra US$ 5,00 por 1.000 posts pela coleta. Com a Sorsa API, o POST /search-tweets devolve cerca de 20 tweets por requisição a partir de US$ 0,07 por 1.000, e 100 requisições grátis cobrem uma primeira execução de 2.000 tweets.
- Endpoint
POST /search-tweets- Tamanho da página
- cerca de 20 tweets por requisição
- Preço
- a partir de US$ 0,07 por 1.000
#Como funciona a análise de sentimento no Twitter
A análise de sentimento lê o texto de um tweet e devolve um de três rótulos, em geral com uma pontuação de confiança, e depois conta os rótulos em algumas centenas ou alguns milhões de tweets para medir o que as pessoas sentem sobre um assunto. Todo projeto segue os mesmos cinco passos:
-
Colete os tweets que mencionam o assunto, com uma consulta de busca e uma janela de datas.
-
Limpe o texto: substitua @menções e links, descarte retweets e cópias.
-
Pontue cada tweet com um modelo: positivo, neutro ou negativo.
-
Confira o modelo em algumas centenas de tweets que você mesmo rotulou.
-
Agregue os rótulos em um número por dia, por produto ou por conta.
O modelo pontua cada tweet por conta própria; o número que você relata vem da soma dos rótulos.
As marcas usam a análise nas menções depois de um lançamento ou de uma queda, as equipes de suporte nas respostas aos seus posts, os analistas num ticker ou num token, e os pesquisadores num debate ou numa eleição. Ela mede para onde uma multidão pende, não o que uma pessoa quis dizer: um modelo lê as palavras, então sarcasmo e tweets ambíguos ("great camera, awful battery") são onde ele mais falha.
Duas decisões moldam o resultado mais do que qualquer outra coisa: quais tweets você coleta e em qual pontuador você confia. As próximas seções tratam delas nessa ordem.
#Pegue os tweets com a Sorsa API
Para a etapa de coleta, use a Sorsa API, uma API e scraper do Twitter (X): uma requisição de busca devolve cerca de 20 tweets com toda a sintaxe de busca do X, a partir de US$ 0,07 por 1.000 tweets, a 20 requisições por segundo em todos os planos. Você precisa de uma chave de API e de nenhuma conta de desenvolvedor do X, e a Sorsa API nunca pede um login do X, então nenhuma conta sua corre risco.
Escolha o endpoint pela pergunta que você faz:
- Opinião sobre um assunto, produto ou marca:
POST /search-tweets(abre em uma nova aba). - O que as pessoas dizem a uma conta ou sobre ela, com mínimo de curtidas ou respostas:
POST /mentions(abre em uma nova aba), explicado no nosso guia da API de menções do Twitter. - Reações sob um post:
POST /comments(abre em uma nova aba), as mesmas respostas que o nosso guia sobre como ver comentários no X lê. - IDs de tweets que você já tem:
POST /tweet-info-bulk(abre em uma nova aba), 100 tweets por requisição, a partir de US$ 0,014 por 1.000.
-
Pegue uma chave. Cadastre-se e copie a sua chave de API no painel. As primeiras 100 requisições são grátis, sem cartão.
-
Escreva a consulta. Dê forma à amostra antes de pagar por ela:
lang:enmantém um idioma para um modelo em inglês,-filter:retweetsdescarta cópias,-from:deixa de fora os posts da própria marca, esince:comuntil:fixa a janela. A nossa lista de operadores de busca do Twitter tem o resto, e a ferramenta grátis Busca avançada do Twitter mostra o que uma consulta devolve antes de você escrever código. -
Envie uma requisição de teste. Uma requisição devolve cerca de 20 tweets e um cursor para a página seguinte. Um cursor é um token que aponta para a próxima página de resultados.
Terminal curl -X POST "https://api.sorsa.io/v3/search-tweets" \ -H "ApiKey: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"order": "latest", "query": "\"battery life\" headphones lang:en -filter:retweets"}'Response200 OK { "tweets": [ { "id": "2116943508275302411", "full_text": "Two full days of battery on these headphones", "created_at": "2026-11-01T18:42:09Z", "lang": "en", "is_reply": false, "likes_count": 31, "reply_count": 4, "retweet_count": 2, "user": { "id": "1834470112963551232", "username": "nadia_reviews_gear", "followers_count": 2318 } } ], "next_cursor": "DAADDAABCgABHWAk1xBVYAoKAAIdYCTSHxWQ" } -
Reúna as páginas numa tabela. Devolva o
next_cursoraté ele voltar vazio e guarde uma linha por ID de tweet. Um 429 significa mais de 20 requisições em um segundo, então espere e tente de novo; um 403 significa chave ausente ou sem requisições.Python import time import pandas as pd import requests URL = "https://api.sorsa.io/v3/search-tweets" HEADERS = {"ApiKey": "YOUR_API_KEY"} def collect(query, limit=2000): body = {"query": query, "order": "latest"} rows = {} while len(rows) < limit: r = requests.post(URL, headers=HEADERS, json=body, timeout=30) if r.status_code == 429: time.sleep(1) continue r.raise_for_status() page = r.json() for t in page.get("tweets", []): rows[t["id"]] = { "id": t["id"], "created_at": t["created_at"], "text": t["full_text"], "lang": t.get("lang"), "is_reply": t.get("is_reply", False), "likes": t.get("likes_count", 0), "author": t["user"]["username"], } if not page.get("next_cursor"): break body["next_cursor"] = page["next_cursor"] return pd.DataFrame(rows.values()) df = collect('"battery life" headphones lang:en -filter:retweets') print(len(df), "tweets")
Quanto custam os tweets
Na Sorsa API uma amostra de sentimento custa a partir de US$ 0,07 por 1.000 tweets pela busca; a API oficial do X cobra US$ 5,00 por 1.000 leituras de posts.
API oficial do X
US$ 500
para 100 mil tweets
US$ 0,005 por post
Sorsa API
a partir deUS$ 7
para 100 mil tweets
a partir de US$ 0,07 por 1.000
Na API oficial do X a conta também cresce com os autores: a partir de 22 de novembro de 2026, o X cobra o perfil devolvido com cada post como uma leitura de usuário, US$ 0,010 a mais por post (aviso do X (abre em uma nova aba)), e o plano de pagamento por uso dela para em 3 milhões de leituras de posts por mês (lista de preços do X (abre em uma nova aba)). Na Sorsa API todo tweet traz o perfil completo do autor, e requisições com falha nunca são cobradas.
As páginas de uma consulta vêm uma depois da outra, porque cada uma precisa do cursor da anterior. Para uma amostra grande, divida a janela em dias e rode os dias lado a lado, até 20 requisições por segundo com uma chave. A mesma busca volta até 2006, o que o nosso guia de dados históricos do Twitter cobre para séries temporais longas.
#Limpe os tweets do jeito que o modelo espera
Limpe menos do que a maioria dos tutoriais: substitua @menções por @user e links por http, descarte retweets e cópias exatas, e mantenha emojis, letras maiúsculas e pontuação. O modelo RoBERTa foi treinado com texto preparado exatamente assim, e o VADER lê maiúsculas, pontos de exclamação e emojis como sentimento mais forte.
import re
def prepare(text):
text = re.sub(r"@\w+", "@user", text)
return re.sub(r"https?://\S+", "http", text)
df = df[df["lang"] == "en"]
df = df[~df["text"].str.startswith("RT @")]
df["clean"] = df["text"].map(prepare)
df = df.drop_duplicates(subset="clean")
As cópias exatas importam mais do que parece: sorteios e campanhas de bots publicam a mesma frase centenas de vezes, e uma única campanha pode virar a pontuação de um dia. Para quase-duplicatas e um conjunto de referência com rótulos manuais, o nosso guia para montar um dataset do Twitter para machine learning tem o código.
Bom saber
A regex de limpeza que muitos tutoriais copiam,
[^a-zA-Z0-9\s], apaga todos os emojis e todos os pontos de exclamação. Os dois carregam sentimento: nos exemplos do próprio VADER, uma linha com três emojis e nenhuma outra palavra de opinião pontua +0,70.
#Quatro jeitos de pontuar sentimento, testados em 12,3 mil tweets
No conjunto de teste de sentimento do TweetEval, 12,3 mil tweets que pessoas rotularam como positivos, neutros ou negativos, o modelo RoBERTa acertou 72,3%, uma regressão logística treinada com 45,6 mil tweets rotulados 59,6%, o VADER 53,0% e o TextBlob 48,3%. Rodamos os quatro em 2 de novembro de 2026, em 4 threads de CPU; a tabela traz as pontuações completas.
| Método | Acurácia | Recall macro | Chamados de positivos (pessoas: 19,3%) | Tweets por segundo |
|---|---|---|---|---|
| RoBERTa (cardiffnlp, latest) | 72,3% | 73,4% | 20,0% | 7 |
| TF-IDF + regressão logística | 59,6% | 60,1% | 21,1% | 34,0 mil |
| VADER, faixa de ±0,05 | 53,0% | 57,0% | 38,9% | 27,6 mil |
| TextBlob, sinal da polaridade | 48,3% | 49,4% | 37,2% | 6.867 |
RoBERTa (cardiffnlp, latest)
- Acurácia
- 72,3%
- Recall macro
- 73,4%
- Chamados de positivos (pessoas: 19,3%)
- 20,0%
- Tweets por segundo
- 7
TF-IDF + regressão logística
- Acurácia
- 59,6%
- Recall macro
- 60,1%
- Chamados de positivos (pessoas: 19,3%)
- 21,1%
- Tweets por segundo
- 34,0 mil
VADER, faixa de ±0,05
- Acurácia
- 53,0%
- Recall macro
- 57,0%
- Chamados de positivos (pessoas: 19,3%)
- 38,9%
- Tweets por segundo
- 27,6 mil
TextBlob, sinal da polaridade
- Acurácia
- 48,3%
- Recall macro
- 49,4%
- Chamados de positivos (pessoas: 19,3%)
- 37,2%
- Tweets por segundo
- 6.867
A acurácia é a parcela de tweets rotulados do mesmo jeito que as pessoas os rotularam. Para ter uma escala, chamar todos os tweets de neutros dá 48,3%, porque quase metade dos tweets de teste é neutra, então o VADER acrescenta menos de 5 pontos sobre não fazer nada. O recall macro é a pontuação do próprio TweetEval: a média de quantos tweets negativos, neutros e positivos cada método encontrou, de modo que um método não ganha chamando tudo de neutro. Duas ressalvas: o modelo RoBERTa foi ajustado na divisão de treino do TweetEval, então este teste é o campo de casa dele, e a regressão logística aprendeu da mesma divisão. No seu próprio assunto, espere que ambos percam alguns pontos e confira-os como diz o passo 4. As velocidades vêm de um servidor compartilhado de 4 núcleos que estava ocupado com outros trabalhos, então trate-as como um piso.
RoBERTa: o mais preciso
O modelo twitter-roberta-base-sentiment-latest (abre em uma nova aba) da Cardiff NLP é um modelo RoBERTa treinado com cerca de 124 milhões de tweets de 2018 a 2021 e depois ajustado para três rótulos. Ele roda numa CPU comum e não precisa de chave de API; na velocidade que medimos num servidor ocupado, 10 mil tweets levam cerca de 23 minutos, então rode-o em lotes durante a noite ou numa GPU para amostras grandes.
from transformers import pipeline
scorer = pipeline(
"sentiment-analysis",
model="cardiffnlp/twitter-roberta-base-sentiment-latest",
)
out = scorer(df["clean"].tolist(), batch_size=32, truncation=True)
df["label"] = [o["label"] for o in out]
df["confidence"] = [round(o["score"], 3) for o in out]
positive 0.978 Battery life on these headphones is great, two full days
positive 0.859 Oh great, another update that breaks Bluetooth. Love ...
neutral 0.789 The firmware update rolls out to all devices on Monday.
positive 0.960 not bad at all tbh, @user was right http
negative 0.860 @user oh great, the update broke Bluetooth AGAIN http
Para tweets em outros idiomas, o modelo twitter-xlm-roberta-base-sentiment (abre em uma nova aba) da mesma equipe foi treinado com cerca de 198 milhões de tweets e ajustado em 8 idiomas, entre eles espanhol, português, francês e árabe. Para emoções em vez de polaridade, o modelo de emoções deles devolve 11 rótulos, como raiva, medo e alegria.
VADER: regras instantâneas, uma faixa neutra fraca
O VADER é uma lista de cerca de 7.500 palavras pontuadas mais regras para maiúsculas, pontos de exclamação, "but" e negação, feita para redes sociais. Ele pontuou cerca de 27,6 mil tweets por segundo num único núcleo, o que o torna uma boa primeira olhada em um milhão de tweets. O ponto fraco dele é a faixa neutra: chamou 38,9% dos tweets de teste de positivos, o dobro dos 19,3% das pessoas.
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
vader = SentimentIntensityAnalyzer()
def vader_label(text, band=0.05):
c = vader.polarity_scores(text)["compound"]
if c >= band:
return "positive"
return "negative" if c <= -band else "neutral"
df["vader"] = df["text"].map(vader_label)
| Tweet | VADER (compound) | RoBERTa |
|---|---|---|
| Battery life on these headphones is great, two full days | positivo (+0,62) | positivo (0,98) |
| Oh great, another update that breaks Bluetooth. Love that for me. | positivo (+0,85) | positivo (0,86) |
| The firmware update rolls out to all devices on Monday. | neutro (+0,00) | neutro (0,79) |
| not bad at all tbh, @kai_builds_tools was right https://t.co/x1y2z3 (abre em uma nova aba) | positivo (+0,43) | positivo (0,96) |
| @nadia_reviews_gear oh great, the update broke Bluetooth AGAIN https://t.co/k3v9q2 (abre em uma nova aba) | positivo (+0,32) | negativo (0,86) |
Battery life on these headphones is great, two full days
- VADER (compound)
- positivo (+0,62)
- RoBERTa
- positivo (0,98)
Oh great, another update that breaks Bluetooth. Love that for me.
- VADER (compound)
- positivo (+0,85)
- RoBERTa
- positivo (0,86)
The firmware update rolls out to all devices on Monday.
- VADER (compound)
- neutro (+0,00)
- RoBERTa
- neutro (0,79)
not bad at all tbh, @kai_builds_tools was right https://t.co/x1y2z3 (abre em uma nova aba)
- VADER (compound)
- positivo (+0,43)
- RoBERTa
- positivo (0,96)
@nadia_reviews_gear oh great, the update broke Bluetooth AGAIN https://t.co/k3v9q2 (abre em uma nova aba)
- VADER (compound)
- positivo (+0,32)
- RoBERTa
- negativo (0,86)
O sarcasmo derrota os dois pontuadores algumas vezes. Os dois leem "Love that for me" como elogio; o RoBERTa percebeu o sarcasmo no último tweet, onde o VADER viu "great" e o pontuou como positivo.
Regressão logística: treine com os seus próprios rótulos
Um modelo TF-IDF com regressão logística aprende com tweets que você mesmo rotula, então se ajusta às palavras do seu assunto: "sick" numa thread de tênis, "bullish" numa de cripto. Treinado com 45,6 mil tweets do TweetEval em 13 segundos, chegou a 59,6%. Compensa quando você tem alguns milhares de rótulos e um vocabulário que os modelos gerais não conhecem.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
model = make_pipeline(
TfidfVectorizer(ngram_range=(1, 2), min_df=2,
sublinear_tf=True),
LogisticRegression(max_iter=2000,
class_weight="balanced"),
)
model.fit(train_texts, train_labels)
df["lr"] = model.predict(df["clean"])
O TextBlob, o quarto método, pontua um léxico de adjetivos em inglês que os autores dele testaram em críticas de filmes, e só chama um tweet de neutro quando a polaridade é exatamente zero. Ele fez 48,3%, o mesmo que chamar todos os tweets de neutros, então não acrescenta nada em tweets. Um modelo de linguagem grande é uma quinta opção: com o tweet e os três rótulos no prompt, ele pode captar sarcasmo que as listas de palavras perdem, mas custa dinheiro por tweet e pode responder diferente numa nova execução. Confira-o com a mesma amostra rotulada à mão antes de confiar nele num dataset inteiro.
#A faixa neutra decide a sua manchete
Com o VADER, o limiar que você escolhe move o resultado mais do que os tweets. Na faixa de ±0,05 da documentação do VADER, ele chama 38,9% dos tweets de teste de positivos; amplie a faixa para ±0,45 e a parcela de positivos cai para 21,4% enquanto a acurácia sobe para 58,1%. Mova o controle deslizante para ver cada passo.
Barras: a parcela do VADER em cada rótulo. Linha: a parcela dada por avaliadores humanos. Conjunto de teste de sentimento TweetEval, 12.3K tweets, pontuados em Nov 2, 2026.
Os mesmos 12.3K tweets, pontuados uma vez pelo VADER; só a faixa neutra muda.
Relate o método e o limiar com cada número que publicar, e nunca compare parcelas de dois pontuadores diferentes. Se você usar o VADER, ajuste a faixa em algumas centenas de tweets do seu próprio assunto que você rotulou à mão.
#Transforme rótulos em um índice que você possa acompanhar
O número que a maioria das equipes acompanha é o sentimento líquido: a parcela de tweets positivos menos a de negativos, de -100 a +100. Calcule-o por dia e deixe de fora os dias com menos de cerca de 100 tweets, em que um punhado de posts pode virar o índice.
df["day"] = pd.to_datetime(df["created_at"]).dt.date
shares = pd.crosstab(df["day"], df["label"], normalize="index")
daily = pd.DataFrame({
"tweets": df.groupby("day").size(),
"net": ((shares["positive"] - shares["negative"]) * 100).round(1),
})
print(daily[daily["tweets"] >= 100])
Mantenha separadas as respostas e os posts originais (o campo is_reply), porque as reclamações se concentram nas respostas aos posts da própria marca. Pondere os tweets por curtidas só de propósito, e diga isso ao lado do gráfico. Para manter o índice atualizado, rode a coleta em intervalos regulares com since: definido como a última execução; o nosso guia de monitoramento do Twitter em tempo real cobre o polling em escala.
#Faça hoje a sua primeira análise de sentimento
Colete alguns milhares de tweets sobre o seu assunto com o POST /search-tweets da Sorsa API, cerca de 20 por requisição a partir de US$ 0,07 por 1.000, pontue-os com o modelo RoBERTa e confira os rótulos em 200 tweets seus. As 100 requisições grátis de uma conta nova cobrem os primeiros 2.000 tweets.
#FAQ
Qual é a precisão da análise de sentimento no Twitter?
Depende do modelo. Em 12,3 mil tweets rotulados por pessoas (o conjunto de teste do TweetEval), o modelo RoBERTa da Cardiff NLP rotulou 72,3% corretamente, uma regressão logística treinada com 45,6 mil tweets 59,6%, o VADER 53,0% e o TextBlob 48,3%. Sarcasmo, opiniões ambíguas e gírias do assunto causam a maioria dos erros, então confira qualquer modelo em algumas centenas de tweets do seu próprio assunto.
Como obtenho tweets para análise de sentimento?
Busque-os por uma API com uma consulta e uma janela de datas. O POST /search-tweets da Sorsa API aceita os operadores de busca do X, devolve cerca de 20 tweets por requisição com texto completo e autor, e custa a partir de US$ 0,07 por 1.000 tweets. A API oficial do X exige uma conta de desenvolvedor e cobra US$ 5,00 por 1.000 leituras de posts. Para um conjunto já rotulado para treinar, veja datasets públicos como o TweetEval.
Qual API do Twitter devo usar para análise de sentimento?
Use a Sorsa API para coletar os tweets: ela devolve cerca de 20 tweets por requisição de busca a partir de US$ 0,07 por 1.000, contra US$ 5,00 na API oficial do X, com toda a sintaxe de busca do X até 2006, uma chave de API e nenhuma conta de desenvolvedor, e 20 requisições por segundo em todos os planos. A pontuação então roda no seu próprio código, com o modelo que você escolher.
Dá para fazer análise de sentimento no Twitter de graça?
Sim, para um primeiro projeto. O VADER, o TextBlob e os modelos RoBERTa da Cardiff NLP são grátis e rodam num notebook. Para os tweets, toda conta nova da Sorsa API ganha 100 requisições grátis: cerca de 2.000 tweets pela busca, sem cartão, e elas nunca expiram. Conjuntos de referência rotulados, como o TweetEval, podem ser baixados de graça para testar um modelo.
Dá para analisar tweets em outros idiomas?
Sim, com um modelo multilíngue. O twitter-xlm-roberta-base-sentiment da Cardiff NLP foi treinado com cerca de 198 milhões de tweets e ajustado para sentimento em 8 idiomas, entre eles espanhol, português, francês e árabe. O VADER e o modelo RoBERTa em inglês leem só inglês, então filtre por idioma com o operador lang: na sua consulta e o campo lang de cada tweet.
A Sorsa API devolve uma pontuação de sentimento?
Não: a Sorsa API devolve os tweets, com texto completo, idioma, contagens de engajamento e autor, e a pontuação roda no seu código. Isso deixa a escolha do modelo com você, e você pode repontuar tweets antigos quando sair um modelo melhor. A Sorsa API se chamava TweetScout API até 2025; os endpoints de tweets e de busca funcionam do mesmo jeito.
#Como conferimos
Em 2 de novembro de 2026 baixamos os dados de sentimento do TweetEval do repositório da Cardiff NLP e pontuamos o conjunto de teste de 12,3 mil tweets com o VADER 3.3.2, o TextBlob 0.20.1, um modelo TF-IDF com regressão logística (scikit-learn 1.9.1) treinado nos 45,6 mil tweets de treino e o twitter-roberta-base-sentiment-latest (transformers 5.22.1, PyTorch 2.15 em 4 threads de CPU); as saídas de exemplo desta página vêm da mesma execução. Os formatos de requisição e resposta seguem a referência de API da Sorsa em produção, e os preços da API oficial do X vêm de docs.x.com, lido no mesmo dia.
Sources
- TweetEval benchmark and data, Cardiff NLP (abre em uma nova aba)
- twitter-roberta-base-sentiment-latest model card (abre em uma nova aba)
- twitter-xlm-roberta-base-sentiment model card (abre em uma nova aba)
- VADER sentiment README (abre em uma nova aba)
- X API pricing (abre em uma nova aba)
- X notice on billing post expansions, Oct 2026 (abre em uma nova aba)
- Sorsa API reference: Search Tweets (abre em uma nova aba)