Начать эту статью мне хотелось бы издалека. Для чего мы работаем? Для того, чтобы НЕ работать! Чтобы, дождавшись вечера, выходных, отпуска — насладиться жизнью. Но, пока мы наслаждаемся жизнью, ресурсы, прежде всего, материальные, тают ускоренно, и вот, наступает пора вернуться к работе. В принципе, на этом нехитром механизме и зиждется развитие цивилизации. Но каждая отдельная особь стремится вырваться из этого замкнутого круга, ведь, в конце концов, мы можем способствовать развитию цивилизации и более непосредственно — построив дом, посадив дерево, бросив зерно в почву, ну или там… что-нибудь еще сделав столь же креативное. И тут нам приходит на помощь вся мощь технического прогресса. Ведь мы можем автоматизировать значительную часть нашей работы и тогда можно будет фактически каждый день кидать зерна в почву и, соответственно, каждый день, через некоторое время, рожать сына, а лучше — дочку.
К построению столь светлого будущего мы и перейдем. Несколько месяцев назад на этом блоге уже была статья о сети дорвеев на WordPress, и даже, насколько помню, оказалась лучшей за месяц. Автор неплохо проработал вопрос дублирования служебных файлов Вордпресса. Я же предлагаю другой подход, при котором инсталляция Вордпресса существует в одном экземпляре и на одном хосте, а полученные блоги копируются на разные хосты. Прежде всего, нам нужен WordPress Multiuser — отдельная ветка Вордпресса, который поддерживает множество блогов, а не юзеров, как можно было подумать из названия.
Скрипт устанавливается один раз и на каждый новый блог в БД создаются таблицы вида wp_nn_posts где nn — порядковый номер очередного блога. Но в хорошей блогоферме, скажете вы, блоги существуют на многих хостингах. Безусловно так. И мы реализуем это через сканирование и html-выгрузку страниц блога на сторонний хостинг. Попутно решается одна весьма важная проблема, связанная с Вордпрессом — его дырявость. Поскольку поисковики и визитеры будут иметь дело с html копией блога, вариантов его взлома просто не остается. Сам блог, при этом должен быть закрыт от посторонних пользователей через htaccess.
Предыдущим параграфом я немного забежал вперед, чтобы сразу объяснить идею предлагаемой блогофермы и преимущества ее такого построения. Теперь же рассмотрим схему ее ядра.
Здесь мы видим основные компоненты нашей блогофермы:
- Текстовый краулер берет из таблицы источников адреса RSS-каналов и HTML-страниц (на тех ресурсах, где RSS не существует), считывает отдельные тексты (посты, новости) и складывает их в таблицу текстов.
- Постер берет тексты из таблицы и отправляет их в закрытые блоги.
- Сканнер как ему и положено по названию, сканирует закрытые блоги, создавая таблицу страниц.
- Аплоадер берет из таблицы страниц их адреса, получает по http содержимое этих адресов и выгружает на внешние блоги (я их также буду называть аватарами) файлы, являющиеся отражением страниц закрытых блогов.
Конечно, это — очень упрощенная схема. И поскольку, тут не изложение идеи, а полноценное палево, то я раскрою вам все все технические детали, вплоть до сложных SQL запросов, с которыми у некоторых могут быть проблемы. А поскольку здесь будут SQL запросы, то поясню мой подход к именованию индексных полей. Первичный индекс таблицы girls у меня называется xxgirl , а индекс в эту таблицу из другой — xgirl . Таким образом, вместо WHERE boy.girl_id=girl.id
я пишу WHERE xgirl=xxgirl
а это — меньше букв.
Итак, первым делом нам надо установить WordPress Multiuser. Скачиваем архив с этой страницы и запускаем скрипт установки по адресу http://domain.com/wp-admin/setup-config.php:
Админка установленного мультиблога доступна по адресу http://domain.com/wp-admin/. Но первым делом надо закрыть блог от посторонних глаз. Для этого в файле .htaccess прописываем:
Deny from all Allow from 111.222.333.444 Allow from 444.333.222.111
Где, вместо 111.222.333.444 вписываем адрес нашего блога, а вместо 444.333.222.111 — свой адрес. Или наоборот. А можно ограничить доступ через куку:
RewriteEngine On RewriteBase / RewriteCond %{HTTP_COOKIE} !moyakuka= [NC] RewriteRule .* - [F]
При этом надо позаботиться чтоб в вашем браузере хранилась кука moyakuka и она же выставлялась бы софтом, работающим с мультиблогом.
Далее, идем в админку, во вкладку Options->General и стираем tagline, иначе эта строка будет повторяться в каждом созданном блоге, а это неприятно.
Далее, идем в SiteAdmin->Users и создаем юзера, от имени которого будут производиться постинги. Не мудрствуя лукаво (а также картаво, гнусаво и слащаво) называем его poster:
Прежде чем приступать к дальнейшему изложению, определимся с терминологией. У нас будут продвигающие ресурсы — блоги (аватары мультиблога) и продвигаемые ресурсы — аптеки. Но продвигаемые ресы, в принципе, тоже могут быть блогами, тогда, как продвигающие, при должном расширении процесса могут оказаться и каталогами и форумами и еще много чем. Я в своем проекте использую музыкальную терминологию. Продвигающие ресурсы у меня называются минорами, продвигаемые — мажорами. Соответственно, будем именовать и таблицы, то есть, таблица minors будет хранить записи об аватарах мультиблога, а таблица majors — о продвигаемых ресурсах.
Далее, переходим к описанию компонентов ядра блогофермы.
Текстовый краулер.
Получает из таблицы источников (sources) адреса RSS-каналов и HTML-страниц с новостями (в тех случаях, где нет RSS), сграбливает новости и записывает их в таблицу текстов (texts).
Некоторые из полей таблицы источников:
- type = RSS/HTML
- url_pattern = шаблон ссылки на новость для HTML-источника, напр
news/\d+
- tag = тематика источника; возможно поддерживать выдирание новостей и продвижение мажоров разных тем.
- time_last_got = время последнего сграбливания новостей источника (во избежание его чрезмерно частого дергания)
Некоторые из полей таблицы текстов:
- tag = тематика текста. копируется из поля tag источника
- posts_count = количество постингов этого текста. позволяет выбирать наименее заюзанные тексты.
- penalty = степень ненормальности текста. Поскольку тексты выдираются атоматически, возможно попадание всякого мусора в таблицу. Я для каждого текста вычитсляю penalty на основе количества байт, знаков препинания, строчных букв после точки, восклицательного и вопросительного знаков.
SQL выбора источников:
SELECT * FROM sources WHERE status='ok' AND time_last_got<NOW()-INTERVAL $regularity HOUR LIMIT 0,20
Постер.
Наиболее сложный компонент. Первым делом определяем миноры, которые «созрели» для постинга.
SELECT * FROM minors WHERE daily_limit> ( SELECT count(*) FROM posts WHERE posts.xminor=xxminor AND result='ok' AND tstamp>now()-INTERVAL 1 DAY ) AND status='ok' AND (max_posts>=total_posts OR total_posts=0) ORDER BY rand() LIMIT 0, $minors_per_call
Выбираем миноры, у которых дневной лимит больше, чем количество успешных постингов за последние сутки И количество постингов которого не достигло его максимума (если он установлен). Чтобы не осталось обиженных миноров, их список мы рандомизируем.
Некоторые из полей таблицы миноров:
- http_root = http://domain.com. это нам понадобится при вычисении адреса страницы аватара.
- template = wordpress template данного минора
- tag = тематика минора. тексты для минора будут выбираться в соответствии с этим полем.
- file_ext = php/html — расширение файлов блога-аватара.
- fillco = коэффициент заполнения. создавать одинаковые наборы текстов на разных минорах будет не лучшей идеей. Для уникализации структуры, можно пропускать некоторые из постингов. Фактически, fillco является вероятностью, с которой происходит постинг отдельного текста.
- days_entropy = энтропия даты постинга. В WordPress есть замечательная возможность опубликовать пост датой в прошлом. days_entropy определяет временой диапозон такой даты, например значение 100, приводит к вычислению даты, как today-rand(0,100) дней. Это позволяет равномерно разбросать постинги по страницам календаря.
- header = php-файл в папке headers, подключение к которому будет сгенерировано для php-страниц аватара сразу после <body> . Используется для подключения js-фидов.
- ftp_host, ftp_login, ftp_password = данные FTP-аккаунта сайта-аватара.
- ip = IP аватара. Может использоваться для исключения аватаров на одном ИПе при их кросс-линковке.
- last_uploaded = время последней выгрузки минора по FTP.
Далее, для каждого выбранного минора, пока не истекло время, выделенное текущему крон-заданию, делаем следующее.
- Убеждаемся, что для тематики минора найдется хотя бы один мажор:
SELECT * FROM majors WHERE prio>0 AND status='ok' AND tag='$minor[tag]' LIMIT 0,1
- Выбираем тексты для постинга в этот минор. Выбираются тексты, которые не были запосщены в этот минор в соответствии с темой минора.
SELECT xxtext, tag FROM texts WHERE tag='$minor[tag]' AND status='ok' AND length(content)>500 AND xxtext NOT IN ( SELECT xtext FROM posts WHERE xminor=$minor[xxminor]) ORDER BY posts_count,when_found LIMIT 0,(4*$minor['daily_limit'])
- Для каждого найденного текста.
- Если тексту не судьба в этот раз запоститься (см. fillco ), то записываем в таблицу постингов пост с результатом fake.
- Иначе — постим текущий текст в текущий минор. А это — целая песня, ее и рассмотрим отдельно.
Постинг текста.
Перед постингом мы насыщаем текст ссылками. Это 2 типа ссылок:
- Ссылки на мажоры.Из таблицы мажоров мы, как уже было упомянуто, имеем домен мажора, например, www.domain.com; он преобразуется в имя класса: www_domain_com, который инклюдится в скрипт:
include "majors/$major_class_name.class.php"; $cmajor = new $major_class_name();
Класс мажора обеспечивает метод get_target_links($num), который возвращает массив из $num элементов типа ancor=>url. Далее, мы можем сделать из этого массива футер поста (не блога) или внедрить его в текст.
- Ссылки на внутренние страницы других миноров. При сканировании миноров мы получаем адреса его страниц и страниц его аватара в таблице pages , эти адреса и используются для кросс-ссылок:
SELECT minor_url FROM pages,minors WHERE minor_url not rlike '/feed|/about|/wp-login|/wp-signup|/index|/tag' AND minor_url!='' AND xminor=xxminor AND minors.status!='banned' AND minors.ip!='$minor[ip]' ORDER BY rand() LIMIT 0,10
Ссылки на страницы других миноров я линкую на случайный фрагмент текста из 3 слов.
Готовый текст постится в блог специальным софтом от имени созданного ранее юзера.
Сканнер.
Сканнер, как ему и положено, сканирует миноры и поддерживает таблицу страниц pages. Некоторые из полей данной таблицы:
- minor_folder = папка, в которой живет минор. Удобно, на мой взгляд ее производить от имени домена минора, например, минор для домена mysite.freehost.com живет в папке mysite_freehost_com. Фактически — это имя юзера, на которого зарегистрирован субблог.
- mu_url = урл данной страницы минора, напр. http://domain.com/mysite_freehost_com/2010/11
- minor_url = урл соответствующей страницы аватара минора, напр. http://mysite.freehost.com/2010/11.html
- md5 = хэш страницы, по нему мы определяем, изменилась ли она и нуждается ли в перевыгрузке.
- uploaded = флаг выгруженности страницы.
Аплоадер.
Аплоадер занимается выгрузкой страниц на внешние хосты. Сначала выбираем миноры, которые имеют невыгруженные страницы:
SELECT * FROM minors WHERE exists ( SELECT * FROM pages WHERE xminor=xxminor AND uploaded=0 ) ORDER BY rand() LIMIT 0,$minors_per_call
Случайный порядок выборки миноров гарантирует, что аплоадер не споткнется на особо тормозном фрихосте.
Далее, аплоадер выбирает невыгруженные страницы очередного минора (думаю, тут нет надобности в пояснении SQL), обрабатывает их и выгружает в соответствии с параметрами минора.
- Обработка.
- Удаление лишних тэгов в <head>; достаточно мельком взглянуть на html код страницы блога, чтоб понять, что там лишнее.
- Удаление ссылки uncategorized. Как категорию, ее невозможно удалить, а повторение всех новостей нам ни к чему.
- Подключение назначенного минору js-фида после тэга <body>
- Формирование META keywords&description.
- Преобразование внутренних ссылок.
- Удаление левых ссылок. Ссылки, которые прописаны в футуре шаблона нам совсем не нужны. Я храню их в отдельной таблице, которую заполняю вручную.
- Выгрузка. Здесь аплоадер определяет актуальное имя файла минора, и загружает его по FTP в соответствии с FTP параметрами минора. Например, для страницы минора http://domain.com/mysite_freehost_com/2010/11 и страницы его аватара http://mysite.freehost.com/2010/11.html в папку 2010 записывается файл 11.html
Теперь немного о шаблонах.
В сети существует огромное множество сайтов с бесплатными шаблонами для WordPress. Устанавливаются они хоть и руками, но просто — распакованные шаблоны заливаются в папку wp-content/themes, после чего заходим в админку Site Admin=>Themes и активизируем установленные темы:
Разумеется, темы устанавливаются на закрытый мультиблог, а чтобы дизайн сохранялся и у аватара, достаточно скопировать файлы стилей и картинок. Удобней будет использование отдельного скрипта, который создает новый минор, а именно:
- Создает блог в папке domain_com
- Выбирает случайным образом шаблон
- Назначает его блогу
- Копирует файлы картинок и стилей шаблона на хост аватара
- Фиксирует в таблице миноров данные FTP, http_root, папку блога и прочее данные, введенные создателем минора
Как показывает опыт, полезной окажется и утилита смены шаблона, то есть копирования файлов стилей и картинок выбранного шаблона.
Также будет не лишним проработка уникализации контента и пингования блогов-аватаров.
Конечно, описанный проект достаточно трудоемок, но он автоматизирует наиболее трудоемкую часть SEO продвижения — простановку ссылок. Достаточно один раз все это настроить, и потом останется только добавлять FTP аккаунты — фрихостовые или собственные перекупленные домены.
Все процесы по сграбливанию новостей, сканированию, постингу и выгрузке происходят автоматически из крона. Чтоб ненароком не положить сервер, рекомендую пользоваться этой штукой .
Всех поздравляю с Новым и Старым годами, успехов в бизнесе и жизни! 🙂
Автор статьи: Cosinus.