Сначала ответ на вопрос «А зачем переходить с Drupal на статику»
Если посмотреть на то, как устроено большинство сайтов, то видно, что, чаще всего, необходимости именно в динамичности содержимого нет. Эти сайты — набор статических (или редко изменяющихся) материалов. Интерактив с посетителями редкость.
Единственное, что оправдывает в такой ситуации технологию CMS — это очень быстрое создание сайтов.
Фактически Drupal (да и другие CMS) используются в таких случаях просто как редактор той или иной публикации на сайте.
Статика прекрасно бы подошла под такие задачи. Она требует меньше ресурсов сервера и существенно проще администрируется.
В качестве вспомогательного инструмента для перехода и дальнейшей эксплуатации в статике выбран Python.
Куда переходить
Поскольку идея генерации полного статического сайта лежит на поверхности, то я прошустрил интернет в поисках готовых разработок. Забавно, что одними из самых первых мне попались подобные системы ребят, зарабатывающих на порнотрафике и на бестолковом рекламном трафике — видимо им без статики не шибко выгодно пропускать через себя кучу пользователей, перемывая кучу пустой породы, в поисках крупинок золота. Это укрепило меня в мысли об высоких эксплутационных свойствах статических сайтов.
Нашел множество обзорных статей про генераторы статических сайтов, приведу в качестве примера одну небольшую, но местную, хабровскую: habrahabr.ru/post/93499/
Входные данные для подобных систем — это просто файлы бинарные и текстовые. Возможно, разложенные по подкаталогам.
Особый восторг вызвал синтаксис текстовых файлов с использованием облегченных языков разметки reStructuredText, Markdown, Textile. Не могу этот восторг тут не выразить.
Как осуществить перенос данных из Drupal в файлы
Осталось решить как извлечь данные из Drupal и перегнать их в текстовые файлы (адаптирую в этом процессе под тот или иной генератор статических сайтов).
Рассмотрение базы данных Drupal не обрадовало: вроде все просто, но поковыряться нужно. А перенос, напоминаю «ленивый», минимальными телодвижениями и минимальными движениями
Поскольку идея, лежащая на поверхности, следовательно, для столь развитой системы как Drupal должно быть несколько средств импорта-экспорта. Выбрал модуль Drupal, который называется «Node Export». Разобраться с ним оказалось несложно.
В панели администрирования сайта после установки данного модуля ("/admin/config/content/node_export") следует указать формат экспорта XML.
Затем зайти в раздел «Cодержимое» ("/admin/content"), выбрать все публикации и произвести операцию экспорта в XML. Сделать это придется постранично — экспорт возможен только с теми публикациями (нодами), которые попали в список на текущей странице.
Получим несколько файлов вида (по одному для каждой страницы из "/admin/content"):
<?xml version="1.0" encoding="UTF-8" ?>
<node_export created="Fri, 08 Jun 2012 23:16:39 +0700">
<node>
<vid>144</vid>
<node created="111"></node>
<uid>1</uid>
<title>Синаксис Markdown по-русски</title>
<log></log>
<status>1</status>
<comment>0</comment>
<promote>1</promote>
<sticky>0</sticky>
<vuuid>d45b309d-f733-4234-3d7f-a213662242b7</vuuid>
<nid>144</nid>
<type>blog</type>
<language>ru</language>
<created>1339166536</created>
<changed>1339166536</changed>
<tnid>0</tnid>
<translate>0</translate>
<uuid>e7bf6ad7-f7a6-bc14-05d7-30e0c7664cfe</uuid>
<revision_timestamp>1339166536</revision_timestamp>
<revision_uid>1</revision_uid>
...
В этом файле есть много чего интересного для полноценного переноса данных из Drupal — несколько публикаций (нод) с номерами и содержимым, датой публикации и информацией об авторе. Существенным минусом является отсутствие представления таксономии (разделов сайта) в виде текста.
Разбор файла XML и его преобразование в текстовый файл был сделан на Python с помощью библиотеки lxml. В примере нет части кода для записи ноды в текстовый файл по причине зависимости от конкретного генератора статического сайта (да и это элементарное действо). Это можно сделать, например, так:
from lxml import etree
doc = etree.parse("fromDrupal.xml")
class ParsedDrupalNode():
def __init__(self, nid, created, title, text):
if nid != None:
self.nid = nid.text
else:
self.nid = ""
if created != None:
self.created = created.text
else:
self.created = ""
if title != None:
self.title = title.text
else:
self.title = ""
if text != None:
self.text = text.text
else:
self.text = ""
def writeNode(self):
if (self.nid == None) or (self.created == None) or (self.title == None) or (self.text == None):
raise Exception ("Undefined field(s) detected")
# тут пишем в текстовый файл, конкретно как - зависит от конкретного выбранного генератора сайтов
for node in doc.findall("node"):
node_nid = node.find("nid")
node_created = node.find("created")
node_title = node.find("title")
node_text = node.find("body/ru/n0/value")
parsed = ParsedDrupalNode(nid = node_nid, created = node_created, title = node_title, text = node_text)
parsed.writeNode()
Разделы сайта (таксономию) и файлы нужно обработать отдельно.
Особенности переноса таксономии
Перенести в статику и таксономию (если не заморачиваться переносом и иерархии таксономии) — несложно. Вполне достаточно экспорта средствами phpMyAdmin.
При экспорте стредствами phpMyAdmin таблицы term_data получаем такой сравнительно простой файл (структура хоть и несложная, но, согласитесь, куда приятнее работать с тем файлом XML, что был сформирован с помощью модуля «Node Export», чем работать с файлом, полученным при помощи phpMyAdmin.):
<?xml version="1.0" encoding="UTF-8"?>
<pma_xml_export xmlns:pma="http://www.phpmyadmin.net/some_doc_url/" version="1.0">
<pma:structure_schemas>
...здесь было описание полей базы данных, вырезано за ненадобностью...
</pma:structure_schemas>
<database name="mydbname_db">
<table name="myprefix_term_data">
<column name="tid">1</column>
<column name="vid">1</column>
<column name="name">Название раздела сайта тут написано</column>
<column name="description">Развернутое описание раздела сайта тут написано</column>
<column name="weight">7</column>
</table>
...
Чтобы получить список разделов сайта нам достаточно только колонок «tid» и «nid»
<column name="tid">1</column>
и как
<column name="name">Название раздела сайта тут написано</column>
В самом первом файле xml (в том, что получен из Drupal при помощи модуля «Node Export») в каждой публикации (ноде) имеется запись вида:
<taxonomy_vocabulary_1>
<und _numeric_keys="1">
<n0>
<tid>8</tid>
<uuid>954badc0-053f-4814-d505-73e5e58106bb</uuid>
</n0>
</und>
</taxonomy_vocabulary_1>
Вот «tid» — это как раз и есть уникальный идентификатор раздела сайта.
Таким образом, если нам не нужна иерахия разделов (таксономия) сайта, то разделы для каждой публикации легко вытягиваются из БД.
Особенности переноса бинарных файлов
В панели администрирования сайта следует выбрать настройки модуля «Node Export» ("/admin/config/content/node_export") для работы со связанными с публикацией (нодой) файлами (это подраздел «File fields» в самом низу страницы).
Модуль умеет переносить бинарные файлы, прикрепленные к публикации (ноде) по разным технологиям. Я использовал на сайте с CMS Drupal в описываемом случае бинарные файл (картинки) с помощью одного из самых популярных модулей — CCK. Конкретно с такими файлами «Node Export» действительно работает, проверил.
Есть 3 варианта — оставить файлы нетронутыми, а выгрузить только ссылки на них; выгрузить файлы локально; и есть возможность встроить файлы в XML, кодируя их в Base64.
Я выбрал вариант «Оставить на сервере», потому как новый уже статический сайт будет жить на том же сервере, чего понапрасну байты гонять. Проверил, работает. Ссылки на файлы генерируются относительно корня CMS без указания имени сайта.
Заключение
Осталось решить как именно хранить сайт в виде текстов, как именовать файл, где класть бинарные файлы, прикрепленные к статьям — это зависит от выбранного генератора статических сайтов.
И дописать небольшой кусок кода, раскладывающий полученную из Drupal информацию так, как это нужно этому конкретному генератору статических сайтов.
Вопрос
Подскажите: как корректно преобразовать дату
Она приезжает как "<created>1339166536</created>"
А фактически является "08 июня 2012 - 21:42"
Автор: denisgorbunov