Анализ ссылочного графа веб-архива
Ссылочный граф (link graph) — это сеть, где узлы это URL или домены, а рёбра — гиперссылки между страницами. Анализ графа полезен для:
- Изучения информационных потоков в СМИ.
- Обнаружения «информационных пузырей» и эхо-камер.
- Исследования медиа-экосистемы.
- Маппинга бот-сетей и спама.
Пример: какие сайты ссылаются на официальные заявления правительства? Какой процент ссылок ведёт на независимые СМИ vs контролируемые? Кто ссылается на расследование?
Входные данные
WAT — метаданные с гиперссылками
Common Crawl предоставляет WAT — JSON-файлы с извлечёнными метаданными, включая гиперссылки.
{
"warcinfo": {...},
"Envelope": {
"WARC-Header-Metadata": {...},
"WARC-Target-URI": "https://example.com/article",
"Payload-Metadata": {
"HTTP-Response-Metadata": {...}
},
"Containers": {
"HTML-Metadata": {
"Link": [
{"href": "https://other.com/page", "path": "a", "rel": "no-follow"},
{"href": "https://example.com/related", "path": "section"}
],
"Head": {
"Title": "Article title",
"Metas": [{"name": "author", "content": "..."}]
}
}
}
}
}
Что даёт WAT:
- Все ссылки с каждой страницы.
- Тип ссылки (
rel="nofollow",rel="sponsored"и т. д.). - Заголовок страницы.
- Метатеги.
WARC + извлечение
Если у вас WARC без WAT, можно извлечь ссылки програм мно:
from warcio.archiveiterator import ArchiveIterator
from bs4 import BeautifulSoup
links_graph = {} # URL → [links]
with open("archive.warc.gz", "rb") as stream:
for record in ArchiveIterator(stream):
if record.rec_type != "response":
continue
url = record.rec_headers.get_header("WARC-Target-URI")
content_type = record.http_headers.get_header("Content-Type", "")
if "text/html" not in content_type:
continue
payload = record.content_stream().read()
soup = BeautifulSoup(payload, "html.parser")
for a in soup.find_all("a", href=True):
links_graph.setdefault(url, []).append(a["href"])
Инструменты
Hyphe (research-grade)
Hyphe — специализированный инструмент для исследования link-graph в веб-архивах от Sciences Po Medialab.
# Установка через Docker
docker pull medialab/hyphe
docker run -p 8080:8080 medialab/hyphe
Что умеет:
- Сбор по URL + старт-листам (seeds).
- Автоклассификация узлов на веб-акторов (СМИ, академия и т.д.).
- Tagging, веб-интерфейс.
- Визуализация сетей.
Когда использовать:
- Академические исследования медиа-экосистем.
- Подробный анализ с curation.
WebGraph (Java фреймворк)
WebGraph — фреймворк для сжатого хранения и обработки огромных графов.
import it.unimi.dsi.webgraph.ImmutableGraph;
import it.unimi.dsi.webgraph.BVGraph;
// Загрузка сжатого графа
ImmutableGraph graph = BVGraph.load("my-graph.bvg");
// Метрики
NodesIterator iter = graph.nodes();
int nodes = (int) graph.numNodes();
Особенности:
- Сжимает граф дружбы Facebook в 4 ГБ на диске.
- Поддерживает PageRank, HITS, центральности.
- Java-only, но стабильный.
pywb (для коллекций)
pywb имеет встроенные возможности извлечения ссылок через wbui.
DuckDB + custom Graph (proto)
DuckDB можно использовать для быстрого прототипирования:
-- Создаём граф как edge-list
CREATE TABLE links AS
SELECT
src_url AS src,
dst_href AS dst
FROM parsed_wat
WHERE rel IS NULL OR rel NOT LIKE '%nofollow%';
-- Top доменов по out-degree (сколько ссылок уходит наружу)
SELECT
regexp_extract(src, '://([^/]+)', 1) AS domain,
COUNT(DISTINCT dst) AS out_links
FROM links
GROUP BY domain
ORDER BY out_links DESC
LIMIT 20;
-- PageRank (через DuckDB-расширения или эмулируя SQL)
-- или экспорт в NetworkX / iGraph для серьёзного анализа
NetworkX (Python)
import networkx as nx
G = nx.DiGraph()
for src, dst in links:
G.add_edge(src, dst)
# PageRank
pagerank = nx.pagerank(G, max_iter=100)
top = sorted(pagerank.items(), key=lambda x: x[1], reverse=True)[:10]
for url, score in top:
print(f"{score:.4f}\t{url}")
Gephi (визуализация)
Gephi — открытый инструмент для визуализации графов.
# Экспорт из Python
import networkx as nx
import igraph as ig
# NetworkX → gephi GEXF
nx.write_gexf(G, "graph.gexf")
# iGraph → gephi GEXF
ig.save(G_igraph, "graph.gexf")
Открыть в Gephi → Layout (ForceAtlas2, Fruchterman-Reingold) → видим красивый граф.
Метрики графа
PageRank
Мера «важности» узла. Чем больше важных узлов на тебя ссылаются, тем ты важнее.
nx.pagerank(G)
Centrality (betweenness)
Мера «посредничества» — узлы, через которые проходит много кратчайших путей.
nx.betweenness_centrality(G)
In-degree / out-degree
Количество входящих / исходящих ссылок. Прямые метрики влияния.
in_deg = sorted(G.in_degree(), key=lambda x: x[1], reverse=True)
out_deg = sorted(G.out_degree(), key=lambda x: x[1], reverse=True)
Connected components
Сколько «изолированных» групп в графе. Полезно для выявления эхо-камер.
components = list(nx.weakly_connected_components(G))
print(f"Связных компонент: {len(components)}")
Clustering coefficient
Мера «кластеризации» — насколько друзья узла являются друзьями друг друга.
nx.average_clustering(G)