1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/dreamidea-neocrawler

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

1. Обзор

NEOCrawler (русское название: НейоКраулер) — это система пауков, реализованная с использованием Node.js, Redis и PhantomJS. Код полностью открытый и предназначен для сбора данных в вертикальных областях и последующей доработки.### [Основные характеристики]

  • Реализация на Node.js обеспечивает простоту, эффективность и легкость обучения JavaScript, что экономит время как при разработке пауков, так и при их последующей модификации. Node.js использует движок Google V8, который обеспечивает высокую производительность. Благодаря асинхронному характеру Node.js, он отлично подходит для выполнения задач, связанных с I/O, где требования к процессорной мощности невелики. В сравнении с другими языками программирования, такими как C/C++, Java или Python, Node.js требует меньших усилий для разработки и демонстрирует лучшую производительность.
  • Центральный распределённый механизм управления позволяет координировать работу пауков, распределяя задачи между ними. Это обеспечивает отказоустойчивость системы, поскольку отдельные проблемы одного паука не влияют на общую систему.
  • Пауки выполняют структурный анализ страниц во время парсинга, выделяя необходимые данные. При записи этих данных в базу данных используются не только исходные коды страниц, но и структурированные данные полей. Это делает данные сразу доступными после парсинга и упрощает процесс удаления дубликатов при записи.
  • Интеграция с PhantomJS позволяет выполнять скрипты JavaScript для получения содержимого страниц, которое генерируется при выполнении этих скриптов.Это также позволяет заполнять формы, отправлять запросы и выполнять действия пользователя на страницах.
  • Механизмы повторной попытки и отказоустойчивости обеспечивают надёжность HTTP-запросов, предоставляя детальные логи ошибок для анализа. Также есть механизмы проверки содержимого ответов, позволяющие обнаруживать пустые страницы, неполные страницы или страницы, захваченные прокси-серверами.
  • Возможность предварительной установки cookie решает проблему необходимости авторизации для доступа к некоторым данным.
  • Ограничение количества одновременных соединений помогает избежать блокировки IP-адреса источником сайта из-за слишком большого количества соединений.
  • Интеграция использования прокси-IP-адресов позволяет обходить сайты, защищённые от парсинга. Пауки автоматически выбирают доступные прокси-IP-адреса для доступа к источнику сайта, что делает невозможным его блокировку.
  • Производственные возможности позволяют разделить базовую часть системы пауков от конкретной бизнес-логики, которая может быть настроена без необходимости программирования.
  • Установка правил парсинга через веб-интерфейс, которая мгновенно применяется к распределённой системе пауков. На веб-интерфейсе можно настроить правила сбора данных; после сохранения новые правила автоматически применяются к работающим на разных машинах процессам пауков (скрейперам).Для изменения правил не требуются программирование или перезапуск программы.### Настройки:
  1. Описание типов страниц регулярными выражениями, позволяющими объединять похожие страницы в группы с одинаковым набором правил;
  2. Начальный адрес, метод сбора данных, место хранения, способ обработки страниц;
  3. Правила для сбора ссылок, используемые CSS-селекторы для ограничения сбора только определённых местоположений на страницах;
  4. Правила для извлечения информации со страниц, используемые CSS-селекторы и регулярные выражения для указания местонахождения каждого поля;
  5. Предопределенные JavaScript-выражения для выполнения при открытии страницы;
  6. Cookies, установленные на странице;
  7. Критерии для проверки корректности ответа сервера, обычно это ключевые слова, наличие которых обязательно для успешной проверки;
  8. Вес (приоритет) и периодичность (через какое время повторить запрос) для каждой категории страниц.
  • Чтобы минимизировать избыточное развитие, требования к сбору данных группируются в экземпляры. Базовая конфигурация каждого экземпляра (локация базы данных, параметры работы скрейпера, пользовательские модификации) может различаться. Таким образом, архитектура конфигураций выглядит следующим образом: система пауков -> экземпляр -> URL.* Архитектура системы пауков основана на Scrapy и состоит из core, spider, downloader, extractor и pipeline. Core является центром управления событиями и связывает все компоненты. Spider управляет входом и выходом очереди, downloader отвечает за скачивание страниц, выбирая между обычным скачиванием HTML-кода и его последующим рендерингом с использованием PhantomJS. Extractor выполняет структурирование данных согласно правилам извлечения, а pipeline обеспечивает долговременное хранение данных или передачу их системам дальнейшей обработки. Все эти компоненты предоставляют возможности для пользовательских настроек, что позволяет легко расширять функционал через JavaScript.### [Архитектура] Подсказка: Рекомендуется новым пользователям пропустить раздел описания архитектуры и сразу перейти ко второму разделу, чтобы запустить систему и получить первоначальное представление. После этого рекомендовано вернуться к изучению архитектуры. Если вам необходима более глубокая настройка или доработка системы, внимательно прочтите этот раздел.

Общая архитектура На этом рисунке желтым цветом показаны различные подсистемы системы пауков. SuperScheduler — центральный распорядчик, который помещает собранные веб-сайты в соответствующие базы данных сайтов. SuperScheduler извлекает соответствующее количество сайтов из различных баз данных сайтов согласно правилам распределения и помещает их в очередь для парсинга.

  • Spider — это распределенная программа-паук, которая извлекает задачи из очереди для парсинга, подготовленной распорядчиком, выполняет парсинг, помещает найденные сайты в базу данных сайтов, а также сохраняет извлеченные данные. Программу-паука можно разделить на ядро (core) и четыре промежуточных компонента (download, extract, pipeline), чтобы было легче переопределить отдельные функции в экземплярах пауков.

  • ProxyRouter — это маршрутизатор, который умело направляет запросы пауков к доступным прокси-серверам при использовании прокси-IP адресов. * Webconfig — это конфигурационный интерфейс для настроек пауков web.

    Второй раздел: шаги выполнения

[Подготовка среды выполнения]

  • Установите Node.js, клонируйте исходный код из Git-репозитория на локальную машину, откройте командную строку в папке с исходным кодом и запустите команду "npm install" для установки зависимых модулей;
  • Установите Redis сервер (поддерживает как Redis, так и SSDB; для экономии памяти рекомендуется использовать SSDB, тип которого можно указать в setting.json);
  • Установите окружение HBase, которое используется для хранения полученных страниц и извлеченных данных. После установки HBase следует активировать HTTP REST сервис, который будет использоваться в дальнейших настройках. Если вы хотите использовать другую систему управления базами данных, то HBase можно не устанавливать. В последующих разделах будут рассмотрены способы деактивации HBase и настройки собственного хранилища. Инициализация HBase столбцов через hbase shell:
    create 'crawled',{NAME => 'basic', VERSIONS => 3},{NAME=>'data',VERSIONS=>3},{NAME => 'extra', VERSIONS => 3}
    create 'crawled_bin',{NAME => 'basic', VERSIONS => 3},{NAME=>'binary',VERSIONS=>3}
    Рекомендуется использование HBase REST метода. После запуска HBase выполните следующую команду в подкаталоге bin каталога HBase для запуска HBase REST:
    ./hbase-daemon.sh start rest
    По умолчанию порт 8080, этот порт будет использоваться в дальнейших настройках. ## [Настройка экземпляров]
  • Экземпляр находится в директории instance, скопируйте example и переименуйте её в abc. Далее все примеры будут использовать имя abc.
  • Отредактируйте instance/abc/settings.json
{
    /* Обратите внимание: здесь представлены объяснения для каждого параметра, реальное settings.json не должно содержать комментарии */
    "driller_info_redis_db": ["127.0.0.1", 6379, 0], /* Расположение информации о правилах сайта, последнее число указывает номер базы данных Redis */
    "url_info_redis_db": ["127.0.0.1", 6379, 1], /* Расположение информации о сайте */
    "url_report_redis_db": ["127.0.0.1", 6379,```
```markdown
## [Запуск]
* Основные шаги запуска пауков:
+ Конфигурирование правил сбора в веб-интерфейсе
+ Отладка отдельной страницы для проверки корректности сбора данных
+ Запуск планировщика (необходимо запустить один экземпляр)
+ При использовании прокси-IP для сбора данных следует запустить маршрутизацию прокси
+ Запуск пауков (пауки могут быть запущены распределённо)
Следующие команды показывают конкретные способы запуска.

* Запуск конфигурации веб-интерфейса (правила конфигурации см. в следующей главе):
> node run.js -i abc -a config -p 8888
Откройте браузер и перейдите по адресу **http://localhost:8888**, чтобы настроить правила сбора данных через веб-интерфейс

* Тестирование отдельной страницы:
> node run.js -i abc -a test -l "http://domain/page/"
```* Запуск планировщика:
> node run.js -i abc -a schedule

-i указывает имя экземпляра, а -a указывает действие планировщика; аналогично ниже

  • Запуск прокси-роутинга Прокси-роутинг следует запускать только при использовании только IP-адреса прокси для сбора данных

node run.js -i abc -a proxy -p 2013 Здесь, -p указывает порт прокси-роутера. При запуске на локальной машине, в файле setting.json должны быть установлены значения proxy_router и port как 127.0.0.1:2013

  • Запуск пауков

node run.js -i abc -a crawl Вы можете просмотреть выходные отладочные журналы в instance/example/logs/debug-result.json Рекомендуется использовать Node.js' PM2 или Python's Supervisor для управления процессами в рабочей среде.

[Конфигурация правил сбора данных]

Откройте веб-интерфейс, например, http://localhost:8888/, перейдите в раздел "Rules for Drilling", добавьте правила. Это JSON-редактор, который позволяет переключаться между режимом кода и визуальным режимом. Ниже представлены объяснения конфигурационных опций. Для конкретной конфигурации приложений обратитесь к примерам в следующем разделе.```javascript { /* Примечание: Ниже приведено объяснение каждого параметра конфигурации. Реальная конфигурация не может содержать комментарии / "domain": "", / Верхнеуровневый домен, например, 163.com (без имени хоста, www.163.com неверно) / "url_pattern": "", / Шаблон URL, регулярное выражение, например, ^http://domain/\d+.html. Чем более точные ограничения, тем лучше / "alias": "", / Альтернативное имя для этого правила / "id_parameter": [], / Допустимые параметры для данного URL. Если первое значение равно "#", то все параметры будут отфильтрованы / "encoding": "auto", / Кодировка страницы, "auto" означает автоматическое определение. Можно указывать значения, такие как gbk, utf-8 / "type": "node", / Тип страницы, ветка или узел / "save_page": true, / Сохранять ли HTML исходный код / "format": "html", / Формат страницы, html/json/binary / "jshandle": false, / Обрабатывать ли JavaScript, определяет, будет ли паук использовать PhantomJS для загрузки страниц / "extract_rule": { / Правила извлечения, подробно объясняются позже / "category": "crawled", "rule": { / Должно быть пустым, если данные не извлекаются / "title": { / Единица извлечения, подробно объясняется позже / "base": "content", "mode": "css", "expression": "title", "pick": "text", "index": 1 } } }, "cookie": [], / Значения cookies, составленные из нескольких объектов, каждый объект представляет одно значение cookie / "inject_jquery": false, / Внедрять ли jQuery при использовании PhantomJS / "load_img": false, / Загружать ли изображения при использовании PhantomJS / "drill_rules": ["a"], / Интересные ссылки внутри страницы, заполнены CSS селекторами для выбора элементов , можно включать несколько, здесь представляют все ссылки */ }


### Выборочные единицы
```javascript
{
    "base": "content", /* Основание для выборки, DOM веб-страницы: content или url */
    "mode": "css", /* Режим выборки, css или regex указывает на CSS селектор или регулярное выражение, value указывает на фиксированное значение */
    "expression": "title", /* Выражение, соответствует mode: CSS селектор или регулярное выражение или фиксированное значение */
}
``````markdown
### Параметры выборки

```json
{
    "pick": "text", /* В CSS режиме выбирается атрибут или значение элемента; `text` или `html` указывают на текстовое значение или HTML код соответственно, `@href` указывает на значение атрибута `href`, остальные атрибуты указываются аналогично с добавлением символа `@` перед названием атрибута */
    "index": 1 /* При наличии нескольких элементов, выбирается n-ый элемент; `-1` указывает на выбор всех элементов, что вернет массив значений */
}

Правила выборки

/* Правила выборки состоят из множества выборочных единиц, их базовая структура представлена ниже */
{
    "extract_rule": {
        "category": "crawled", /* Название таблицы HBase, куда будет сохраняться этот узел */
        "rule": { /* Конкретные правила */
            "title": { /* Выборочная единица, правила см. выше */
                "base": "content",
                "mode": "css",
                "expression": "title",
                "pick": "text",
                "index": 1,
                "subset": { /* Подмножество */
                    "category": "comment", /* Категория `comment` (сохраняется в `comment`) */
                    "relate": "#title#", /* Соответствие с родительским узлом */
                    "mapping": false, /* Тип подмножества, если `mapping=true`, то данные будут храниться отдельно в другой таблице */
                    "rule": {
``````markdown
                  "profile": {"base":"content","mode":"css","expression":".classname","pick":"@href","index":1},/*Извлечение единицы*/
                   "message": {"base":"content","mode":"css","expression":".classname","pick":"@alt","index":1}
                 },
               "require":["profile"]/*Необходимое поле*/
             }
       }
     }
   "require":["title"]/*Необходимое поле. Если значение внутри поля является массивом, то это означает, что любое одно из значений в этом массиве удовлетворяет требование, например [[a,b],c]*/
   }

3. Простой пример

Этот шаг предполагает, что вы уже запустили веб-конфигурацию в фоновом режиме. Для запуска веб-конфигурации следуйте инструкциям из предыдущего раздела. Ниже приведён пример конфигурации для извлечения WeChat ID. Предположим, что наша цель — извлечение всех WeChat ID c http://www.sovxin.com.

Мы создаем правила извлечения согласно этим уровням страниц, где только на детальной странице требуется извлечение информации, а остальные три страницы используются для последовательного открытия детальной страницы.
Мы начинаем с конца, с детальной страницы, и затем переходим к главной странице.
## Скриншот правил (на вашем интерфейсе таких списков пока нет, нажмите Add для добавления правил, используйте мою конфигурацию ниже)
![](http://git.oschina.net/uploads/images/2014/1103/155217_f57d134c_13016.png)
## Детальная страница (извлечение фактического содержимого)
![](http://git.oschina.net/uploads/images/2014/1103/153248_212b5771_13016.png)Вы должны сравнить этот пример со всеми объяснениями каждого параметра конфигурации из предыдущего раздела.
Вы можете переключиться в режим редактирования кода и вставить следующий JSON.
```json
{
   "domain": "sovxin.com",
   "url_pattern": "^http://www.sovxin.com/weixin_\\d+.html$",
   "alias": "detail",
   "id_parameter": [
     "#"
   ],
   "encoding": "auto",
   "type": "node",
   "save_page": false,
   "format": "html",
   "jshandle": false,
   "extract_rule": {
     "category": "crawled",
     "rule": {
       "nickname": {
         "base": "content",
         "mode": "css",
         "expression": ".title>strong",
         "pick": "text",
         "index": 1
       },
       "name": {
         "base": "content",
         "mode": "regex",
         "expression": ">微信号:(.*)</td>",
         "pick": "text",
         "index": 1
       },
       "subtype": {
         "base": "content",
         "mode": "regex",
         "expression": ">账号类型:(.*)</td>",
         "pick": "text",
         "index": 1
       }
     }
   }
}

Листинг страницы (через которую можно получить ссылки на конфигурационные детальные страницы и свои собственные пагинационные ссылки)

{
    "domain": "sovxin.com",
    "url_pattern": "^http://www.sovxin.com/t_.+?.html$",
    "alias": "list",
    "id_parameter": [
        "#"
    ],
    "encoding": "auto",
    "type": "branch",
    "save_page": false,
    "format": "html",
    "jshandle": false,
    "extract_rule": {
        "category": "crawled",
        "rule": {}
    },
    "cookie": [],
    "inject_jquery": false,
}

Категорийная страница (через которую можно получить ссылки на конфигурированные списки страниц)

```javascript { "domain": "sovxin.com", "url_pattern": "^http://www.sovxin.com/fenlei_.+\\.html$", "alias": "категория", "id_parameter": [ "#" ], "encoding": "auto", "type": "ветвь", "save_page": false, "format": "html", "jshandle": false, "extract_rule": { "category": "crawled", "rule": {} }, "cookie": [], "inject_jquery": false, "load_img": false, "drill_rules": [ "a" ], "drill_relation": { "base": "content", "mode": "css", "expression": "title", "pick": "text", "index": 1 }, "validation_keywords": [ "当前位置" ], "script": [], "navigate_rule": [], "stoppage": -1, "priority": 2, "weight": 10, "schedule_interval": 86400, "active": true, "seed": [ "http://www.sovxin.com/fenlei_zixun.html" ], "schedule_rule": "FIFO", "use_proxy": false, "first_schedule": 1414938594585 }

![](http://git.oschina.net/uploads/images/2014/1103/153317_671070d2_13016.png)

```javascript
{
    "domain": "sovxin.com",
    "url_pattern": "^http://www.sovxin.com/$",
    "alias": "home",
}
## Продвинутый пример
### Кастомизация хранения данных
По умолчанию данные, полученные при парсинге, хранятся в HBase. Вы можете отключить это поведение по умолчанию и хранить данные в других типах баз данных. Для этого измените `instance/ваш_экземпляр/settings.json`, установив значение `save_content_to_hbase` в `false`. Затем измените `instance/ваш_экземпляр/spider_extend.js`, где вы сможете реализовать свои кастомизации. Удалите комментарий метода `pipeline`, который будет вызван после завершения парсинга страницы. Этот метод принимает два аргумента: `extracted_info` — структурированные данные, и `callback` — обратный вызов, требующий выполнения ваших действий (например, записи данных в вашей базе данных).

Пример кода (хранение данных в MongoDB) приведён ниже для справки:
``````javascript
/**
 * Вместо основной конвейерной логики фреймворка
 * если этот метод ничего не делает, закомментируйте его
 * @param extracted_info (тот же, что и в процессе извлечения)
 */
spider_extend.prototype.pipeline = function(extracted_info, callback) {
    var spider_extend = this;
    if (!extracted_info['extracted_data'] || isEmpty(extracted_info['extracted_data'])) {
        logger.warn('Данные ' + extracted_info['url'] + ' пусты.');
        callback();
    } else {
        var data = extracted_info['extracted_data'];
        if (data['article'] && data['article'].trim() !== '') {
            var _id = crypto.createHash('md5').update(extracted_info['url']).digest('hex');
            var pureContent = data['article'].replace(/[^\u4e00-\u9fa5a-z0-9]/ig, '');
            var simplefp = crypto.createHash('md5').update(pureContent).digest('hex');
            var currentTime = new Date();
currentTime.getTime();
data['обновлено'] = currentTime;
data['опубликовано'] = false;
``````markdown
// удаление дополнительной информации
if (data['$category']) delete data['$category'];
if (data['$require']) delete data['$require'];

// форматирование отношения в массив
if (выtracted_info['drill_relation']) {
    data['отношение'] = выtracted_info['drill_relation'].split('->');
}

// получение домена
var urlibarr = выtracted_info['origin']['urllib'].split(':');
var домен = urlibarr[urlibarr.length - 2];
data['домен'] = домен;

logger.debug('получено ' + data['название'] + ' с ' + домен + '(' + выtracted_info['url'] + ')');
data['url'] = выtracted_info['url'];

var запрос = {
    "$or": [
        {
            '_id': _id
        },
        {
            'simplefp': simplefp
        }
    ]
};

spider_extend.mongoTable.findOne(запрос, function (err, элемент) {
    if (err) {
        throw err;
        callback();
    } else {
        if (элемент) {
            // если новое значение поля меньше старого, удалить его
            (function (nlist) {
                for (var c = 0; c < nlist.length; c++) {
                    if (data[nlist[c]] && элемент[nlist[c]] && data[nlist[c]].length < элемент[nlist[c]].length)
                        delete data[nlist[c]];
                }
            })(['название', 'статья', 'теги', 'ключевые слова']);

            spider_extend.mongoTable.update({'_id': элемент['_id']}, {$set: data}, {w: 1}, function (err, результат) {
                if (!err) {
                    spider_extend.reportdb.rpush('очередь:обработано', _id);
                    logger.debug('обновление ' + data['название'] + ' в mongodb, ' + data['url'] + ' --перезапись-> ' + элемент['url']);
                }
                callback();
            });
        } else {
            data['simplefp'] = simplefp;
            data['_id'] = _id;
            data['создано'] = текущее_время;
            spider_extend.mongoTable.insert(data, {w: 1}, function (err, результат) {
                if (!err){
```

Перевод:

```markdown
// удаление дополнительной информации
if (data['$category']) delete data['$category'];
if (data['$require']) delete data['$require'];

// форматирование отношения в массив
if (выtracted_info['drill_relation']) {
    data['relation'] = выtracted_info['drill_relation'].split('->');
}

// получение домена
var urlibarr = выtracted_info['origin']['urllib'].split(':');
var domain = urlibarr[urlibarr.length - 2];
data['domain'] = domain;

logger.debug('received ' + data['name'] + ' from ' + domain + '(' + выtracted_info['url'] + ')');
data['url'] = выtracted_info['url'];

var query = {
    "$or": [
        {
            '_id': _id
        },
        {
            'simplefp': simplefp
        }
    ]
};

spider_extend.mongoTable.findOne(query, function (err, element) {
    if (err) {
        throw err;
        callback();
    } else {
        if (element) {
            // если новое значение поля меньше старого, удалить его
            (function (nlist) {
                for (var c = 0; c < nlist.length; c++) {
                    if (data[nlist[c]] && element[nlist[c]] && data[nlist[c]].length < element[nlist[c]].length)
                        delete data[nlist[c]];
                }
            })(['name', 'article', 'tags', 'keywords']);

            spider_extend.mongoTable.update({'_id': element['_id']}, {$set: data}, {w: 1}, function (err, result) {
                if (!err) {
                    spider_extend.reportdb.rpush('queue:processed', _id);
                    logger.debug('updated ' + data['name'] + ' in mongodb, ' + data['url'] + ' --overwrite-> ' + element['url']);
                }
                callback();
            });
        } else {
            data['simplefp'] = simplefp;
            data['_id'] = _id;
            data['created'] = current_time;
            spider_extend.mongoTable.insert(data, {w: 1}, function (err, result) {
                if (!err){
```## Настройка параллельной обработки данных пауками

Для изменения количества параллельных запросов, выполняемых пауками, отредактируйте файл `instance/ваш_экземпляр/settings.json` и установите значение параметра `SPIDER_CONCURRENCY`. Обратите внимание: этот параметр настраивает количество параллельных запросов, выполнение которых осуществляется пауками. Частота повторного захвата содержимого для каждого типа страниц устанавливается в интерфейсе конфигурирования правил.

## Кастомизация процесса извлечения ссылок и контентаИногда правила, установленные через веб-интерфейс, недостаточно для удовлетворения специфических требований к захвату данных. Например, после того как страница была захвачена, вам может потребоваться отправить AJAX-подзапрос для объединения данных. Либо вы можете предпочесть использовать свои методы для извлечения ссылок и контента. Удалите метод `extract` в файле `instance/ваш_экземпляр/spider_extend.js`, так как он будет вызван пауком после завершения извлечения данных. Этот метод принимает два аргумента: `extracted_info`, содержащий информацию о захваченном содержимом, и `callback`, который требуется вызвать после выполнения ваших действий.## 5. Данные Redis/ssdb

Понимание данных поможет вам лучше понять всю систему и проводить дальнейшие доработки. Neocrawler использует четыре хранилища: driller_info_redis_db, url_info_redis_db, url_report_redis_db, proxy_info_redis_db. Настройки можно найти в settings проекта.


```javascript
/**
  * @param {Object} extracted_info - информация, извлеченная из страницы
  * @param {Function} callback - обратный вызов с результатами
  */
spider_extend.prototype.extract = function(extracted_info, callback) {
    var self = this;
    var domain = __getTopLevelDomain(extracted_info['url']);
    var result = extracted_info;
```    switch (domain) {
        case 'sino-manager.com':
            if (result['origin'].urllib === 'urllib:driller:sino-manager.com:sinolist') {
                for (var i = 0; i < result['drill_link']['urllib:driller:sino-manager.com:sinolist'].length; i++) {
                    result['drill_link']['urllib:driller:sino-manager.com:sinolist'][i] = result['drill_link']['urllib:driller:sino-manager.com:sinolist'][i].replace(/(.{31})/, "$1s");
                }
                break;
            } else {
                break;
            }

        case 'chinaventure.com.cn':
            if (result['origin'].urllib === 'urllib:driller:chinaventure.com.cn:chinaventurelist') {
                var content = JSON.parse(result['content'].substring(1, result['content'].length - 1));
                var news_url = '';
                var detail = [];
                var list = [];
                var pages;

                for (var i = 0; i < content.length; i++) {
                    detail.push(content[i].news_url);
                }

                result['drill_link']['urllib:driller:chinaventure.com.cn:chinaventuredetail'] = detail;

                var expression = new RegExp('^.*pages=([0-9]+).*$', 'ig');
                var matched = expression.exec(result['url']);

                if (matched) {
                    pages = parseInt(matched[1]) + 1;
                    result['url'] = result['url'].replace('pages=' + matched[1], 'pages=' + pages);
                } else {
                }

                logger.debug(result['url']);
                list.push(result['url']);
                result['drill_link']['urllib:driller:chinaventure.com.cn:chinaventurelist'] = list;
                break;
            } else {
                break;
            }

        default:;
    }    return callback(result);
}

```JSON конфигурация, использует четыре различных категории хранения с одним и тем же ключом, который не вызывает конфликтов. Можно указывать все четыре пространства в одной базе данных Redis/SSDB, при этом каждое пространство может иметь различный темп роста. При использовании Redis рекомендуется направлять каждый тип пространства в отдельное базовое пространство (db). В идеальном случае каждому пространству следует выделить отдельную базу данных Redis.```Далее приведены описания четырёх пространств:

## driller_info_redis_dbСодержит правила сбора и адреса сайтов.
* `driller:{domain}:{alias}`
Пример: `driller:163.com:newslist`. Квадратные скобки обозначают переменные, аналогично далее. Хэш-тип, содержащий правила сбора, которые были настроены через веб-интерфейс.
* `urllib:driller:{domain}:{alias}`
Пример: `urllib:driller:163.com:newslist`. Списковый тип, содержащий очередь адресов сайта, соответствующих определённым правилам. Когда паук обнаруживает адрес, соответствующий правилам сбора, он помещает его в соответствующую очередь. Диспетчер извлекает адреса из этих очередей для распределения задач, а паук выполняет сбор информации согласно распределённой очереди. Процесс повторяется циклически.
* `queue:scheduled:all`
Очередь для планирования сбора, списковый тип. Одновременно существует множество `urllib` (см. выше). Диспетчер определяет текущий допустимый размер очереди на основе общего ограничения распределения пауками и длины очереди `queue:scheduled:all`. Затем он извлекает адреса из каждого списка в соответствии со значением приоритета (priority, weight), которое было настроено через веб-конфигурационный центр, и помещает их в очередь `queue:scheduled:all`. Паук извлекает адреса из этой очереди для выполнения сбора информации.
* `updated:driller:rule`
Запись версии правил сбора.Изменения пауков/диспетчеров относительно правил сбора реагируют мгновенно (в режиме реального времени), но полное перезагрузочное сканирование всех правил после каждого распределения (период примерно составляет несколько секунд) невозможно. Поэтому используется система версионирования. После изменения правил сбора через веб-конфигурационный центр версия обновляется. Паук периодически проверяет этот ключ; если обнаруживается изменение версии, то он перезагружает правила сбора.## url_info_redis_db

Это пространство содержит информацию об адресах сайтов. Чем больше время работы системы сбора, тем больше данных здесь накапливается.
* {url-md5-lowercase}
Пример: 9108d6a10bd476158144186138fe0ba8. Хэш-тип, содержащий подробную информацию об адресе сайта, странице, где был найден адрес, текущем состоянии, истории действий пауковой системы (открытие — распределение — сборка — хранение/неудача и т.д.) и последнем времени действия. Эти записи используются диспетчером как основа для принятия решений о том, следует ли снова распределять адрес сайта для сборки.

## url_report_redis_db

Это пространство содержит отчеты о работе пауков.
* fail:urllib:driller:{domain}:{alias}
Пример: fail:urllib:driller:163.com:newslist. Zset-тип, содержащий адреса сайтов, которые не удалось собрать.
* stuck:urllib:driller:{domain}:{alias}
Пример: stuck:urllib:driller:1.63.com:newslist. Zset-тип, содержащий адреса сайтов, которые не удалось сохранить (HBase). Ошибка при захвате/хранении URL можно исправить с помощью tools/queue-helper.js для добавления в очередь повторной попытки захвата.
Замечание: В связи с сетевыми факторами, паук уже выполняет повторные попытки при неудачном захвате; количество таких попыток можно настроить в settings.json. Упомянутые выше ошибки захвата/хранения обычно возникают после нескольких попыток и связаны либо с неправильными правилами захвата, либо с проблемами HBase.* count:{date}
Пример: count:20150203, тип хэша, увеличение статистики захвата, которое находится в соответствующих функциях расширения spider_extend.js. По умолчанию эти строки статистики закомментированы, но если их активировать, они будут выполнять увеличенное статистическое отслеживание. В конфигурационном центре Web "Ежедневный отчёт захвата" можно будет видеть результаты статистики.

## proxy_info_redis_db
Этот раздел предназначен для хранения данных, связанных с прокси-IP.

* proxy:public:available:3s
Список доступных прокси-IP

# [Контакты автора]
* E-mail: <successage@gmail.com>,
* Блог: <http://my.oschina.net/waterbear>
* Проблемы: <http://git.oschina.net/dreamidea/neocrawler/issues? assignee_id=&issue_search=&label_name=&milestone_id=&scope=&sort=&status=all>
* Группа QQ для обсуждения: 3239305
* QQ для беспокоить: 419117039
* WeChat для беспокоить: dreamidea

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

**Neocrawler** — система краулеров на Node.js. Особенности: * поддержка настройки правил извлечения через веб-интерфейс (CSS-селекторы и регулярные выражения); * наличие безголового браузерного движка (PhantomJS) для извлечения контента, созданного с помощью JavaScript; * использование HTTP-прокси для маршрутизации запросов с целью предотвращен... Развернуть Свернуть
BSD-3-Clause
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/dreamidea-neocrawler.git
git@api.gitlife.ru:oschina-mirror/dreamidea-neocrawler.git
oschina-mirror
dreamidea-neocrawler
dreamidea-neocrawler
master