Osintgram

Como usar o Osintgram: todos os comandos explicados

O Osintgram é um shell interativo preso a um único nome de usuário alvo: você o inicia com python3 main.py <target> e digita um comando por vez em um prompt "Run a command:". O comando list interno imprime 23 comandos, três a mais do que o README documenta, e todos eles estão na tabela abaixo.

18 min de leituraEquipe Osintgram

O Osintgram não é um scanner que você aponta para um nome de usuário e deixa rodando sozinho. O main.py recebe um único argumento posicional obrigatório, monta um cliente de API, imprime um banner e depois fica em loop em um prompt até você digitar quit. Todo comando se aplica a esse único alvo, e nada acontece enquanto você não digitar algo.

Inicie com python3 main.py <target> e digite os comandos no prompt Run a command: . O list interno mostra 23 comandos; o README documenta apenas 20. A gravação em arquivo vem desativada por padrão: digite FILE=y ou JSON=y antes, ou inicie com -f / -j. Os quatro comandos de coleta de contatos (fwersemail, fwingsemail, fwersnumber, fwingsnumber) fazem uma chamada de API por seguidor, sem nenhum backoff, e são justamente os que fazem você ser bloqueado.

Como funciona o shell

Este guia parte de um clone funcionando e de um config/credentials.ini preenchido; se não for o seu caso, comece por como instalar o Osintgram. No Kali vale o mesmo, com algumas armadilhas específicas da distro.

Sempre execute a partir da raiz do repositório

O src/config.py lê o config/credentials.ini como caminho relativo, então python3 ~/Osintgram/main.py target a partir do seu diretório home simplesmente não encontra credencial nenhuma. Entre no clone com cd antes. Rodar de outro lugar também é a causa documentada da issue #105, ModuleNotFoundError: No module named 'src.Osintgram'.

Na inicialização, o backend clássico imprime o banner do alvo: Logged as <you>. Target: <target> [<numeric id>], mais [PRIVATE PROFILE] quando a conta é privada e [FOLLOWING] ou [NOT FOLLOWING]. Quem imprime isso é o construtor, e é por isso que o banner aparece antes do logo em ASCII. O banner do HikerAPI é mais curto: sem linha de login, sem estado de follow. Depois vem o prompt: a string literal Run a command: , em amarelo.

O autocompletar com TAB é ligado ao dicionário de comandos pelo gnureadline no Linux e no macOS, ou pelo pyreadline no Windows, então nomes parciais são completados. Qualquer coisa que o dicionário não reconheça imprime Unknown command em vermelho; uma linha vazia apenas imprime uma linha em branco. quit e exit imprimem Goodbye! e encerram, e o Ctrl-C é capturado para fazer a mesma coisa.

Run a command: FILE=y
Run a command: JSON=y
Run a command: info
Run a command: followers
Run a command: target
Run a command: quit
O que digitar, não uma sessão capturada: o main.py imprime o prompt; o resto é o que você digita. O TAB completa nomes de comandos, mas não as opções FILE= e JSON=.

Você não fica preso ao nome de usuário com que iniciou. O comando target pergunta Insert new target username: , resolve a nova conta e reimprime o banner, sem novo login. Ele tem um defeito: o setTarget() acrescenta o nome do alvo ao diretório de saída toda vez que roda, então, depois de uma troca, seus arquivos vão parar em output/<first target>/<second target>/ em vez de uma pasta irmã.

Três formas de iniciar a ferramenta

O README documenta três modos de execução, e eles diferem em mais coisas do que só a sintaxe.

# 1. interactive shell
python3 main.py <target username>

# 2. one command, then exit
python3 main.py <target username> --command info

# 3. HikerAPI backend, no Instagram login of your own
HIKERAPI_TOKEN=<hikerapi token> python3 main.py <target username> -c info
As três formas de invocação listadas no README, com um comando real no lugar do exemplo genérico.

O modo de comando único não é apenas o shell com uma rodada já feita por você. Quando -c está definido, o main.py pula o printlogo() e o construtor suprime a linha Attempt to login..., então a saída fica bem mais silenciosa, e o photos para de perguntar quantas fotos baixar e leva tudo. O loop também é interrompido depois de exatamente uma iteração, então -c FILE=y alterna a flag e sai sem executar nada; use -f e -j no lugar.

O terceiro modo é o que mais importa em 2026. Se o config.getHikerToken() retornar qualquer coisa (vinda do campo hikerapi_token do credentials.ini ou da variável de ambiente HIKERAPI_TOKEN), o main.py instancia a HikerCLI em vez da classe clássica Osintgram, e nenhum login no Instagram acontece. A linha de inicialização passa a ser Connect to HikerAPI.... Encare esse caminho como o que ainda foi projetado para funcionar, e não como uma garantia: a issue #2664 (2026-06-21) relata que esse branch lida mal com formatos alternativos de resposta de usuário, e o HikerAPI é um terceiro pago a quem você entrega seus alvos. Se o caminho clássico de usuário e senha ainda autentica é outra questão, tratada em o Osintgram ainda funciona.

FlagO que fazObservações
-c, --commandExecuta um comando e saiSuprime o logo e a linha de login; o photos para de perguntar
-f, --fileGrava a saída em .txt durante a sessãoIdêntico a digitar FILE=y
-j, --jsonGrava a saída em JSON durante a sessãoIdêntico a digitar JSON=y
-o, --outputO texto de ajuda diz "where to store photos"Na prática substitui todo o diretório-base de saída, para qualquer tipo de arquivo
-C, --cookiesLimpa a sessão em cache antes de iniciarMesmo efeito do comando cache: o config/settings.json é redefinido para um objeto vazio
O conjunto completo de flags, lido do bloco argparse do main.py. São exatamente cinco; não existe --file-output.

Todos os comandos do Osintgram

O README lista 20 comandos. A função cmdlist(), que o list interno chama, imprime 23. Os três a mais são cache, commentdata e target, e nenhum deles aparece no bloco de comandos do README. O doc/COMMANDS.md está ainda mais atrasado: o bloco de cabeçalho dele deixa de fora fwersnumber e fwingsnumber (os dois têm seções mais abaixo) e não documenta cache, commentdata nem target em lugar nenhum. Se você quer a lista definitiva, digite list no shell ou leia o dicionário commands no main.py.

ComandoO que retornaStatus e observações
addrsLocalizações GPS marcadas nos posts do alvoQuase sempre vem vazio. Conta apenas posts com lat e lng e depois faz geocodificação reversa de cada um pelo Nominatim
cacheApaga o arquivo de sessão em cacheSó local, sem chamada de rede. Imprime Cache Cleared. ou Settings.json don't exist.; no HikerAPI ele apenas diz Cache is already empty.
captionsLegendas dos posts do alvoA exportação em JSON grava no nome de arquivo errado (veja abaixo)
commentdataTodos os comentários de todos os posts, com id e nome de usuário do autorNão documentado no README. A exportação em JSON sai malformada
commentsNúmero total de comentários em todos os postsPercorre o feed inteiro para contar
followersLista de seguidores: id, nome de usuário, nome completoSem tratamento de throttle: um limite de taxa aqui aparece como traceback cru
followingsContas que o alvo segueA mesma ausência de tratamento do followers
fwersemailE-mails públicos publicados pelos seguidores do alvoUma chamada de API extra por seguidor. O grande ímã de throttle
fwingsemailE-mails públicos das contas que o alvo segueO mesmo formato de uma chamada por usuário
fwersnumberTelefones públicos dos seguidores do alvoO mesmo formato, mais um nome de arquivo JSON escrito errado
fwingsnumberTelefones públicos das contas que o alvo segueO mesmo formato
hashtagsHashtags que o alvo usaPassa pelo feed inteiro
infoMetadados do perfil como rótulos entre colchetesUm dos poucos comandos que passa por cima da trava de perfil privado. Ignora o FILE=y: só grava JSON
likesNúmero total de curtidas em todos os postsPassa pelo feed inteiro
mediatypeQuantos posts são fotos e quantos são vídeosPassa pelo feed inteiro
photodesDescrições em texto alternativo das fotosMorto. Chama o endpoint web ?__a=1, já aposentado; o caminho do HikerAPI responde Instagram has disabled this functionality.
photosBaixa os posts como .jpg na pasta de saídaPergunta a quantidade; com -c leva tudo. Enumera o feed inteiro antes de aplicar o limite
propicBaixa a foto de perfilTambém passa por cima da trava de perfil privado
storiesBaixa os stories ativos no momento como .jpg ou .mp4KeyError: 'media_count' é relatado quando o payload do reel não traz a chave
taggedUsuários que o alvo marcou nos próprios postsSem trava explícita, mas ele lê o feed, então ainda precisa de acesso a ele
targetTroca para um novo alvo sem reiniciarNão documentado no README. Aninha o diretório de saída a cada troca
wcommentedUsuários que comentaram nos posts, ordenados por quantidadeFeed inteiro mais uma busca de comentários por post, lento em contas ativas
wtaggedUsuários que marcaram o alvo, ordenados por quantidadeLê o feed de marcações; o loop de paginação dele passa para o feed do alvo
As descrições parafraseiam as strings que cmdlist() imprime. O status foi lido de main.py, src/Osintgram.py e src/hikercli.py, além do issue tracker público; não rodamos a CLI contra uma conta real do Instagram.

Outras quatro entradas do dicionário não são comandos de dados: list e help imprimem essa mesma lista, quit e exit encerram. Duas entradas são tratadas completamente fora do dicionário (FILE=y/n e JSON=y/n), e é por isso que o TAB nunca as completa.

Uma ressalva vale para a tabela inteira: nada retorna dados se o backend não conseguir autenticar. Toda linha pressupõe que você passou do login, seja com uma sessão que o cliente clássico aceite, seja com um token do HikerAPI. Em 2026, não são os comandos que quebram primeiro.

Lendo a saída do info

O info é o comando que você vai rodar primeiro e o que tem mais chance de te enganar. Ele chama o endpoint privado users/{user_id}/full_detail_info/, lê content['user_detail']['user'] e imprime uma sequência fixa de rótulos entre colchetes:

  • [ID], [FULL NAME], [BIOGRAPHY]: sempre impressos
  • [FOLLOWED], [FOLLOW]: sempre impressos, e não são o que parecem
  • [BUSINESS ACCOUNT] e, na sequência, [BUSINESS CATEGORY] apenas quando a conta é comercial e não escondeu a categoria
  • [VERIFIED ACCOUNT] e, na sequência, [EMAIL] apenas quando há um e-mail público definido
  • [HD PROFILE PIC]: sempre impresso, como URL
  • [FB PAGE], [WHATSAPP NUMBER], [CITY], [ADDRESS STREET], [CONTACT PHONE NUMBER]: cada um impresso apenas quando o campo está preenchido

A armadilha do [FOLLOWED] / [FOLLOW]

[FOLLOWED] é a contagem de seguidores e [FOLLOW] é a contagem de seguindo. Os rótulos parecem dizer justamente o contrário do que significam. A exportação em JSON resolve a dúvida: os mesmos dois valores são gravados nas chaves edge_followed_by e edge_follow, os nomes antigos da web API para seguidores e seguindo. Se for transcrever os números, tire-os da exportação em JSON.

O backend do HikerAPI imprime uma linha [MEDIA] a mais, com a contagem de posts que o caminho clássico nunca mostra, então o mesmo comando devolve uma lista de campos diferente em cada backend. E, quando a chamada por baixo lança uma exceção, o handler imprime Oops... <target> non exist, please enter a valid username. e sai com o código 2. É uma mensagem em que você não deveria confiar. A issue #1020 mostra o Instagram devolvendo um corpo de erro que não é JSON e a ferramenta relatando isso como usuário inexistente.

Salvando a saída e os nomes de arquivo que colidem

Nada é gravado em disco a menos que você peça. Digite FILE=y para saída em texto e JSON=y para JSON em qualquer momento da sessão; a ferramenta confirma com Write to file: enabled e Export to JSON: enabled, e FILE=n / JSON=n desligam tudo de novo. Iniciar com -f ou -j define os mesmos booleanos antes do primeiro comando.

No master atual, os resultados vão para um subdiretório por alvo. Na tag de release 1.3 eles caíam em um output/ plano, e é por isso que guias mais antigos mostram outro layout. O arquivo .txt guarda a tabela ASCII crua do PrettyTable (file.write(str(t))), e não CSV, então não espere abri-lo em uma planilha.

output/
|-- dont_delete_this_folder.txt
`-- <target>/
    |-- <target>_followers.txt
    |-- <target>_followers.json
    |-- <target>_propic.jpg
    |-- <target>_<photo id>.jpg
    `-- <target>_<story id>.mp4
Layout de saída no master. A flag -o substitui a base "output", não apenas o caminho das imagens.

É na nomenclatura que a coisa fica bagunçada. Três comandos gravam JSON com um nome de arquivo que não corresponde ao comando digitado, um deles sobrescreve um resultado anterior e outros dois quebram o padrão cada um do seu jeito.

Comando com JSON=yArquivo que ele realmente gravaProblema
captions<target>_followings.jsonSobrescreve o arquivo que o followings gravou. Bug de copiar e colar em get_captions
photodes<target>_descriptions.jsonO nome não corresponde ao comando
fwersnumber<target>_fwerssnumber.jsonDois "s", e a chave dentro do objeto é followings_phone_numbers
commentdata<target>_comment_data.jsonEscrito à mão, com vírgula sobrando e sem separadores entre os objetos, então o json.load() falha nele
infoApenas <target>_info.jsonNão existe nenhum writer de .txt; o FILE=y não faz nada aqui
Lido dos blocos de escrita em src/Osintgram.py no master.

Não rode captions depois de followings na mesma sessão

Com JSON=y ativado, o captions grava em <target>_followings.json. Se você exportou a lista de seguindo antes, rodar o captions substitui tudo por dados de legenda, sem confirmação, sem backup e sem aviso. Exporte as legendas em outra sessão ou renomeie o dump de followings antes.

Os comandos que fazem você levar throttle

Os quatro comandos de coleta de contatos compartilham a mesma arquitetura. O get_fwersemail() primeiro pagina a lista inteira de seguidores, imprimindo um contador Catched N followers email que vai subindo. Só depois disso ele pergunta Do you want to get all emails? y/n: . Em seguida, para cada seguidor coletado, dispara uma chamada user_info separada e só guarda o registro se houver um e-mail público definido.

Daí decorrem duas consequências. Seu limite é aplicado depois da enumeração completa, então responder "n" e pedir 200 e-mails ainda percorre a lista de seguidores inteira antes. E o limite conta apenas as correspondências, então um alvo cujos seguidores raramente publicam e-mail acaba enumerado quase do começo ao fim de qualquer jeito. Não há sleep, jitter nem backoff nesses loops; a issue #657 é um patch da comunidade que adiciona um.

Pedir menos resultados não deixa a operação mais barata

A lista de seguidores é enumerada por completo antes de o prompt aparecer, e depois é disparada uma chamada de perfil por seguidor. No backend clássico, isso é volume de requisições que o Instagram contabiliza contra você; no HikerAPI, o mesmo loop chama user_by_id_v2 uma vez por usuário, então é volume de requisições que você paga. Nenhum dos dois backends te dá uma amostra barata de uma lista grande de seguidores.

A cara de um bloqueio depende do comando. Os quatro comandos de contato capturam ClientThrottledError e imprimem Error: Instagram blocked the requests. Please wait a few minutes before you try again.followers e followings não têm esse tratamento, então a mesma condição escapa como um traceback cru terminando em urllib.error.HTTPError: HTTP Error 429: Too Many Requests, o formato relatado na issue #394.

O handler também não salva os seus dados. Na issue #366, um usuário chegou a Catched 41643 followers email antes do bloqueio, e o caminho de recuperação então quebrou com TypeError: string indices must be integers, descartando todos os registros coletados. A issue #342 relata um corte por volta de 35.000 seguidores em um alvo com seis dígitos. Esses são os únicos números concretos que existem: nenhum limite confiável em tempo de relógio foi publicado, e qualquer guia que te dê um valor em minutos está chutando.

photos, comments, likes, mediatype, hashtags, wcommented e commentdata paginam o feed inteiro, e os dois últimos ainda buscam os comentários de cada post por cima disso. Eles raramente disparam um bloqueio, mas em uma conta com milhares de posts são bem mais lentos do que parecem.

Comandos que não retornam nada

Um Sorry! No results found :-( em vermelho não é um erro. Quer dizer que a requisição deu certo e que o alvo não tem dados daquele tipo. A maioria dos comandos pode emitir essa mensagem.

O addrs é o suspeito de sempre. Ele só conta os posts em que o objeto de localização traz latitude e longitude, e posts geolocalizados ficaram raros desde que o Instagram aposentou o mapa de fotos. O pouco que existe passa por geocodificação reversa no Nominatim, que por sua vez também tem limite de taxa.

O photodes é um caso diferente: ele não está vazio, está morto. Ele ainda busca https://www.instagram.com/<target>/?__a=1 e tenta acessar graphql.user.edge_owner_to_timeline_media, um endpoint sem autenticação que não devolve mais esse JSON. No backend do HikerAPI, a função foi reduzida a uma única linha que imprime Instagram has disabled this functionality. Trate-o como removido.

O stories não retorna nada quando não há nada no ar, o que é normal, mas ele também tem um parser frágil: a issue #1258 mostra o comando abortando com KeyError: 'media_count' quando o payload do reel não inclui essa chave.

Alvos privados, em resumo

Se o banner mostra [PRIVATE PROFILE] junto de [NOT FOLLOWING], quase todo comando da tabela para antes de fazer qualquer requisição. Uma única trava verifica se a conta é privada e não seguida, imprime Impossible to execute command: user has private profile e oferece Do you want send a follow request? [Y/N]: . O backend do HikerAPI é ainda mais seco: só de ser privada já bloqueia, sem prompt de solicitação de follow. Nenhuma flag muda isso. O quadro completo (quais comandos sobrevivem e o que o Instagram ainda expõe publicamente) está em o Osintgram funciona em contas privadas.

Fazendo o mesmo trabalho sem a CLI

O conjunto de comandos é realmente amplo. O que torna o Osintgram incômodo é tudo o que existe em volta: um alvo por sessão, um arquivo de credenciais, throttling sem backoff, nomes de arquivo que se sobrescrevem e um caminho de login que falha para muita gente antes de qualquer uma dessas coisas importar. Se você usa a CLI para pesquisa de verdade, mantenha as sessões curtas e exporte um conjunto de dados por vez.

Se você só quer o relatório, uma consulta hospedada pula todo esse aparato: não há repositório para clonar, nenhuma conta do Instagram sua em risco e nenhum loop de rate limit para ficar vigiando. Ela cobre apenas perfis públicos, o mesmo teto que a CLI tem.

Perguntas frequentes

  • Como instalar o Osintgram em 2026

    Clone, venv, pip, credenciais: os seis comandos que instalam o Osintgram, além de cada erro real que trava a instalação e o que cada um significa de verdade.

  • O Osintgram funciona em contas privadas do Instagram?

    O Osintgram bloqueia perfis privados com uma verificação de duas condições no código. A única exceção, a matriz completa de capacidades e por que os sites de visualizador são golpe.

O Osintgram é uma ferramenta OSINT independente e não tem qualquer vínculo com o Instagram ou a Meta. Estes guias descrevem apenas software de código aberto publicamente documentado e pesquisa em fontes abertas. Use essas técnicas de forma legal, sobre alvos que você esteja autorizado a investigar, e nunca para assediar ou vigiar pessoas.