Как использовать LinkExchange
Здесь описано использование "голой" LinkExchange без использования кода интеграции с конкретными фрейворками и приложениями. Код интеграции со сторонними ферйворками упрощает подключение к ним этой библиотеки, информация на странице LinkExchange и фреймворки.
Создание площадки
Прежде всего нужно создать площадку и указать список клиентов служб, которые будут использоваться:
>>> import linkexchange >>> from linkexchange.clients.sape import SapeClient >>> clients = [SapeClient(user = 'user123456789', db_driver = ('mem',))] >>> platform = linkexchange.Platform(clients)
В данном примере мы явно импортировали класс SapeClient, создали экземпляр класса, и передали его как элемент списка в конструктор площадки. Но можно обойтись и без явного импорта и создания экземпляра:
>>> clients = [('sape', [], dict(user = 'user123456789', db_driver = ('mem',)))]
Здесь клиент обозначен как картеж, первый элемент которого - имя клиента (по сути имя точки входа словами setuptools), второй и третий - аргументы, передаваемые в конструктор класса. Аналогично можно указывать драйвер БД (в данном примере это аргумент db_driver) и классы форматирования, которые будут рассмотрены ниже.
Подробную информацию о параметрах клиентов можно найти в исходниках или в описании файла конфигурации.
Экземпляр класса Platform не хранит связанную с HTTP-запросом информацию, по этому площадку удобно создать один раз при инициализации приложения, а затем многократно использовать ее методы для получения ссылок при обработке HTTP-запросов.
Получение необработанного списка ссылок
Экземпляры класса PageRequest предназначены для передачи информации об HTTP-запросе. Эта информация передается площадке, затем площадка передает ее клиентам служб, а те, в свою очередь, на основе этой информации возвращают ссылки для размещения на заданной странице.
Попробуем получить необработанный список ссылок для страницы http://example.com/:
>>> req = linkexchange.PageRequest(host = 'example.com', uri = '/') >>> lx = platform.get_raw_links(req) >>> lx[0] u'<a href="url1">link1</a>' >>> lx[1] u'<a href="url2">link2</a>'
Для получения необработанного списка ссылок используется метод get_raw_links(), которому в качестве единственного аргумента передается экземпляр PageRequest.
При создании экземпляра PageRequest необходимо передать полную информацию о запрашиваемой странице, это можно сделать передав конструктору аргументы host и uri, которые задают хост (имя домена) и путь, либо аргумент url, который задает полный URL. Рекомендуется также передать куки в аргументе cookies и IP-адрес удаленной машины в аргументе remote_addr.
Такие ошибки как ошибки соединения с удаленными службами и ошибки при обработке результатов обращения к службам, которые могут возникать в работе клиента, обрабатываются площадкой. И в случаи такой ошибки исключение не возникает, а в коде ссылки присутствует HTML-комментарий с описанием проблемы. Это делает ваше веб-приложение более устойчивым, страницы вашего сайта по прежнему доступны посетителям, не смотря на проблемы при обращении к удаленной службе за ссылками.
Получение ссылок разбитых на блоки
Блоки ссылок определятся классами форматирования. Например мы хотим получить два блока ссылок: две ссылки в первом и все остальные во втором, первый оформлен как элемент DIV, содержащий в себе ссылки разделенные знаком "|" pipe, а второй - в виде ненумерованного списка (элемент UL). Для этого определяем два объекта форматирования (экземпляры классов форматирования):
>>> from linkexchange.formatters import InlineFormatter, ListFormatter >>> formatters = [InlineFormatter(2, delimiter = '|'), ... ListFormatter(None)]
Теперь используем метод get_blocks() для получения списка ссылок:
>>> bx = platform.get_blocks(req, formatters) >>> bx[0] u'<div><a href="url1">link1</a>|<a href="url2">link2</a></div>' >>> bx[1] u'<ul><li><a href="url3">link3</a></li><li><a href="url4">link4</a></li></ul>'
Также как и клиенты служб объекты форматирования можно указывать без явного импорта и создания экземпляров:
>>> formatters = [('inline', [2], dict(delimiter = '|')), ... ('list', [None], )]
Классы форматирования имеют множество параметров, которые позволяют настраивать форматирование блоков ссылок, подробную информацию смотрите в исходниках или в описании файла конфигурации.
Перестановка блоков ссылок
Чтобы снизить риск попадания сайта в бан поисковых систем рекомендуется размещать блоки ссылок на разных страницах в разных местах. В этом поможет функция rearrange_blocks().
- linkexchange.utils.rearrange_blocks(request, blocks, rearrange_map)
- Делает перестановку блоков ссылок blocks в соответствии с правилами rearrange_map и значением request.uri и возвращает новый список блоков. request - объект PageRequest; blocks - список блоков ссылок; rearrange_map - список правил перестановки. Каждое правило представлено в виде кортежа (i1, i2, o1, o2), где i1 и i2 - начальный и конечный индекс исходного массива блоков ссылок, o1 и o2 - начальный и конечный индекс выходного массива.
Например, имеется 2 блока ссылок, и на странице есть 5 мест, где можно их разместить, при этом размещение блоков на каждой отдельной странице должно быть разным:
>>> import linkexchange >>> from linkexchange.utils import rearrange_blocks >>> bx = [u'<!-- block1 -->', u'<!-- block2 -->'] >>> req = linkexchange.PageRequest(host = 'example.com', uri = '/') >>> rearrange_blocks(req, bx, [(0, 2, 0, 5)]) [u'', u'', u'<!-- block1 -->', u'<!-- block2 -->', u''] >>> req = linkexchange.PageRequest(host = 'example.com', uri = '/page1') >>> rearrange_blocks(req, bx, [(0, 2, 0, 5)]) [u'<!-- block2 -->', u'', u'', u'', u'<!-- block1 -->']
Использование контекстных ссылок
Контекстные ссылки - это ссылки которые продаются в контенте страницы и позволяют рекламодателям покупать рекламные места внутри существующих текстов на страницах Вашего сайта.
Для контекстных ссылок в LinkExchange предусмотрена функция фильтрации контента. Объект площадки имеет метод content_filter(), который принимает объект запроса и строку контента, и возвращает отфильтрованный контент.
- linkexchange.Platform.content_filter(request, content)
- Обрабатывает контент в параметре content в соответствии с запросом request. request - экземпляр класса PageRequest; content - unicode-строка содержащая HTML-код для обработки. Возвращает обработанный (отфильтрованный) контент.
Поддережка контекстных ссылок Sape реализована отдельным клиентом sape_context (класс SapeContextClient).
>>> import linkexchange >>> clients = [('sape_context', [], dict(user = 'user123456789', db_driver = ('mem',)))] >>> platform = linkexchange.Platform(clients) >>> req = linkexchange.PageRequest(host = 'example.com', uri = '/', cookies = cookies_dict) >>> new_content = platform.content_filter(req, old_content)
Заметьте что куки нужно передать обязательно чтобы клиент мог определить когда на сайт заходит бот системы Sape.
База данных клиента
Клиенты используют базу данных для быстрого доступа к данным (ссылки, конфигурация). Базу данных реализуют драйвера баз данных. Драйвер указывается в параметре db_driver клиента.
В примерах выше использовался MemMultiHashDriver, который хранит данные в оперативной памяти, его можно использовать в некоторых случаях, когда сайт работает в продолжительном окружении (persistence environment) и общее количество продаваемых ссылок не велико. Но в большинстве случаев для хранения данных необходимо внешнее хранилище.
На данный момент имеется реализация базы данных с использованием модуля shelv.
>>> clients = [('sape', [], dict(user = 'user123456789', db_driver = ('shelv', [] dict( ... filename = 'sape-XXX.db' ))))]
На основе указанного параметра filename формируется имя файла, в котором будет хранится база данных. Если передана строка содержащая 'XXX', то конечное имя файла будет filename.replace('XXX', host), если последовательность 'XXX' не встречается, то имя файла будет filename + host, где host - доменное имя сайта. Можно также передавать в качестве значения filename функцию, тогда имя файла будет filename(host).
Подробную информацию о всех драйверах баз данных и их параметрах можно найти в исходниках или в описании файла конфигурации.
Файл конфигурации
Библиотека LinkExchange включает функцию linkexchange.file_config(), которая создает площадку, клиенты и объекты форматирования по заданному конфигурационному файлу. Файл конфигурации LinkExchange имеет формат в стиле INI, и содержит определения клиентов, объектов форматирования и дополнительных опций.
- linkexchange.file_config(vars, fname[, defaults[, prefix]])
- Считывает файл конфигурации, и при успешной его обработке создает в словаре vars следующие значения: vars['platform'] - объект площадки с добавленными в нее клиентами; vars['formatters'] - список объектов форматирования; vars['options'] - словарь дополнительных опций. Аргумент fname - имя файла или файловый объект; defaults - словарь значений для строковой интерполяции; prefix - общий префикс для ключей в vars.
Обновление базы данных
По умолчанию база данных клиента обновляется автоматически при попытке извлечь ссылки. Когда база данных становится старее чем значение параметра db_lifetime (по умолчанию 1 час), то прежде чем вернуть ссылки клиент выполняет ее обновление.
Однако, такой способ может вызвать "подвисание" на сайте, если удаленный сервер службы будет задерживать ответ. Решением этой проблемы будет отключение автоматического обновления БД при запросе и выполнение обновления периодически при помощи скрипта lxrefresh из cron.
Чтобы отключить автоматическое обновление нужно параметру db_lifetime установить значение None, а для периодического обновления воспользоваться такой конфигурацией cron:
0 * * * * lxrefresh -c путь/к/linkexchange.cfg -r example.com
Отладка
LinkExchange использует стандартною систему ведения журналов - модуль logging. Логгер верхнего уровня библиотеки - linkexchange, модули клиентов используют логгеры linkexchange.clients.*. Настроив правильно систему ведения журналов вы сможете получать отладочную информацию, предупреждения, сообщения об ошибках, и т.д.
