Рецепт

Поиск обратных ссылок на Python: список потенциальных площадок за сорок строк

Найдите домены, которые ссылаются на ваших конкурентов, но не на вас, оцените их в одном запросе и отсортируйте CSV. Пример с вымышленными числами приведен ниже.

Рабочий верстак с инструментами для черчения и красной нитью, соединяющей точки на бумаге

Логика перед кодом

Для решения задачи достаточно трех вызовов. intersect принимает от двух до десяти доменов и возвращает те, которые ссылаются на несколько из них. refdomains для вашего сайта дает множество доменов, которые нужно вычесть. Затем bulk_dr оценивает оставшиеся варианты.

Стоимость одного запуска мала, и эту арифметику стоит проделать один раз. Два кредита за пересечение, два за ваш собственный список, один за оценку до 2000 доменов. Пять кредитов — это $0.0005.

Порядок важен. Вычитайте перед оценкой.

Часто сначала оценивают всё, а затем фильтруют. Это неверный подход. Оценка стоит недорого, но занимает много времени, если CSV содержит пятьдесят тысяч строк. Сначала сократите список по пересечению, запросите DR для оставшихся вариантов и храните всё в обычном словаре, чтобы следующий запуск мог использовать результаты вчерашнего дня.

prospects.py

Домены в RIVALS — это заглушки. Имена полей читаются через .get, поэтому перед тем как полагаться на столбец, проверьте одну сырую строку из вашего собственного запуска.

python
import csv, json, os, urllib.request as u, urllib.parse as p
KEY = os.environ['LZ_KEY']
ME = 'mysite.example'
RIVALS = ['rival-a.example', 'rival-b.example', 'rival-c.example']
def get(**kw):
    q = p.urlencode(kw)
    with u.urlopen(f'https://linkzoid.pro/api.php?{q}&key={KEY}', timeout=30) as r:
        d = json.load(r)
    if not d['ok']:
        raise SystemExit(d)
    return d
gap = get(action='intersect', q=','.join(RIVALS), per=1000)['rows']
mine = {r.get('domain') for r in get(action='refdomains', q=ME, per=1000)['rows']}
fresh = [r.get('domain') for r in gap if r.get('domain') not in mine]
scores = get(action='bulk_dr', domains=','.join(fresh[:2000]))['rows']
with open('prospects.csv', 'w', newline='') as f:
    wr = csv.writer(f)
    for row in scores:
        wr.writerow([row.get('domain'), row.get('dr')])
print(len(fresh), 'candidates')

Рабочий пример, вымышленные числа

Вымышленный запуск для небольшого нишевого блога; ваши результаты будут отличаться
ШагСтрок на выходеКредиты
Пересечение 3 конкурентов640 доменов2
Минус собственные реферальные доменыОсталось 4102
bulk_dr для 410 доменов410 оценено1
Оставляем DR 20 и вышеоколо 1200
Ручная проверка топ-30Открыто 30 страниц0

От CSV к рассылке без спама

01

Сортировка по пересечению

Домены, которые ссылаются на два или три ваших конкурента, — это те, у которых есть тематическая причина ссылаться на вас. Поместите их в начало списка.

02

Откройте тридцать страниц вручную

Посмотрите на страницу, которая ссылается на конкурента. Это список ресурсов, обзор или новостная статья? Лишь некоторые из них принимают новые записи.

03

Напишите одну строку с обоснованием

Объясните, что добавляет ваша страница, чего нет на странице конкурента. Если не можете сформулировать это в одном предложении, пропустите этот сайт.

04

Фиксируйте, что отправили

Добавьте столбцы с датой, контактом и результатом в тот же CSV и закоммитьте его. В следующем квартале вы скажете себе спасибо.

Ошибки и их исправление

Скрипты поиска потенциальных площадок ошибаются в одних и тех же местах
ОшибкаПочему это вредитИсправление
Сортировка только по DRКрупные каталоги и скрейперы оказываются наверхуСортируйте сначала по количеству пересечений, затем по DR
Рассылка всем, кто выше определенного порогаВыглядит как спам, тратит доброе имяОткройте топ-30 вручную
Ручная URL-кодировкаЗапятые и слэши ломают запросИспользуйте urllib.parse.urlencode
Отправка 3000 доменов в одном запросеПревышение лимита в 2000Разбейте список на части, один кредит за часть
Доверие DR как показателю качестваЭто логарифмическое количество реферальных доменовРассматривайте его как ключ сортировки, а не как вердикт
Два маленьких куста и одно большое дубовое дерево, делящие солнечный свет в саду

Выбор конкурентов, у которых есть ваша аудитория

Конкуренты определяют, что вернет пересечение. Поиск обратных ссылок не лучше, чем список, который вы ему подаете. Три прямых конкурента с одной аудиторией дают чистое пересечение, в то время как крупный издатель, ранжирующийся по всем запросам, даст вам тысячи ссылок, которые ничего не говорят о вашей странице.

Допустим, вы ведете небольшой блог о ремонте велосипедов. Ваши конкуренты могут быть двумя блогами о ремонте и одним магазином с сильным разделом руководств. Это отличный набор. Добавьте национальное издание, и список заполнится страницами, которые никогда не станут ссылаться на блог о велосипедах.

Два-десять доменов — это окно, которое принимает конечная точка, поэтому выбирайте набор в этих пределах. Держите список достаточно коротким, чтобы вы могли назвать каждого конкурента по памяти. Короткие списки легче обосновать.

Почему гигантские хабы загрязняют набор

Каталоги и агрегаторы ссылаются почти на всё. Они появляются в каждом пересечении и засыпают те несколько доменов, которые ссылаются из реального интереса. Читайте верх отсортированного списка, прежде чем доверять ему.

Обычный файл исключений исправляет большую часть этой проблемы. Держите домены, которые вы никогда не хотите видеть, в одном текстовом файле, по одному на строку. Загрузите их в множество и отбрасывайте совпадения перед вызовом оценки, чтобы кредиты тратились только на кандидатов, достойных прочтения.

Разделение конкурентов и вашего собственного сайта

Ваш собственный домен никогда не должен быть конкурентом. Это звучит очевидно, но скопированный список со старого проекта часто содержит его, и тогда пересечение сообщает о ваших собственных ссылках на вас самих.

Поместите конкурентов в словарь конфигурации в начале скрипта с комментарием о том, почему каждый из них там. В следующем месяце вы вспомните причину, и так же поступит чужой человек, читающий репозиторий.

Чтение сырых строк перед фильтрацией

Код читает каждое поле через .get, что предотвращает сбой при отсутствии ключа. Это также скрывает неверный ключ. Выведите одну строку из пересечения перед тем, как писать любой фильтр, и посмотрите на имена полей и типы каждого значения.

Оценка, пришедшая в виде текста, сортируется как текст, поэтому 9 окажется после 80. Преобразуйте её в число один раз сразу после вызова, и остальная часть скрипта останется простой.

Нормализация доменов перед сравнением

Один и тот же сайт может появиться с префиксом www. в одном списке и без него в другом. Приведите всё к нижнему регистру и удалите префикс перед сравнением множеств. В противном случае ваш собственный сайт может выглядеть как новый кандидат.

Конечные слэши и случайные пробелы из вставленного списка вызывают те же проблемы. Функция очистки в одну строку стоит дешевле, чем один потраченный впустую вызов оценки.

Храните dated-копию каждого запуска

Записывайте каждый запуск в файл с датой и сохраняйте предыдущий. Так вы сможете отличить новых кандидатов от тех, которых вы уже видели, и увидеть, когда конкурент начал ссылаться на что-то новое.

Файлы с датой — также самый простой способ отладки странного результата. Откройте два файла рядом, и изменение обычно очевидно.

Оценивайте только то, что выжило

Массовый вызов принимает до 2000 доменов за один кредит. Передавайте ему выживших после вычитания, а не всё пересечение. В вымышленном примере выше 640 строк и 410 строк стоят одинаково при оценке в один вызов, но меньший список гораздо легче читать.

Каменная весы с латным грузом и грубым камнем в отдельных чашах

Вопросы перед запуском поиска

Большинство вопросов, которые люди задают в этой части работы, сводятся к стоимости, сортировке и тому, что происходит при сбое запроса.

Дорого ли строить список потенциальных площадок?

Недорого. Рецепт использует intersect, refdomains и bulk_dr, поэтому пять кредитов за запуск при указанном размере, что составляет $0.0005. Повторный запуск в следующем месяце обойдется столько же. Ваша собственная тратится на чтение страниц — это реальная стоимость.

Почему не отсортировать пересечение по DR и на этом остановиться?

DR считает реферальные домены в логарифмическом масштабе. Крупные каталоги поднимаются наверх независимо от их релевантности, поэтому сортируйте сначала по пересечению, а DR используйте как разделитель, а не как основной ключ.

Могу ли я отправить рассылку всем из CSV?

Можете, но это плохое использование списка. Откройте страницу, которая ссылается на конкурента, решите, подходит ли новая запись, и только тогда пишите. CSV — это шорт-лист, а не список для рассылки.

С скольких конкурентов мне начать?

Три — хорошее начало, в пределах диапазона от двух до десяти, который принимает пересечение. Добавляйте больше, только если первый запуск возвращает слишком мало строк для ранжирования.

Что если у моего собственного домена еще нет реферальных доменов?

Тогда вычитание ничего не удалит, и каждая строка пересечения станет кандидатом. Это правильно, но список будет длинным. Сократите его по пересечению и прочитайте топ-тридцать вручную.

Нужен ли скрипту платный ключ?

Да. Вызовы intersect, refdomains и bulk_dr оплачиваются кредитами. Бесплатное действие overview не требует ключа, а регистрационного кредита в $100 хватит на множество запусков такого размера.

Перед отправкой любого сообщения

  • Откройте страницу кандидата и подтвердите, что она ссылается на конкурента, а не просто на список ссылок.
  • Проверьте, подходит ли страница вашей аудитории, а не только вашему ключевому слову.
  • Удалите любой домен, которому вы уже писали, и зафиксируйте дату рядом с ним.
  • Напишите одно предложение о том, что добавляет ваша страница, или отбросьте кандидата.
  • Отправляйте небольшими партиями, чтобы ответы действительно можно было прочитать.

Запуск поиска по расписанию

Списки потенциальных площадок устаревают медленнее, чем ожидают многие. Ежемесячно — более чем достаточно. Новые ссылки от конкурента появляются при ежемесячном обновлении, поэтому запуск каждые несколько недель ловит большинство из них. Еженедельные запуски в основном воспроизводят файл прошлой недели, поэтому тот же поиск обратных ссылок может работать без присмотра без большого шума.

Разумный ритм — ежемесячная оценка и быстрый просмотр верхних строк после каждого запуска. Держите шаг вычитания в той же задаче, чтобы список никогда не включал то, что у вас уже есть.

Держите ключ вне файла

Скрипт читает ключ из окружения, поэтому он никогда не лежит в репозитории. Установите LZ_KEY как секрет в вашем планировщике или экспортируйте его из файла, который остается вне git.

Строка crontab может вызывать тот же скрипт с переменной, установленной перед ним. Проверьте, чтобы файл, содержащий ключ, имел строгие права доступа на сервере.

Сбой перед записью CSV

401 или 402 должны остановить запуск, так же как и флаг ok, который читается как false. Код вызывает исключение до открытия файла, поэтому неудачный запуск никогда не перезапишет вчерашний CSV частичным.

Фиксируйте расходы с каждым запуском

Каждый ответ содержит _credits, поэтому выводите баланс в конце задачи. За несколько месяцев эта строка покажет, стоит ли расписание того, что вы планировали, и не начался ли цикл повторного получения страниц.

Сопоставьте это с SQLite diff, если хотите историю в базе данных вместо папки с файлами.

Слово о том, что DR может и не может сказать

DR здесь — это round(100 * log(ref_domains + 1) / log(20,000,000)). Он растет с количеством реферальных доменов и ничем другим. Имейте это в виду. Сайт может быть на уровне 55 и все равно быть бесполезным для вас.

Используйте его для ранжирования, затем читайте. Посмотрите, что публикует сайт, ссылается ли он на сотню нерелевантных магазинов, и изменилось ли что-то на нем недавно. Эти проверки занимают минуту на сайт, и ни один скрипт их не заменит.

Как только список станет чистым, храните его как файл с датой и запускайте снова через месяц. Руководство по Actions показывает, как его запланировать, а сравнение n8n охватывает вариант без кода, если ваш специалист по рассылкам предпочитает его.

Примечания о рейтинге и размере

Каждый вызов возвращает до 1000 строк и оплачивается один раз, поэтому прохождение через 5000 строк пересечения стоит 10 кредитов, или $0.001. Глубокая пагинация останавливается на 50 000 строк. Используйте sort и order=desc на сервере, а не сортируйте огромный список в Python после.