15 KiB
Avaliação inicial do banco de dados
Data da avaliação: 13 de julho de 2026
Banco: dfimoveis_data/dfimoveis.sqlite3
Escopo: diagnóstico estrutural e de qualidade anterior a qualquer análise dos imóveis
1. Pergunta respondida
O banco já representa de forma segura anúncios, snapshots históricos e imóveis físicos, com cobertura e qualidade suficientes para iniciar análises imobiliárias?
Resposta curta: ele representa anúncios e estados de conteúdo, mas ainda não representa imóveis físicos deduplicados. A coleta cobre apenas um dia e contém exatamente um snapshot por anúncio. Preços, áreas e quartos podem ser usados somente após validações específicas; localização e dados de anunciante estão fortemente contaminados e não devem ser usados como estão. Portanto, o banco ainda não sustenta tendência histórica, tempo de mercado, preço por m² ou comparáveis por localização.
2. Segurança e método
A análise foi feita exclusivamente com consultas agregadas ou amostras pequenas. O banco foi aberto com sqlite3 -readonly ou URI mode=ro&immutable=1, sempre com PRAGMA query_only = ON. Nenhum scraper foi executado e nenhuma instrução SQL de escrita foi enviada ao banco.
Identificação do arquivo analisado:
- tamanho: 5.017.600 bytes;
- modificação:
2026-07-13 14:20:34.601285975 -03:00; - SHA-256 inicial:
1ce3128b488c50c993d7328ac6e24b5905f083a7e04e3f636407eea1edd02b9d; - sem arquivos
-walou-shme sem processo com o arquivo aberto na inspeção inicial; PRAGMA quick_check:ok;PRAGMA foreign_key_check: nenhuma violação.
Na validação final, o arquivo principal continuava com o mesmo tamanho, mtime e SHA-256. Como seu modo persistido é WAL, o cliente SQLite havia criado dois sidecars de runtime: dfimoveis.sqlite3-shm, com 32.768 bytes, e dfimoveis.sqlite3-wal, vazio. Eles não foram removidos, conforme a regra explícita do projeto.
O esquema completo e as decisões de interpretação estão em docs/ACTUAL_SCHEMA.md.
3. Universo, período e cobertura
Não houve filtro ou exclusão de registros para este diagnóstico. O universo físico contém:
| Unidade | Quantidade |
|---|---|
| Execuções do coletor | 4 |
Anúncios únicos por listing_id |
156 |
| URLs de anúncio únicas | 156 |
| Snapshots de conteúdo | 156 |
| Vínculos anúncio–busca | 156 |
| Fotos registradas | 5.386 |
| Anúncios com pelo menos uma foto | 156 |
Cobertura temporal
Todas as datas técnicas válidas estão em ISO 8601. A coleta cobre somente 13/07/2026:
| Evento | UTC | Horário de Brasília (UTC−3) |
|---|---|---|
| Primeira execução iniciada | 12:20:58 | 09:20:58 |
| Primeira observação de anúncio | 12:56:32 | 09:56:32 |
| Última observação de anúncio | 13:25:51 | 10:25:51 |
| Última execução concluída | 17:20:34 | 14:20:34 |
As duas primeiras execuções terminaram com status = ok, mas registraram zero páginas, URLs e detalhes. As duas execuções com coleta efetiva somaram:
- 9 páginas de busca;
- 156 URLs encontradas;
- 156 detalhes processados com sucesso e zero falhas;
- 5.383 fotos baixadas e 3 falhas;
- zero anúncios marcados como inativos.
As buscas cobertas foram:
https://www.dfimoveis.com.br/venda/df/cruzeiro/novo/apartamento/3-quartos— 65 anúncios;https://www.dfimoveis.com.br/venda/df/brasilia/jardins-mangueiral/casa/3,4-quartos— 91 anúncios.
O universo é, portanto, intencionalmente limitado a um portal e a duas consultas. A busca do Jardins Mangueiral aceita três ou quatro quartos: 89 casas foram extraídas com três quartos anunciados e 2 com quatro. Mesmo os 89 registros de três quartos não comprovam a planta original exigida pelo projeto.
4. Como as entidades são representadas
Anúncio
listings guarda uma linha por listing_id do DF Imóveis, com URL única e o estado corrente. Os 156 IDs, URLs e hashes correntes são distintos. Essa é uma identidade de publicação no portal, não de unidade residencial.
Snapshot ou observação histórica
listing_history guarda uma linha por par único (listing_id, content_hash). Isso é um histórico de mudanças de conteúdo: uma nova observação idêntica não cria novo snapshot. listings.first_seen_at e last_seen_at condensam a janela observada.
No snapshot atual:
- todos os 156 anúncios têm exatamente um registro histórico;
- o hash histórico é igual ao hash corrente em todos os casos;
captured_at = first_seen_atem todos os casos;first_seen_at = last_seen_atem todos os casos.
Assim, não há série histórica real ainda. Não é possível medir mudança de preço, republicação, duração, saída ou retorno do estoque.
Execução do scraper
crawl_runs registra horários, estado e contadores JSON, mas não existe run_id em listings, listing_history ou listing_searches. A execução geradora só pode ser inferida por horário. Isso limita auditoria, cobertura por execução e diagnóstico de ausências.
Imóvel físico
Não existe tabela ou chave para imóvel físico, unidade, endereço normalizado ou relação de duplicidade. Anúncios de corretores diferentes permanecem independentes. A base também não contém hashes perceptuais; possui apenas SHA-256 exato das imagens.
Logo, as unidades válidas hoje são:
- anúncio único: suportado por
listing_id; - estado alterado do anúncio: suportado por
listing_history; - imóvel físico provável/confirmado: não suportado sem derivação e revisão.
5. Qualidade dos dados
5.1 Integridade estrutural
Pontos positivos:
- arquivo íntegro segundo
quick_check; - nenhuma FK órfã em histórico, buscas ou fotos;
- todos os JSONs são sintaticamente válidos;
- todos os IDs de anúncio têm 6–7 caracteres numéricos;
- todas as URLs pertencem ao domínio e padrão esperados;
- todos os 156 HTMLs brutos referenciados existem;
- todos os hashes de conteúdo têm 64 caracteres;
- não há URL, hash corrente ou caminho de HTML repetido.
Limitações estruturais:
- nenhuma relação entre execução e item;
- fonte implícita, sem
source_id; - área armazenada em um único conceito;
- mídia ligada ao anúncio, não ao snapshot;
- ausência de entidade de imóvel físico e de localização normalizada;
- apenas autoíndices; não há índices por datas ou atributos analíticos.
5.2 Completude dos principais campos
| Campo | Ausentes | Percentual |
|---|---|---|
| preço | 0 | 0,0% |
| área | 0 | 0,0% |
| quartos | 0 | 0,0% |
| condomínio | 59 | 37,8% |
| IPTU | 144 | 92,3% |
| suítes | 41 | 26,3% |
| vagas | 57 | 36,5% |
| cidade | 156 | 100,0% |
| UF | 156 | 100,0% |
| nome do anunciante | 156 | 100,0% |
| latitude/longitude | 156 / 156 | 100,0% / 100,0% |
| data de publicação | 156 | 100,0% |
| data de inativação | 156 | 100,0% |
Esses percentuais medem apenas nulos. Para campos textuais, a taxa de preenchimento é enganosa porque o parser capturou conteúdo da página em vez do valor pretendido.
5.3 Contaminação de texto
Os problemas mais graves são:
- 146 endereços (93,6%) têm mais de 300 caracteres;
- 154 bairros (98,7%) têm mais de 100 caracteres;
- os dois valores curtos de bairro são
.e um trecho de descrição, também inválidos; - 98 códigos de anunciante (62,8%) têm mais de 100 caracteres;
- 153 valores de CRECI (98,1%) têm mais de 100 caracteres.
Os textos longos incluem navegação, formulários, política de privacidade e outros fragmentos da página. Eles podem conter dados de contato exibidos pelo portal; por isso, não foram reproduzidos neste relatório. Esses campos devem ser considerados indisponíveis, não apenas ruidosos.
Os títulos têm somente quatro valores distintos e funcionam como títulos genéricos por tipologia. As 156 descrições são distintas, mas têm apenas 156–161 caracteres, compatíveis com resumos/metadados truncados, não com a descrição completa. extra_json contém um array json_ld vazio nos 156 registros e não resolve a reextração.
5.4 Valores estruturados e outliers
| Tipo anunciado | N | Preço mínimo | Preço máximo | Área mínima | Área máxima | Quartos |
|---|---|---|---|---|---|---|
| Apartamento | 65 | R$ 480.000 | R$ 2.030.598 | 61 m² | 113 m² | 3 |
| Casa | 91 | R$ 450.000 | R$ 570.000.000 | 0,11 m² | 131,46 m² | 3–4 |
Não há valores nulos ou não positivos em preço e área, mas isso não significa validade:
- anúncio
1351663: R$ 570.000.000, forte indício de erro de escala ou parsing; - anúncio
1370918: 0,11 m², área fisicamente implausível.
Não foi aplicado corte nem correção silenciosa. Também não se calculou preço por m², pois area_m2 não distingue área útil, privativa, construída, total ou terreno.
5.5 Fotos e arquivos brutos
Das 5.386 linhas em photos:
- 5.383 têm arquivo local, e o tamanho em disco coincide com
bytes; - 3 não têm hash, MIME, tamanho ou caminho, correspondendo às três falhas registradas pelo coletor;
- há 4.514 WebP, 558 JPEG, 311 PNG e 3 sem MIME;
- os anúncios possuem de 5 a 61 fotos;
- não há caminho local nem ordinal duplicado dentro de anúncio.
Há 3.307 hashes distintos. Cento e quatorze hashes aparecem em mais de um anúncio, e um deles aparece nos 156 anúncios. Isso revela logos, selos, placeholders ou outros ativos comuns. Hash idêntico pode ser sinal de anúncio duplicado somente depois de excluir ativos genéricos e combinar outros sinais.
6. Duplicidades e imóveis físicos prováveis
Não há duplicidade técnica imediata por listing_id, URL ou content_hash. Uma assinatura exploratória composta por bairro, tipo, preço, área, quartos e vagas encontrou 13 grupos, equivalentes a 18 linhas excedentes. Esse resultado não é evidência de 18 imóveis duplicados, porque:
- o bairro está contaminado;
- preço, área e quartos podem coincidir entre unidades distintas;
- fotos compartilhadas incluem ativos genéricos;
- não há endereço/unidade confiável nem telefone normalizado;
- SHA-256 só detecta arquivos idênticos, não versões redimensionadas da mesma foto.
Consequentemente, o método de deduplicação desta avaliação foi apenas técnico: unicidade de anúncio por listing_id. Nenhuma fusão de anúncios nem contagem de imóveis físicos foi produzida.
Uma futura camada derivada deve combinar, com confiança e revisão manual:
- endereço/QC/quadra/bloco/unidade reextraídos;
- imagens após remoção de ativos comuns, idealmente com hash perceptual;
- preço, área, planta, quartos e vagas validados;
- anunciante e descrição normalizados;
- estados
unreviewed,probable,confirmed,rejectedeambiguous.
7. Possíveis quebras de coleta
- Localização:
addresseneighborhoodcapturaram grandes trechos da página; cidade, UF e coordenadas ficaram vazias. - Anunciante:
advertiser_codeecrecifrequentemente capturaram texto extenso;advertiser_nameficou vazio. - Dados estruturados: o
json_ldfoi preservado como array vazio em todos os anúncios. - Escala numérica: pelo menos um preço e uma área são claramente suspeitos.
- Fotos: três falhas foram registradas de modo consistente, sem arquivo local.
- Execuções vazias: duas execuções
oknão coletaram páginas. Sem motivo/configuração persistidos, não é possível diferenciar teste, filtro vazio ou falha silenciosa. - Filtro do Mangueiral: a URL coletada inclui casas de quatro quartos e não identifica planta original.
8. Limitações para qualquer conclusão imobiliária
- Um único dia não permite análise histórica ou tendência.
- A amostra cobre apenas DF Imóveis e duas buscas específicas.
- Preço anunciado não é preço negociado.
- Não há transações, status comprovado de venda ou evidência de fechamento.
- Não há imóveis físicos deduplicados.
- Não há localização analítica confiável por QC, quadra ou bloco.
- Não há conceito comparável de área.
- O estado de reforma, planta original, elevador, garagem, andar e qualidade funcional não está modelado de forma suficiente.
- Para Jardins Mangueiral,
bedrooms = 3não valida planta original de três quartos.
Portanto, ainda não é apropriado produzir medianas regionais, comparáveis, preço por m², tempo de anúncio, liquidez ou recomendações de visita com base apenas neste banco.
9. Próximas ações recomendadas
Antes da análise dos imóveis:
- corrigir e testar a extração de endereço, bairro, anunciante e CRECI usando os HTMLs já salvos, sem recrawling;
- criar uma derivação reproduzível fora do banco original e preservar os valores brutos;
- separar áreas privativa, útil, construída, total e de terreno, deixando nulo o conceito não comprovado;
- criar regras explícitas de validação para preço e área, mantendo os outliers identificados em quarentena;
- filtrar o Mangueiral por planta original de três quartos, não apenas pelo número anunciado;
- coletar múltiplas datas e auditar a cobertura por busca antes de estimar permanência, entradas ou saídas;
- numa evolução aprovada do coletor, adicionar
source_id,run_idnos snapshots, referência ao HTML bruto histórico e versão/configuração da coleta; - construir
property_candidatesapenas em uma camada derivada, com confiança e revisão, sem fundir registros no banco original.
10. Consultas de reprodução
Todas devem ser executadas com sqlite3 -readonly dfimoveis_data/dfimoveis.sqlite3 ou conexão Python URI em mode=ro e PRAGMA query_only = ON.
-- Objetos do esquema
SELECT type, name, tbl_name, sql
FROM sqlite_master
ORDER BY type, name;
-- Contagens (executar uma tabela por vez após validar os nomes)
SELECT COUNT(*) FROM crawl_runs;
SELECT COUNT(*) FROM listings;
SELECT COUNT(*) FROM listing_history;
SELECT COUNT(*) FROM listing_searches;
SELECT COUNT(*) FROM photos;
-- Cobertura
SELECT MIN(started_at), MAX(finished_at), COUNT(*)
FROM crawl_runs;
SELECT MIN(first_seen_at), MAX(last_seen_at),
COUNT(DISTINCT date(first_seen_at))
FROM listings;
-- Número de snapshots por anúncio
SELECT snapshots, COUNT(*) AS listings
FROM (
SELECT listing_id, COUNT(*) AS snapshots
FROM listing_history
GROUP BY listing_id
)
GROUP BY snapshots;
-- Completude de campos críticos
SELECT
COUNT(*) AS total,
SUM(price_brl IS NULL) AS missing_price,
SUM(area_m2 IS NULL) AS missing_area,
SUM(condominium_brl IS NULL) AS missing_condominium,
SUM(iptu_brl IS NULL) AS missing_iptu,
SUM(latitude IS NULL OR longitude IS NULL) AS missing_coordinates
FROM listings;
-- Contaminação textual sem imprimir os textos
SELECT
SUM(length(address) > 300) AS long_address,
SUM(length(neighborhood) > 100) AS long_neighborhood,
SUM(length(advertiser_code) > 100) AS long_advertiser_code,
SUM(length(creci) > 100) AS long_creci
FROM listings;
-- Integridade referencial e física
PRAGMA quick_check;
PRAGMA foreign_key_check;
11. Implicação para a decisão de compra
Esta avaliação reduz o risco de transformar uma coleta tecnicamente bem-sucedida em falsa precisão de mercado. O próximo ganho real não virá de comparar preços imediatamente, mas de corrigir localização e semântica de área, acumular histórico e construir uma deduplicação reversível. Até lá, os registros são úteis como inventário bruto de anúncios e arquivos, não como avaliação consolidada de imóveis físicos.