A biologia gera dados em uma escala que requer infraestrutura de armazenamento e recuperação de nível industrial. O sequenciamento de um único genoma humano produz ~200 GB de leituras brutas. Os bancos de dados do NCBI coletivamente contêm petabytes de dados biológicos acumulados ao longo de décadas. Antes de analisar dados biológicos, você precisa saber onde eles vivem e como extraí-los.
Este capítulo é um guia prático dos principais bancos de dados biológicos — o que eles contêm, como acessá-los programaticamente e como eles se relacionam entre si.
O Panorama dos Bancos de Dados Biológicos
Os dados biológicos não são centralizados. São distribuídos em dezenas de bancos de dados especializados, a maioria dos quais faz referências cruzadas entre si:
| Banco de Dados | Conteúdo | URL |
|---|---|---|
| NCBI / GenBank | Sequências de DNA/RNA (todos os organismos) | ncbi.nlm.nih.gov |
| RefSeq | Sequências de referência curadas | ncbi.nlm.nih.gov/refseq |
| UniProt / Swiss-Prot | Sequências de proteínas + anotações | uniprot.org |
| PDB | Estruturas 3D de proteínas | rcsb.org |
| Ensembl | Anotação do genoma eucarioto | ensembl.org |
| SRA | Leituras de sequenciamento brutas | ncbi.nlm.nih.gov/sra |
| GEO | Conjuntos de dados de expressão gênica | ncbi.nlm.nih.gov/geo |
| dbSNP | Variantes genéticas humanas conhecidas | ncbi.nlm.nih.gov/snp |
| ClinVar | Associações variante-doença | ncbi.nlm.nih.gov/clinvar |
| OMIM | Doenças genéticas | omim.org |
O insight fundamental é que esses bancos de dados são interligados. Um gene no Ensembl tem um ID RefSeq. Esse ID RefSeq mapeia para registros de proteínas UniProt. Essas proteínas têm entradas de estrutura no PDB. As variantes naquele gene estão no dbSNP; variantes patogênicas estão no ClinVar. Aprender a navegar essas referências cruzadas é fundamental para a bioinformática.
NCBI Entrez: A Interface Programática
O sistema Entrez do NCBI é o API gateway para a maioria dos bancos de dados do NCBI. A biblioteca Biopython fornece o módulo Entrez como uma interface Python limpa.
Configuração
from Bio import Entrez, SeqIO
# Obrigatório pelo NCBI — eles usam isso para entrar em contato se suas consultas causarem problemas
Entrez.email = "seu@email.com"
Sem uma chave de API, o NCBI permite 3 requisições/segundo. Com uma chave de API gratuita (disponível no NCBI), você obtém 10 requisições/segundo. Sempre adicione delays entre requisições em loops:
import time
time.sleep(0.4) # fique dentro do limite de 3 req/s
Buscando uma Sequência por Número de Acesso
Cada sequência no GenBank/RefSeq tem um número de acesso — um identificador estável. Por exemplo, NM_007294 é o número de acesso RefSeq para o mRNA do BRCA1 humano.
from Bio import Entrez, SeqIO
Entrez.email = "seu@email.com"
# Buscar sequência de mRNA do BRCA1
handle = Entrez.efetch(
db="nucleotide",
id="NM_007294",
rettype="gb", # formato GenBank
retmode="text"
)
record = SeqIO.read(handle, "genbank")
handle.close()
print(record.id) # NM_007294.4
print(len(record.seq)) # comprimento da sequência em pb
print(record.description) # descrição humana
print(record.seq[:100]) # primeiras 100 bases
Pesquisando Registros
A função esearch executa uma busca de texto e retorna uma lista de IDs:
handle = Entrez.esearch(
db="nucleotide",
term="BRCA1[Gene Name] AND Homo sapiens[Organism] AND mRNA[Filter]",
retmax=10
)
search_results = Entrez.read(handle)
handle.close()
ids = search_results["IdList"]
print(f"Encontrados {search_results['Count']} registros, buscando {len(ids)}")
A sintaxe de busca do Entrez usa tags de campo entre colchetes. Campos comuns:
[Gene Name]— símbolo do gene[Organism]— espécie[Filter]— tipo de registro (mRNA, protein, RefSeq, etc.)[PDAT]— data de publicação (2020/01/01:2024/12/31[PDAT])
Busca em Lote
Para múltiplos registros, use efetch com uma lista de IDs separada por vírgulas:
import time
ids = ["NM_007294", "NM_000059", "NM_000546"] # BRCA1, BRCA2, TP53
handle = Entrez.efetch(
db="nucleotide",
id=",".join(ids),
rettype="fasta",
retmode="text"
)
records = list(SeqIO.parse(handle, "fasta"))
handle.close()
for rec in records:
print(f"{rec.id}: {len(rec.seq)} pb")
O Formato GenBank
O formato flat file do GenBank é o formato mais rico para sequências anotadas. Cada registro contém a sequência mais metadados extensos:
LOCUS NM_007294 7088 bp mRNA linear PRI 01-JAN-2024
DEFINITION Homo sapiens BRCA1 DNA repair associated (BRCA1), mRNA.
ACCESSION NM_007294
VERSION NM_007294.4
KEYWORDS RefSeq; MANE Select.
SOURCE Homo sapiens (human)
ORGANISM Homo sapiens
Eukaryota; Metazoa; Chordata; ...
FEATURES Location/Qualifiers
source 1..7088
/organism="Homo sapiens"
/mol_type="mRNA"
/chromosome="17"
gene 1..7088
/gene="BRCA1"
CDS 232..5824
/gene="BRCA1"
/product="breast cancer type 1 susceptibility protein"
/protein_id="NP_009225.1"
ORIGIN
1 gaattcgatt tctgaataga gatcaagagg ...
Acessando features programaticamente:
record = SeqIO.read(handle, "genbank")
for feature in record.features:
if feature.type == "CDS":
print(f"Localização CDS: {feature.location}")
print(f"Gene: {feature.qualifiers.get('gene', ['?'])[0]}")
print(f"ID da proteína: {feature.qualifiers.get('protein_id', ['?'])[0]}")
# Extrair a sequência CDS
cds_seq = feature.extract(record.seq)
protein = cds_seq.translate(to_stop=True)
print(f"Comprimento da proteína: {len(protein)} aa")
UniProt: O Banco de Dados de Sequências de Proteínas
Para proteínas, o UniProt é a referência primária. Ele tem duas camadas:
- Swiss-Prot — curado manualmente, anotações de alta qualidade (~570k entradas)
- TrEMBL — anotado computacionalmente, muito maior mas de menor confiança (~250M entradas)
Você acessa o UniProt via API REST:
import requests
def fetch_uniprot(accession: str) -> dict:
url = f"https://rest.uniprot.org/uniprotkb/{accession}.json"
response = requests.get(url)
response.raise_for_status()
return response.json()
# Buscar proteína BRCA1 humana
data = fetch_uniprot("P38398")
print(data["primaryAccession"]) # P38398
print(data["uniProtkbId"]) # BRCA1_HUMAN
print(data["organism"]["scientificName"]) # Homo sapiens
# Sequência da proteína
sequence = data["sequence"]["value"]
print(f"Comprimento: {len(sequence)} aa")
print(f"Massa: {data['sequence']['molWeight']} Da")
Pesquisando o UniProt:
def search_uniprot(query: str, fields: str = "accession,id,gene_names,length", max_results: int = 10) -> list:
url = "https://rest.uniprot.org/uniprotkb/search"
params = {
"query": query,
"fields": fields,
"size": max_results,
"format": "json"
}
response = requests.get(url, params=params)
response.raise_for_status()
return response.json()["results"]
results = search_uniprot("BRCA1 AND organism_id:9606 AND reviewed:true")
for entry in results:
print(entry["primaryAccession"], entry.get("uniProtkbId"))
O PDB: Banco de Dados de Estruturas de Proteínas
O Protein Data Bank (RCSB PDB) armazena estruturas 3D determinadas experimentalmente. Cada entrada tem um ID PDB de 4 caracteres.
import requests
def fetch_pdb_info(pdb_id: str) -> dict:
url = f"https://data.rcsb.org/rest/v1/core/entry/{pdb_id.lower()}"
response = requests.get(url)
response.raise_for_status()
return response.json()
info = fetch_pdb_info("1JM7") # domínio BRCT do BRCA1
print(info["struct"]["title"])
print(info["rcsb_entry_info"]["resolution_combined"])
print(info["rcsb_entry_info"]["experimental_method"])
Baixando arquivos de estrutura:
from Bio.PDB import PDBParser, MMCIFParser
import urllib.request
# Baixar arquivo PDB
pdb_id = "1JM7"
url = f"https://files.rcsb.org/download/{pdb_id}.pdb"
urllib.request.urlretrieve(url, f"{pdb_id}.pdb")
# Parsear estrutura
parser = PDBParser(QUIET=True)
structure = parser.get_structure(pdb_id, f"{pdb_id}.pdb")
for model in structure:
for chain in model:
residues = list(chain.get_residues())
print(f"Cadeia {chain.id}: {len(residues)} resíduos")
Arquivos PDB vêm em dois formatos: o formato de texto .pdb legado (limitado a ~100k átomos) e o formato mais novo .cif/.mmCIF (sem limite de tamanho). Para complexos grandes (ribossomos, vírus), use mmCIF. O MMCIFParser do Biopython lida com ambos.
Mapeamento de IDs entre Bancos de Dados
Uma tarefa comum em bioinformática é mapear entre IDs de bancos de dados. O UniProt fornece um serviço para isso:
def map_ids(ids: list, from_db: str, to_db: str) -> dict:
url = "https://rest.uniprot.org/idmapping/run"
response = requests.post(url, data={
"ids": ",".join(ids),
"from": from_db,
"to": to_db
})
job_id = response.json()["jobId"]
# Polling para resultados
import time
while True:
status = requests.get(f"https://rest.uniprot.org/idmapping/status/{job_id}").json()
if status.get("jobStatus") == "FINISHED":
break
time.sleep(1)
results_url = f"https://rest.uniprot.org/idmapping/results/{job_id}"
results = requests.get(results_url).json()
return {r["from"]: r["to"] for r in results["results"]}
# Mapear IDs de proteínas RefSeq para accessions UniProt
mapping = map_ids(["NP_009225.1", "NP_000050.2"], "RefSeq_Protein", "UniProtKB")
print(mapping)
Padrões Práticos
Padrão 1: Gene → Sequência → Anotação
from Bio import Entrez, SeqIO
import time
Entrez.email = "seu@email.com"
def get_gene_info(gene_name: str, organism: str = "Homo sapiens") -> dict:
# 1. Buscar mRNA RefSeq
handle = Entrez.esearch(
db="nucleotide",
term=f"{gene_name}[Gene Name] AND {organism}[Organism] AND RefSeq[Filter] AND mRNA[Filter]"
)
ids = Entrez.read(handle)["IdList"]
handle.close()
if not ids:
return {}
time.sleep(0.4)
# 2. Buscar o resultado principal
handle = Entrez.efetch(db="nucleotide", id=ids[0], rettype="gb", retmode="text")
record = SeqIO.read(handle, "genbank")
handle.close()
# 3. Extrair informações relevantes
cds_features = [f for f in record.features if f.type == "CDS"]
result = {
"accession": record.id,
"length_bp": len(record.seq),
"cds_count": len(cds_features),
}
if cds_features:
cds = cds_features[0]
result["protein_id"] = cds.qualifiers.get("protein_id", ["?"])[0]
result["protein_length"] = len(cds.extract(record.seq).translate(to_stop=True))
return result
info = get_gene_info("TP53")
print(info)
Padrão 2: Download em Lote de Sequências para Análise
def download_sequences(gene_name: str, organism: str, output_file: str, max_seqs: int = 50):
Entrez.email = "seu@email.com"
handle = Entrez.esearch(
db="nucleotide",
term=f"{gene_name}[Gene Name] AND {organism}[Organism] AND RefSeq[Filter]",
retmax=max_seqs
)
ids = Entrez.read(handle)["IdList"]
handle.close()
time.sleep(0.4)
handle = Entrez.efetch(
db="nucleotide",
id=",".join(ids),
rettype="fasta",
retmode="text"
)
with open(output_file, "w") as f:
f.write(handle.read())
handle.close()
print(f"Baixadas {len(ids)} sequências para {output_file}")
download_sequences("COX1", "Homo sapiens", "cox1_sequences.fasta")
Resumo
Os principais bancos de dados que você usará constantemente:
- NCBI Entrez — o gateway para sequências, genomas e literatura. O Biopython o encapsula de forma limpa.
- UniProt — registros canônicos de proteínas. Use a API REST diretamente.
- RCSB PDB — dados estruturais. O módulo
Bio.PDBdo Biopython cuida do parsing.
A referência cruzada entre bancos de dados é a habilidade central. Um gene tem um símbolo, um ID RefSeq, um accession UniProt e possivelmente uma estrutura no PDB — e navegar entre eles é uma operação diária em bioinformática.
Antes de escrever uma consulta de banco de dados, verifique:
- O banco de dados tem uma API REST estável? (A maioria tem)
- Existe uma biblioteca Biopython ou Python dedicada? (Economiza semanas de trabalho)
- Quais são os limites de taxa? (Sempre adicione delays em loops)
- Você precisa de uma chave de API para maior throughput?
- Existe uma opção de download em lote para grandes conjuntos de dados? (FTP/S3 é mais rápido que API para >1000 registros)