.. _tools:

.. currentmodule:: grab.tools

================
Полезные утилиты
================

В пакете :ref:`grab.tools <api_tools>` содержится множество различных вспомогательных утилит, которые оказываются полезными в разработке Grab и парсеров на основе Grab. Здесь приведён обзор наиболее важных утилит.

Пул заданий
===========


Используя функцию :func:`work.make_work` вы можете организовать выполнение множества заданий в параллельных тредах, причём количеством тредов можно управлять::

    def worker(url):
        g = Grab()
        g.go(url)
        return url, g.xpath_text('//title')

    task_iterator = open('urls.txt')
    for url, title make_work(worker, task_iterator, limit=5):
        print url, title
       
Обратите внимание, что вы можете передавать не только статический список заданий, но и итератор. Результат работы функции :func:`work.make_work` выполнен также в виде итератора. Если вы хотите использовать процессы, вместо тредов, вам нужна функция :func:`pwork.make_work`. Она аналогична вышерассмотренной, за тем исключением, что она порождает не треды (`threading.Thread`), но процессы (`multiprocessing.Process`)

Блокировка файла
================

Для того, чтобы гарантировать то, что в любой момент времени выполняется только один экземпляр вашего парсера, можно использовать функцию :func:`lock.assert_lock`. Её аргумент - путь до файла, который должен быть залочен. Если залочить файл не удаётся, функция генерирует исключение и программа прекращается. Естественно, в разных скриптах нужно лочить различные файлы.


Логирование Grab-активности в файл
==================================

Функция :func:`logs.default_logging` настраивает logging-систему так, чтобы все сообщения библиотеки Grab направлялись в файл, по-умолчанию, это "/tmp/grab.log". Удобно вызвать эту функцию в начале программы и наблюдать за активностью парсинга с помощью команды `tail -f /tmp/grab.log`, оставляя себе возможность выводить в консоль, где был запущен скрипт, более важные данные.

Фильтрация строк в файле
========================

Функция :func:`files.unique_file` читает строки из файла, оставляет уникальные строки и записывает их обратно в файл. Функция :func:`files.unique_host` читайет список URL-строк из файла и оставляет только строки с уникальным hostname, далее записывает строки обратно в файл.

Обработка HTML
==============

* :func:`html.decode_entities` - преобразовывает все &XXX; и &#XXX; последовательности в тексте в уникод.
* :func:`html.strip_tags` - вырезает все тэги из текста простым регекспом. 
* :func:`html.escape` - преобразовывает ряд "небезопасных" HTML-символов в "&xxx;" последовательности.

Работа с LXML-элементами
========================

* :func:`lxml_tools.get_node_text` - возвращает текстовое содержимое элемента и всех его под-элементов, за ислючением элементов script и style.
* :func:`lxml_tools.find_node_number` - возвращает первое найденное число в текстовом содержимом переданного элемента.

Работа с регулярными выражениями
================================

Функция :func:`rex.rex` позволяет искать регулярное выражение. Вы можете передать ей как скомпилированный объект регулярного выражения, так и просто текст из которого будет построен объект регулярного выражения. Объекты регулярных выражений кэшируются, так что вам не нужно беспокоитсья о том, что выражение будет перекомпилироваться. Если выражение не найдено, функция :func:`rex.rex` сгенерирует :class:`grab.error.DataNotFound` исключение. Вы можете изменить это поведение, передав в аргументе `default` значение, которое нужно вернуть по-умолчанию::

    >>> from grab.tools import rex
    >>> import re
    >>> rex.rex('*** foo +++', re.compile('\w+')).group(0)
    'foo'
    >>> rex.rex('*** foo +++', '\w+').group(0)
    'foo'
    >>> rex.rex('***', '\w+')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/lib/python2.6/dist-packages/grab/tools/rex.py", line 44, in rex
        raise DataNotFound('Could not find regexp: %s' % regexp)
    grab.error.DataNotFound: Could not find regexp: <_sre.SRE_Pattern object at 0xb83c10>
    >>> rex.rex('***', '\w+', default='default value')
    'default value'

Функция :func:`rex.rex_list` вернёт список всех найденных регулярных выражений. Функция :func:`rex.rex_text` найдёт указанный текст и затем вырежет из него все тэги. Функция :func:`rex.rex_text_list` вернёт список всех найденных текстовых фрагментов с вырезанными тэгами.

Работа с текстом
================

* :func:`text.find_number` - поиск числа в строке
* :func:`text.drop_space` - удаление *всех* пробелов в строке
* :func:`text.normalize_space` - удаление начальных и конечных пробелов, приведение последовательности пробелов к одному пробелу.

Работа с http-заголовками
=========================

* :func:`http.urlencode` - сериализация словаря или списка пар в строку, которую можно отправить в GET или POST-запросе. В отличие от стандартного `urllib.urlencode` может обрабатывать unicode, None и :class:`grab.upload.UploadFile` объекты.
