Интеграция SEMrush API для SEO-аналитики сайта
SEMrush API открывает данные, которые вручную из интерфейса собирать нерационально: органический трафик и ключевые слова конкурентов, позиции по тысячам запросов, ссылочный профиль, технические аудиты. API позволяет включить эти данные в собственную аналитическую систему, сравнивать несколько доменов в одном дашборде и автоматизировать конкурентный анализ.
Аутентификация и базовый клиент
SEMrush API использует API-ключ как query-параметр. Формат ответа — CSV (по умолчанию) или JSON для некоторых эндпоинтов:
import requests
import csv
import io
from typing import Literal
class SemrushClient:
BASE_URL = 'https://api.semrush.com'
ANALYTICS_URL = 'https://api.semrush.com/analytics/v1'
def __init__(self, api_key: str):
self.api_key = api_key
self.session = requests.Session()
def _request(self, params: dict) -> list[dict]:
params['key'] = self.api_key
resp = self.session.get(self.BASE_URL, params=params, timeout=30)
resp.raise_for_status()
if resp.text.startswith('ERROR'):
raise ValueError(f'SEMrush API error: {resp.text}')
reader = csv.DictReader(io.StringIO(resp.text), delimiter=';')
return list(reader)
Органические ключевые слова домена
def get_organic_keywords(
self,
domain: str,
database: str = 'ru', # ru, us, uk, de, fr и др.
limit: int = 1000,
offset: int = 0,
sort_by: str = 'tr', # tr=traffic, po=position, nq=search volume
) -> list[dict]:
params = {
'type': 'domain_organic',
'domain': domain,
'database': database,
'display_limit': limit,
'display_offset': offset,
'display_sort': f'{sort_by}_desc',
'export_columns': 'Ph,Po,Pp,Pd,Nq,Cp,Ur,Tr,Tc,Co,Nr,Td',
# Ph=keyword, Po=position, Pp=prev_position, Nq=search_vol,
# Cp=CPC, Ur=URL, Tr=traffic, Tc=traffic_cost, Co=competition
}
return self._request(params)
Поля ответа: Ph — ключевое слово, Po — позиция, Nq — месячный объём поиска, Tr — расчётный трафик, Ur — URL страницы.
Сравнение с конкурентами
def compare_domains(
self,
domains: list[str],
database: str = 'ru',
) -> list[dict]:
results = []
for domain in domains:
params = {
'type': 'domain_ranks',
'domain': domain,
'database': database,
'export_columns': 'Db,Dn,Rk,Or,Ot,Oc,Ad,At,Ac,Sh,Sv',
# Or=organic_keywords, Ot=organic_traffic, Rk=semrush_rank
}
data = self._request(params)
if data:
results.append({'domain': domain, **data[0]})
return results
Конкуренты по органике
def get_organic_competitors(
self,
domain: str,
database: str = 'ru',
limit: int = 20,
) -> list[dict]:
params = {
'type': 'domain_organic_organic',
'domain': domain,
'database': database,
'display_limit': limit,
'display_sort': 'np_desc', # по количеству пересекающихся ключевых слов
'export_columns': 'Dn,Cr,Np,Or,Ot,Oc,Ad',
# Dn=domain, Cr=common_keywords, Np=competitor_keywords, Or=organic_keywords
}
return self._request(params)
Backlink-аудит через API
def get_backlinks(
self,
target: str,
limit: int = 1000,
target_type: Literal['root_domain', 'domain', 'url'] = 'root_domain',
) -> list[dict]:
params = {
'type': 'backlinks',
'target': target,
'target_type': target_type,
'display_limit': limit,
'display_sort': 'page_ascore_desc',
'export_columns': 'source_url,target_url,anchor,source_title,page_ascore,domain_ascore,nofollow,first_seen,last_seen',
}
return self._request(params)
def get_referring_domains(self, target: str, limit: int = 500) -> list[dict]:
params = {
'type': 'backlinks_refdomains',
'target': target,
'target_type': 'root_domain',
'display_limit': limit,
'display_sort': 'domain_ascore_desc',
'export_columns': 'domain,domain_ascore,backlinks_num,ip,country,first_seen',
}
return self._request(params)
Мониторинг позиций
SEMrush Position Tracking доступен через отдельный API для проектов. Создание проекта и отслеживание ключевых слов программно:
def get_position_tracking(self, project_id: str) -> list[dict]:
# Position Tracking API использует другой базовый URL
resp = self.session.get(
f'{self.ANALYTICS_URL}/projects/{project_id}/tracking/position',
params={'key': self.api_key},
timeout=30,
)
resp.raise_for_status()
return resp.json().get('data', [])
Ежедневный сбор данных и хранение
import psycopg2
from datetime import date
def collect_daily_metrics(client: SemrushClient, domains: list[str], db_conn):
today = date.today().isoformat()
for domain in domains:
try:
ranks = client.compare_domains([domain])[0] if True else {}
keywords = client.get_organic_keywords(domain, limit=500)
with db_conn.cursor() as cur:
# Общие метрики домена
cur.execute('''
INSERT INTO semrush_domain_metrics
(domain, snapshot_date, organic_keywords, organic_traffic, semrush_rank)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (domain, snapshot_date) DO UPDATE SET
organic_keywords = EXCLUDED.organic_keywords,
organic_traffic = EXCLUDED.organic_traffic
''', (
domain,
today,
ranks.get('Or', 0),
ranks.get('Ot', 0),
ranks.get('Rk', 0),
))
# Топ ключевых слов
for kw in keywords[:200]:
cur.execute('''
INSERT INTO semrush_keyword_positions
(domain, keyword, position, search_volume, url, snapshot_date)
VALUES (%s, %s, %s, %s, %s, %s)
ON CONFLICT DO NOTHING
''', (
domain,
kw.get('Keyword') or kw.get('Ph'),
kw.get('Position') or kw.get('Po'),
kw.get('Search Volume') or kw.get('Nq'),
kw.get('URL') or kw.get('Ur'),
today,
))
db_conn.commit()
except Exception as e:
print(f'Error collecting for {domain}: {e}')
CREATE TABLE semrush_domain_metrics (
id SERIAL PRIMARY KEY,
domain TEXT NOT NULL,
snapshot_date DATE NOT NULL,
organic_keywords INTEGER,
organic_traffic INTEGER,
semrush_rank INTEGER,
paid_keywords INTEGER,
paid_traffic INTEGER,
UNIQUE(domain, snapshot_date)
);
CREATE TABLE semrush_keyword_positions (
id SERIAL PRIMARY KEY,
domain TEXT NOT NULL,
keyword TEXT NOT NULL,
position INTEGER,
search_volume INTEGER,
url TEXT,
snapshot_date DATE NOT NULL,
UNIQUE(domain, keyword, snapshot_date)
);
Расчёт стоимости API-запросов
SEMrush API тарифицируется в «API units». Стоимость одного запроса зависит от типа и объёма:
-
domain_organic(100 строк) — 10 units -
backlinks(100 строк) — 40 units -
domain_ranks— 10 units
На плане Guru — 3000 units/месяц. На Business — 10 000. Для ежедневного мониторинга 5 доменов (метрики + 200 ключевых слов) расход примерно 500–700 units в день — Business plan необходим.
Оптимизация: не запрашивать полные списки бэклинков ежедневно, только ключевые метрики. Полный backlink-аудит — раз в неделю.
Сроки
Базовая интеграция с ежедневным сбором метрик домена и топ-200 ключевых слов — 2–3 рабочих дня. С анализом конкурентов, backlink-аудитом, алертами и визуализацией в Grafana/Metabase — 5–7 дней.







