Конвертируем картинку в base64 строку

Скрипт для конвертирования изображений в base64-строку для использования в теге img. Тип в data берем из расширения файла.

1
2
3
4
5
6
7
8
# base64 encode image

import sys, os.path
import base64

img = file(sys.argv[1], "rb")
ext = os.path.splitext(sys.argv[1])[1][1:]
print ( "data:image/" + ext + ";base64," + base64.b64encode(img.read()) )
egax написал 1 год,1 месяц назад

Сайт с использованием Django-nonrel фреймворка

В этой статье я хочу рассказать о разработке своего проекта - сайта egaxegax.appspot.com.

Поскольку являюсь большим поклонником языка Python, свой сайт я решил создать на популярном фреймворке Django. Чтобы использовать его на бесплатном хостинге appspot.com, адаптировал код для использования NoSQL версии django и платформы Google AppEngine.

Сайт существует уже больше 3 лет с 12-го года. Я использую его как платформу для изучения возможностей django и appengine "вживую". Также интересно изучать статистику по нему в Google Webmasters: поисковые индексы, запросы. Например, для себя я выяснил, что Google индексирует для поиска заголовки title, а не содержимое тегов meta.

Началось все с блога - небольших заметок на программные темы: скрипты, конфиги, примеры использования. Но статьи быстро закончились. А создавать новые в большом объеме не получается. Нужно было что-то большее.

Как-то где-то в Сети я скачал архив файлов с текстами и аккордами песен. Добавил к ним пару десятков своих подборов и решил выложить все на сайт. Всего получилось около 11500 файлов. Вручную столько не загрузить. Для этого я написал скрипт ptext.bat, который преобразует текстовые файлы в дампы для загрузки данных таблиц в GAE DataStore.

Загрузку данных пришлось разделить на несколько этапов из-за ограничений на количество операций записи в сутки в DataStore. В сутки получалось записывать около 700-800 записей (файлов).

После загрузки данных через некоторое время при открытии страницы сайта все чаще стала возникать ошибка 503 Server Error: Over Quota. Поизучав логи на сервере, я выяснил, что главными пользователями моего сайта были googlebot и yandexbot, которые обращаются к страницам с интервалом в 2-3 минуты. Ошибка возникает из-за превышения ограничения количества операций в сутки на чтение из DataStore.

Посмотрев документацию и примеры по appengine, я понял, что совсем не использовал модуль cache (а именно memcache). Каждое открытие страницы вызывало обращение к базе данных через QuerySet. В новой схеме результаты выборок из рекордсетов QuerySet я передаю в списки Dictionary, которые сохраняются в кэш и считываются оттуда при повторном обращении. Это решило проблему с быстрым исчерпанием лимита на чтение.

Позже я добавил раздел Фото и Новости. Разделы оформлены как отдельные приложения (apps). Данные хранятся в таблицах DataStore. Раздел Фото также использует хранилище файлов BlobStore. Все приложения используют кэш при выборке данных.

Сейчас по аналогии с разделом Аккорды я заполняю раздел Книги, куда выкладываю тексты электронных книг. Тексты книг я получаю, распаковывая файлы *.epub с помощью скрипта bconv.py из каталога media/scripts. В отличие от текстов песен они намного больше в объеме и не могут быть целиком отображены на странице. Кроме того, возникла проблема с тем, что книга целиком не может быть добавлена в кэш из-за превышения лимита памяти кэша. Для этого я считываю, помещаю в кэш и отображаю их по главам. Правда до конца проблема не решена. Поскольку сейчас в кэш помещается вся книга по главам целиком, при чтении нескольких книг подряд возникает ошибка превышения лимита на чтение. Выход - в чтении и кэшировании только текущей главы, а не всей книги целиком. Но это пока в проекте.

Кому интересно заходите на страницу проекта в репозитории GitHub django-egaxegax.

egax написал 1 год,8 месяцев назад

Расширенный аналог утилиты wc в Linux

Скрипт рекурсивно считает число строк в файлах каталогов. Можно задавать маски поиска имен файлов на вхождение или не вхождение. Скрипт использовался в средах Windows и Linux (локаль koi8-r) для версии языка Python 2.4. Подробности вызова смотри в исходнике или в справке при вызове без параметров:

python pywc.py

Текст:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Выводит число строк, байт для каждого файла каталога рекурсивно и итоговую строку."""

import sys, os, re
import fileinput as i
import fnmatch as f

__version__ = '0.3'

E = lambda text: text.encode({'posix':'koi8-r', 'nt':'cp866'}.get(os.name))
_E = lambda text: text.decode({'posix':'koi8-r', 'nt':'cp866'}.get(os.name))
E_OS = lambda text: text.encode({'posix':'koi8-r', 'nt':'cp1251'}.get(os.name))
_E_OS = lambda text: text.decode({'posix':'koi8-r', 'nt':'cp1251'}.get(os.name))

STR_HELP = u"""\
Вызов: python pywc.py <папка> [<файл_масок> | - ]
Выводит число строк, байт для каждого файла в ПАПКЕ по маскам из ФАЙЛА_МАСОК.

ФАЙЛ_МАСОК содержит маски поиска на включение и исключение файлов, разделенных пустой строкой.
Если ФАЙЛ_МАСОК задан как -, читает стандартный ввод, если не задан, подсчитываются все файлы.

Пример файла:
  # включать
  *.c *.cpp
  *.h *.asm

  # исключать
  *\.svn\* *\stdafx.h

Примеры использования:
  python pywc.py .               Считать все файлы в текущем каталоге и ниже. 
  python pywc.py тест1 dir       Считать файлы в test1 и ниже, используя файл масок dir."""

REG_COL = '(?:[ \t]*#.*\r?\n?)*((?:[^\r\n]+\r?\n?)+)'
REG_ROW = '([^ \t\r\n]+)'

def subinfo(lines, size, files, _files, ts, lastprint=True):
    """Выводит расчеты в stdout."""
    print lines, size, ts
    print E(u'Посчитано файлов'), files, E(u'из'), files + _files             
    if (lastprint):
        print

args = sys.argv[1:]

if (not args):
    print E(STR_HELP)
    sys.exit(2)

# файл масок поиска и исключений
_wcfile = []
if (len(args) > 1):
    if (args[1] == '-'):
        wcfile = sys.stdin
    else:
        wcfile = file(args[1])
    _wcfile = re.findall(REG_COL, _E_OS(wcfile.read()))

res = []
for x in _wcfile:
    res += [re.findall(REG_ROW, x)]

# каталог подсчетов    
os.chdir(args[0])

dd = sublines = subsize = subfiles = _subfiles = None
totallines = totalsize = totalfiles = _totalfiles = 0
for root, dirs, files in os.walk(u'.', topdown=False):
    # подпапки
    if (root != dd):
        if (sublines):
            subinfo(sublines, subsize, subfiles, _subfiles, E(u'ИТОГО'))
        sublines = subsize = subfiles = _subfiles = 0
        dd = root
    for name in files:
        curname = os.path.normpath(os.path.join(root, name))
        absname = os.path.join(_E_OS(os.getcwd()), curname)
        if (res):      
            p = e = False        
            # вхождения
            for x in res[0]:
                p = (f.fnmatch(name, x) or f.fnmatch(curname, x) or f.fnmatch(absname, x))
                if (p):
                    break
            # исключения
            if (len(res) > 1 and p):            
                for x in res[1]:
                    e = (f.fnmatch(name, x) or f.fnmatch(curname, x) or f.fnmatch(absname, x))
                    if (e):
                        break                    
            if (not (p and (not e))):
                print >> sys.stderr, E(u'Игнорируем'), E(curname)
                _subfiles += 1
                _totalfiles += 1
                continue
        for line in i.input(E_OS(absname)):
            pass
        else:
            curlines, cursize = i.filelineno(), os.stat(curname)[6]            
            # по подпапкам
            sublines += curlines
            subsize += cursize
            subfiles += 1
            # всего
            totallines += curlines
            totalsize += cursize
            totalfiles += 1
            print curlines, cursize, E(curname)
            i.close()
else:
    if (sublines):
        subinfo(sublines, subsize, subfiles, _subfiles, E(u'ИТОГО'))

if (totallines):
    subinfo(totallines, totalsize, totalfiles, _totalfiles, E(u'ВСЕГО'), lastprint=False)
egax написал 4 лет,10 месяцев назад

Войдите, чтобы оставлять сообщения.