Como usar os ficheiros da webatla

Cada ficheiro é JSON Lines comprimido com zstd, com um domínio por linha. Veja aqui como o abrir, fazer-lhe perguntas e carregá-lo no seu stack. Cada receita foi executada na amostra gratuita de 10 000 linhas, e o resultado que vê foi o que o comando devolveu.

Formato
JSON Lines, comprimido com zstd
.jsonl.zst
Uma linha por
Domain, todas as chaves sempre presentes
os valores podem ser null
Nome do ficheiro
Dataset e data da exportação
all-data-2026-10-16.jsonl.zst
Atualização
Uma nova exportação todos os dias
as mesmas colunas todos os dias

1 · O que descarrega

O que descarrega

Todos os datasets da webatla são JSON Lines: um domínio por linha, um objeto JSON por linha. Os ficheiros pagos são comprimidos com zstd.

FicheiroO que contémFormato
Dataset completoTodas as linhas do dataset.jsonl.zst
CorteTodas as linhas de um TLD, sufixo de TLD, país (por IP) ou tecnologia, com os mesmos campos do ficheiro completo.jsonl.zst
Amostra gratuita (10 000 linhas)As primeiras 10 000 linhas do ficheiro completo.jsonl simples, sem compressão
Amostra de 20 linhas nas páginas de TLD, país e tecnologiaLinhas dessa entidade, com os mesmos nomes de campos do ficheiro pago. Mostra algumas das linhas mais completas, não linhas aleatórias.na página

Descarregue um corte em vez de filtrar o ficheiro completo

Se precisa de uma zona, um país ou uma tecnologia, o corte já vem filtrado e é muitas vezes mais pequeno.

A amostra gratuita mostra o formato, não uma mistura típica

A maioria dos ficheiros está ordenada por sufixo de TLD, por isso as primeiras 10 000 linhas cobrem apenas alguns sufixos do início do alfabeto, e .com não é um deles. Um filtro que não devolve nada na amostra pode devolver milhões de linhas no ficheiro completo. Use a amostra para montar e testar os seus comandos. Eles correm sem alterações no ficheiro pago.

2 · Abrir o ficheiro

Espreitar lá dentro sem descomprimir

Todas as ferramentas aqui leem o ficheiro comprimido em fluxo. A única diferença entre a amostra e o ficheiro pago é a forma como o abre.

Antes de começar: escolha uma ferramenta

sudo apt install zstd jq        # Debian, Ubuntu
brew install zstd jq duckdb     # macOS
pip install duckdb zstandard    # Python, any OS

No Windows, use o WSL.

O mesmo comando na amostra e no ficheiro pago

# free preview (plain JSONL): give the file to jq directly
jq -c 'select(."Country by IP" == "BG") | {Domain, "TLD suffix", "IP address"}' \
  webatla-all-data-preview-10k.jsonl

# paid file or slice (.jsonl.zst): decompress on the fly into the same jq
zstd -dc all-data-2026-10-16.jsonl.zst \
  | jq -c 'select(."Country by IP" == "BG") | {Domain, "TLD suffix", "IP address"}'
Saída real da amostra de 10 000 linhas
{"Domain":"360.0.bg","TLD suffix":"0.bg","IP address":"31.13.236.27"}
{"Domain":"doktoranti5.0.bg","TLD suffix":"0.bg","IP address":"185.80.2.212"}
{"Domain":"edu5.0.bg","TLD suffix":"0.bg","IP address":"79.98.104.12"}
...

O zstdcat lê os dois tipos de ficheiro, por isso um só pipeline serve para a amostra e para o ficheiro pago: zstdcat FILE | ...

DuckDB

brew install duckdbwinget install DuckDB.cli

SELECT Domain, TLD, "Country by IP", "HTTP status"
FROM read_json('all-data-2026-10-16.jsonl.zst',
  columns = {Domain: 'VARCHAR', TLD: 'VARCHAR',
             "Country by IP": 'VARCHAR', "HTTP status": 'INTEGER'})
LIMIT 3;
Saída real da amostra de 10 000 linhas
Domain       TLD  Country by IP  HTTP status
360.0.bg     bg   BG             200
digsys.0.bg  bg   NULL           200
dnssec.0.bg  bg   NULL           0

zstdcat + jq

brew install zstd jqapt install zstd jq

zstdcat dns-2026-10-16.jsonl.zst | head -n 1 | jq .
Saída real da amostra de 10 000 linhas
{
  "Domain": "360.0.bg",
  "TLD suffix": "0.bg",
  "TLD": "bg",
  "Domain type": "ICANN",
  ...

Python

pip install zstandard

import io, json, zstandard
with open("dns-2026-10-16.jsonl.zst", "rb") as fh:
    stream = zstandard.ZstdDecompressor().stream_reader(fh, read_across_frames=True)
    for line in io.TextIOWrapper(stream, encoding="utf-8"):
        row = json.loads(line)
        mx = (row["DNS records"] or {}).get("MX") or []
        if any((m.get("host") or "").lower().endswith(".google.com") for m in mx):
            print(row["Domain"])
Saída real da amostra de 10 000 linhas
edu5.0.bg
shopping.9guacu.br
ffe.a.se
...

Contar linhas e listar os campos

brew install zstd jqapt install zstd jq

zstd -dc all-data-2026-10-16.jsonl.zst | wc -l
zstd -dc all-data-2026-10-16.jsonl.zst | head -n 1 | jq -r 'keys_unsorted[]'
Saída real da amostra de 10 000 linhas
10000
Domain
TLD suffix
TLD
Domain type
HTTP status
...

Criar a sua própria amostra aleatória

A amostra gratuita não é aleatória. Para obter uma amostra representativa de um ficheiro que descarregou:

Linux: shufmacOS: gshuf (brew install coreutils)

zstd -dc all-data-2026-10-16.jsonl.zst | shuf -n 1000 > random-1000.jsonl
wc -l < random-1000.jsonl
Saída real da amostra de 10 000 linhas
1000

3 · Responder a perguntas

Perguntas a que o ficheiro diário responde

Primeiro a resposta, a consulta DuckDB a um clique de distância. Abra um terminal na pasta com o ficheiro descarregado, escreva duckdb e cole a consulta.

Vendas Technologies

Que lojas WooCommerce estão alojadas na Alemanha?

Saída real da amostra de 10 000 linhas
ariana.acDE
fjak.acDE
empower.abudhabiDE

Ordenadas por PR value, guardadas como woocommerce-de.csv com 12 linhas. Um CSV que o seu CRM ou folha de cálculo abre.

Mostrar a consulta
COPY (SELECT Domain, "PR value" FROM read_json('technologies-2026-10-16.jsonl.zst',
    columns = {Domain: 'VARCHAR', "Country by IP": 'VARCHAR',
               Technologies: 'JSON', "PR value": 'DOUBLE'})
  WHERE "Country by IP" = 'DE' AND list_contains(CASE json_type(Technologies)
    WHEN 'OBJECT' THEN json_keys(Technologies)
    WHEN 'ARRAY' THEN from_json(Technologies, '["VARCHAR"]') END, 'WooCommerce')
  ORDER BY "PR value" DESC
) TO 'woocommerce-de.csv';
Dataset Technologies →
Marketing de produto Technologies

Que construtor de sites está por trás de mais websites?

Saída real da amostra de 10 000 linhas
WordPress628 · 80,6%
Wix52 · 6,7%
Squarespace45 · 5,8%
Drupal22 · 2,8%
Webflow20 · 2,6%
Joomla12 · 1,5%

Quota entre estes seis construtores, não entre todos os websites. Execute-a num corte de um país para comparar um mercado.

Mostrar a consulta
SELECT tech, count(*) AS sites,
       round(100 * count(*) / sum(count(*)) OVER (), 1) AS pct
FROM (SELECT unnest(CASE json_type(Technologies)
        WHEN 'OBJECT' THEN json_keys(Technologies)
        WHEN 'ARRAY' THEN from_json(Technologies, '["VARCHAR"]') END) AS tech
      FROM read_json('technologies-2026-10-16.jsonl.zst', columns = {Technologies: 'JSON'}))
WHERE tech IN ('WordPress', 'Wix', 'Squarespace', 'Webflow', 'Drupal', 'Joomla')
GROUP BY tech ORDER BY sites DESC;
Dataset Technologies →
Proteção de marca RDAP & WHOIS

Que domínios novos contêm o nome da sua marca?

Saída real da amostra de 10 000 linhas, obtida em 16/10/2026
kayorashop.store2026-10-11
moonovaactivewearshop.com2026-10-10
shopcastava.com2026-10-01

Registados nos últimos 30 dias, com o registrar. Substitua shop pelo nome da sua marca.

Mostrar a consulta
SELECT "Domain creation date"[:10] AS created, Domain, Registrar
FROM read_json('rdap-whois-2026-10-16.jsonl.zst', columns = {Domain: 'VARCHAR',
  "Domain creation date": 'VARCHAR', Registrar: 'VARCHAR'})
WHERE Domain LIKE '%shop%'
  AND "Domain creation date" >= CAST(current_date - 30 AS VARCHAR)
ORDER BY created DESC;
Dataset RDAP & WHOIS →
Investimento em domínios Websites + Ranking

Que websites com classificação expiram nos próximos 30 dias?

Saída real da amostra de 10 000 linhas, obtida em 16/10/2026
adamcadre.ac2026-10-24
ama.ab.ca2026-10-31
psychologistsassociation.ab.ca2026-11-09

Ordenados por PR value. Muitas entidades de registo renovam automaticamente, por isso trate o resultado como uma lista de vigilância e não como uma lista de drops.

Mostrar a consulta
SELECT Domain, "Domain expiration date"[:10] AS expires
FROM read_json('websites-ranking-2026-10-16.jsonl.zst', columns = {Domain: 'VARCHAR',
  "Domain expiration date": 'VARCHAR', "PR value": 'DOUBLE'})
WHERE "Domain expiration date"
  BETWEEN CAST(current_date AS VARCHAR) AND CAST(current_date + 30 AS VARCHAR)
ORDER BY "PR value" DESC LIMIT 3;
Dataset Websites + Ranking →
E-mail e infraestrutura DNS

Quem gere o DNS destes domínios?

Saída real da amostra de 10 000 linhas
cloudflare.com2277 · 25,1%
registrar-servers.com704 · 7,7%
domaincontrol.com622 · 6,8%

Percentagem de domínios com um registo NS utilizável, agrupados pelos dois últimos rótulos do nome de anfitrião.

Mostrar a consulta
CREATE OR REPLACE MACRO provider(h) AS
  array_to_string(string_split(lower(rtrim(h, '.')), '.')[-2:], '.');
SELECT provider(json_extract_string("DNS records", '$.NS[0]')) AS dns,
  count(*) AS domains, round(100 * count(*) / sum(count(*)) OVER (), 1) AS pct
FROM read_json('dns-2026-10-16.jsonl.zst', columns = {"DNS records": 'JSON'})
WHERE dns <> '' GROUP BY dns ORDER BY domains DESC, dns LIMIT 3;
Dataset DNS →
Vendas All data

Que empresas usam o Google Workspace para e-mail?

Saída real da amostra de 10 000 linhas
edu5.0.bgGoogle
shopping.9guacu.brGoogle
ffe.a.seGoogle

456 domínios na amostra gratuita, lidos a partir dos registos MX. Para o Microsoft 365, teste antes .mail.protection.outlook.com.

Mostrar a consulta
zstd -dc all-data-2026-10-16.jsonl.zst | jq -r '
  select(any(."DNS records".MX[]?.host;
             ascii_downcase | test("(^|\\.)(google|googlemail)\\.com$")))
  | .Domain' > google-workspace.txt
Dataset All data →

4 · Criar uma lista

Criar uma lista a partir do ficheiro completo ou de um corte

O ficheiro completo não cabe numa folha de cálculo, por isso filtre-o primeiro ou comece por um corte: uma tecnologia, TLD, sufixo de TLD ou país como ficheiro próprio, a partir da respetiva página da webatla ou da API. Com acesso a Technologies ou a All data, cada página de tecnologia tem uma caixa de transferência para o seu corte.

A partir do ficheiro completo

Um TLD ou um sufixo

jq

O TLD é o último rótulo do domínio. O sufixo de TLD é o sufixo público exato.

# every domain under one TLD (de covers every suffix that ends in .de)
zstd -dc all-data-2026-10-16.jsonl.zst | jq -c 'select(.TLD == "de")' > de.jsonl

# exactly one suffix
zstd -dc all-data-2026-10-16.jsonl.zst | jq -c 'select(."TLD suffix" == "2ix.de")' > 2ix.de.jsonl

# a suffix that equals its TLD (com, de, ac) has no file of its own:
# filter the TLD slice instead
zstd -dc webatla-all-data-ac-2026-10-16.jsonl.zst | jq -c 'select(."TLD suffix" == "ac")' > ac.jsonl
Saída real da amostra de 10 000 linhas
de.jsonl      224 lines
2ix.de.jsonl   52 lines
ac.jsonl     5463 lines

Websites alojados num só país, de forma rápida

grep + jq

Um website é uma linha com um endereço IP, e o seu país é onde o servidor está alojado (um código ISO em maiúsculas). O grep elimina as linhas que não podem corresponder e depois o jq verifica as restantes com exatidão.

zstd -dc all-data-2026-10-16.jsonl.zst \
  | grep -F '"Country by IP":"DE"' \
  | jq -c 'select(."IP address" != null and ."Country by IP" == "DE")' > de-websites.jsonl
Saída real da amostra de 10 000 linhas
de-websites.jsonl: 595 lines, the same as jq alone

Exportar para CSV para o Excel ou o Google Sheets

jq

O Excel mostra no máximo 1 048 576 linhas, por isso filtre primeiro. Importe o CSV como UTF-8 (Data, From Text/CSV) para que os nomes com caracteres não latinos apareçam corretamente.

zstd -dc all-data-2026-10-16.jsonl.zst | jq -nr '
  ["Domain","TLD suffix","HTTP status","Technologies"],
  (inputs | [.Domain, ."TLD suffix", ."HTTP status",
             (.Technologies | if . then tojson else null end)])
  | @csv' > all-data.csv
Saída real da amostra de 10 000 linhas
"Domain","TLD suffix","HTTP status","Technologies"
"360.0.bg","0.bg",200,"{""HTTP/2"":{""version"":null},...}"
...  10,001 lines

A partir de um corte

Vendas

Potenciais clientes num só mercado

O corte WooCommerce e depois só um país.

COPY (
  SELECT Domain AS Website, "Country by IP" AS Country
  FROM read_json('webatla-technologies-WooCommerce-2026-10-16.jsonl.zst',
    columns = {'Domain': 'VARCHAR', 'Country by IP': 'VARCHAR', 'PR value': 'DOUBLE'})
  WHERE "Country by IP" = 'DE'
  ORDER BY "PR value" DESC
) TO 'woocommerce-germany.csv';
Saída real da amostra de 10 000 linhas
Website,Country
ariana.ac,DE
fjak.ac,DE
empower.abudhabi,DE
Agências

Lista de upsell: sites HubSpot que também usam WordPress

O corte HubSpot e depois só os stacks com WordPress.

COPY (
  SELECT Domain AS Website, "Country by IP" AS Country
  FROM read_json('webatla-technologies-HubSpot-2026-10-16.jsonl.zst', columns = {
    'Domain': 'VARCHAR', 'Country by IP': 'VARCHAR', 'Technologies': 'JSON'})
  WHERE list_contains(CASE json_type(Technologies) WHEN 'OBJECT' THEN json_keys(Technologies)
    ELSE json_extract_string(Technologies, '$[*]') END, 'WordPress')
) TO 'hubspot-on-wordpress.csv';
Saída real da amostra de 10 000 linhas
Website,Country
ateliercrescendo.ac,US
Operações de vendas

Um ficheiro por território

Divida um corte num CSV por país do servidor.

COPY (
  SELECT Domain AS Website, coalesce("Country by IP", 'unknown') AS Country
  FROM read_json('webatla-technologies-WooCommerce-2026-10-16.jsonl.zst',
    columns = {'Domain': 'VARCHAR', 'Country by IP': 'VARCHAR'})
) TO 'woocommerce-by-country'
  (FORMAT csv, PARTITION_BY (Country), WRITE_PARTITION_COLUMNS true, OVERWRITE);
Saída real da amostra de 10 000 linhas
woocommerce-by-country/Country=DE/data_0.csv
woocommerce-by-country/Country=US/data_0.csv
...
Cabe numa folha de cálculo?Uma folha do Excel comporta 1 048 576 linhas
Sites com HubSpot 375 063 Cabe numa folha
Sites com WordPress 23 798 524 Filtrar ou dividir
All data, o ficheiro completo 420 933 308 Não cabe em nenhuma folha

5 · Carregá-lo

Postgres, Parquet ou um cruzamento com a sua própria lista

PostgreSQL

psql

Cada linha do ficheiro passa a ser uma linha jsonb, com um índice GIN em Technologies.

psql -c 'CREATE TABLE domains (doc jsonb)'
zstdcat technologies-2026-10-16.jsonl.zst \
  | psql -c "\copy domains FROM STDIN WITH (FORMAT csv, QUOTE e'\x01', DELIMITER e'\x02')"
psql -c "CREATE INDEX ON domains USING gin ((doc->'Technologies'))"
psql -c "SELECT doc->>'Country by IP' AS country, count(*) AS sites FROM domains
         WHERE doc->'Technologies' ? 'WordPress' GROUP BY 1 ORDER BY 2 DESC, 1 LIMIT 5"
Saída real da amostra de 10 000 linhas
COPY 10000
 country | sites
---------+-------
 US      |   300
 DE      |   110
 CA      |    29

Parquet

DuckDB

Colunas tipadas, com Technologies como lista de nomes. Pode ser carregado em BigQuery, Snowflake, Spark ou pandas.

CREATE OR REPLACE MACRO techs(t) AS CASE json_type(t) WHEN 'OBJECT'
  THEN json_keys(t) WHEN 'ARRAY' THEN t->>'$[*]' ELSE []::VARCHAR[] END;
COPY (SELECT "Domain" AS domain, "Country by IP" AS country,
             "PR value" AS pr_value, techs("Technologies") AS technologies
      FROM read_json('technologies-2026-10-16.jsonl.zst', columns = {
        'Domain': 'VARCHAR', 'Country by IP': 'VARCHAR',
        'PR value': 'DOUBLE', 'Technologies': 'JSON'}))
TO 'technologies.parquet' (FORMAT parquet);
Saída real da amostra de 10 000 linhas
technologies.parquet: 10000 rows
domain · country · pr_value · technologies (list of names)

Enriqueça a sua própria lista

DuckDB

O seu CSV de um lado, a exportação do outro, cruzados por Domain.

SELECT c.domain, w."Country by IP" AS country, w."Registrar" AS registrar,
       w."HTTP status" AS http, w."Domain creation date"[:10] AS created
FROM read_csv('my-domains.csv') c
LEFT JOIN read_json('all-data-2026-10-16.jsonl.zst', columns = {
    'Domain': 'VARCHAR', 'Country by IP': 'VARCHAR', 'Registrar': 'VARCHAR',
    'HTTP status': 'INTEGER', 'Domain creation date': 'VARCHAR'}) w
  ON w."Domain" = lower(trim(c.domain))
ORDER BY 1;
Saída real da amostra de 10 000 linhas
domain              country  registrar                    http  created
Tamm.AbuDhabi       AE       ADSIC Registry Operator      200   2018-07-09
easy.ac             US       MarkMonitor Inc.             200   2014-02-27
global.abb          US       CSC Corporate Domains, Inc.  301   2019-10-03

6 · Atualizações diárias

Veja o que mudou de um dia para o outro

Todos os dias chega uma nova exportação. Compare dois dias por Domain e envie apenas as alterações para os seus sistemas a jusante. Troque a ordem dos dois ficheiros para listar os domínios que saíram.

COPY (
  SELECT "Domain" FROM read_json('all-active-domains-2026-10-16.jsonl.zst',
                                 columns = {'Domain': 'VARCHAR'})
  EXCEPT
  SELECT "Domain" FROM read_json('all-active-domains-2026-10-15.jsonl.zst',
                                 columns = {'Domain': 'VARCHAR'})
) TO 'new-since-yesterday.csv' (HEADER false);

7 · Erros comuns

Onde é fácil tropeçar

Os nomes dos campos têm espaços

Coloque-os entre aspas, tanto em SQL como em jq.

jq: ."TLD suffix"SQL: "TLD suffix" = 'com.sa'

DNS Status é texto

Contém o texto "TRUE" ou "FALSE", não um booleano, por isso compare-o como texto.

select(."DNS Status" == "TRUE")

Technologies tem várias formas

Um mapa de nomes para versões (ou para objetos com uma versão), uma lista de nomes ou null. Leia as chaves de um mapa e os itens de uma lista e obterá sempre uma única lista.

jq: (.Technologies // []) | if type == "object" then keys else . end

Nunca descomprima um ficheiro completo para o disco

O ficheiro All data completo tem cerca de 34 GB comprimido e várias centenas de GB descomprimido. Leia-o em fluxo, como todas as receitas aqui.

Verifique as primeiras linhas

No DuckDB, um nome de coluna mal escrito devolve NULL e não um erro.

8 · Resolução de problemas

Quando algo corre mal

SintomaCausa e solução
zstd: … unsupported format na amostra gratuitaA amostra é JSONL simples, sem compressão. Passe-a diretamente ao jq ou use o zstdcat, que lê ambos.
O Python devolve muito menos linhas do que zstd -dc FILE | wc -lO ficheiro tem vários frames zstd e foi lido com uma chamada que termina depois do primeiro. Use stream_reader com read_across_frames=True, como na receita Python.
jq: syntax error em .TLD suffixPonha entre aspas os nomes que contêm espaços: ."TLD suffix"
O SQL devolve 0 linhas sem erro'Country by IP' entre aspas simples é um texto, não uma coluna. Use aspas duplas para nomes de colunas.
O DuckDB falha a meio com Expected OBJECT, but got ARRAYA deteção automática do esquema olha apenas para as primeiras linhas. Declare as colunas, com os campos aninhados como JSON.
O ficheiro descarregado está completo?zstd -tq FILE && echo OK apresenta OK quando o ficheiro descomprime por completo.

Todas as receitas funcionam no ficheiro diário completo

Acesso mensal ou anual, uma nova exportação todos os dias e uma API para cortes. Qualquer conta pode ainda descarregar uma amostra gratuita de 10 000 linhas de cada dataset.