2016-05-31 5 views
2

Так что я делаю небольшой скребок для учебных целей, в конце концов, я должен получить древовидную структуру страниц на веб-сайте.Как создать рекурсивный скребок с javascript?

Я ударил головой, пытаясь получить правильные запросы. Это более или менее то, что у меня есть:

var request = require('request'); 


function scanPage(url) { 

    // request the page at given url: 


    request.get(url, function(err, res, body) { 

    var pageObject = {}; 

    /* [... Jquery mumbo-jumbo to 

     1. Fill the page object with information and 
     2. Get the links on that page and store them into arrayOfLinks 

    */ 

    var arrayOfLinks = ['url1', 'url2', 'url3']; 

    for (var i = 0; i < arrayOfLinks.length; i++) { 

     pageObj[arrayOfLinks[i]] = scanPage[arrayOfLinks[i]]; 

    } 
    }); 

    return pageObj; 
} 

Я знаю, что этот код не так на многих уровнях, но это должно дать вам представление о том, что я пытаюсь сделать.

Как изменить его, чтобы он работал? (Без использования обещаний, если это возможно)

(можно предположить, что веб-сайт имеет древовидную структуру, так что каждая страница имеет только ссылки на страницы, далее вниз по три, следовательно, рекурсивный подход)

+0

Возможно, вам понадобится html-синтаксический анализатор. Попробуйте googling что-то вроде «javascript html parser» ... – Daniel

+0

Спасибо, но это не имеет никакого отношения к моему вопросу. Я анализирую html с помощью cheerio (реализация jQuery node.js), моя проблема заключается в том, как обрабатывать рекурсивное построение моего объекта. – Gloomy

+0

Самая большая проблема здесь - добиться рекурсивного поведения из-за асинхронного характера для javascript. – AJS

ответ

1

I знайте, что вы не хотите использовать обещания по какой-либо причине (и я не могу спросить, почему в комментариях, потому что я новичок), но я считаю, что обещания - лучший способ добиться этого.

Вот решение, используя обещания, что ответы на ваш вопрос, но не может быть именно то, что вам нужно:

var request = require('request'); 
var Promise = require('bluebird'); 
var get = Promise.promisify(request.get); 

var maxConnections = 1; // maximum number of concurrent connections 

function scanPage(url) { 

    // request the page at given url: 

    return get(url).then((res) => { 

     var body = res.body; 

     /* [... Jquery mumbo-jumbo to 

     1. Fill the page object with information and 
     2. Get the links on that page and store them into arrayOfLinks 

     */ 

     var arrayOfLinks = ['url1', 'url2', 'url3']; 

     return Promise.map(arrayOfLinks, scanPage, { concurrency: maxConnections }) 
          .then(results => { 
           var res = {}; 
           for (var i = 0; i < results.length; i++) 
            res[arrayOfLinks[i]] = results[i]; 
           return res; 
          }); 

    }); 

} 

scanPage("http://example.com/").then((res) => { 
    // do whatever with res 
}); 

Edit: Благодаря комментарий Берги, в переписал код, чтобы избежать конструктора антипаттерн Promise.

Редактировать: Переделано намного лучше. Используя опцию Bluebird concurrency, вы можете легко ограничить количество одновременных подключений.

+0

Избегайте антипаттера конструктора '' Promise' (http://stackoverflow.com/q/23803743/1048572)! Вы должны только пролонгировать 'request.get', используя его, а затем связать остальную часть кода с помощью' .then (...) '. – Bergi

+0

Не запускайте это на чем-то вроде википедии ... вы можете просто прогнать всю полосу пропускания в своей локальной сети, нагреть свой процессор и, возможно, заподозрить DDoSing на сайте или что-то в этом роде. Также попробуйте предотвратить циклические ссылки от выполнения чего-то вроде url1 -> url2 -> url1 -> ... '. –

+0

Я пришел к аналогичному решению, проблема в том, что все запросы срабатывают одновременно, а сервер * недоволен * (см. То, что говорит Патрик Робертс). Я попытался сделать это последовательно с помощью сокращения(), но для меня это слишком сложно, поэтому я просил «классического» решения. – Gloomy

Смежные вопросы