2016-10-04 3 views
1

Я видел некоторые ответы на это, которые ссылаются на абитуриентов в другие библиотеки (например, phantom.js), но я здесь задаюсь вопросом, все это можно сделать только в node.js?Node.js: запрос страницы и возможность создания страницы перед очисткой

Учитывая мой код ниже. Он запрашивает веб-страницу с использованием request, затем используя cheerio, он исследует dom до scrape страницы для данных. Он работает безупречно, и если все пойдет так, как планировалось, я считаю, что он выдал бы файл, как я себе представлял.

Проблема в том, что page I am requesting для того, чтобы очистить, построить таблицу IM, глядя на асинхронно с использованием либо Ajax или JSONP, я не совсем уверен, как .jsp работы страницы.
Итак, здесь я пытаюсь найти способ «подождать» для загрузки этих данных, прежде чем я очищу данные для своего нового файла.

var cheerio = require('cheerio'), 
    request = require('request'), 
    fs = require('fs'); 

// Go to the page in question 
request({ 
    method: 'GET', 
    url: 'http://www1.chineseshipping.com.cn/en/indices/cbcfinew.jsp' 
}, function(err, response, body) { 
    if (err) return console.error(err); 
    // Tell Cherrio to load the HTML 
    $ = cheerio.load(body); 


    // Create an empty object to write to the file later  
    var toSort = {} 

    // Itterate over DOM and fill the toSort object 
    $('#emb table td.list_right').each(function() { 
     var row = $(this).parent();  
     toSort[$(this).text()] = { 
      [$("#lastdate").text()]: $(row).find(".idx1").html(), 
      [$("#currdate").text()]: $(row).find(".idx2").html()    
     } 
    }); 

    //Write/overwrite a new file 
    var stream = fs.createWriteStream("/tmp/shipping.txt"); 
    var toWrite = ""; 

    stream.once('open', function(fd) { 
     toWrite += "{\r\n" 
     for(i in toSort){ 
      toWrite += "\t" + i + ": { \r\n"; 
       for(j in toSort[i]){ 
        toWrite += "\t\t" + j + ":" + toSort[i][j] + ",\r\n";    
       }    
      toWrite += "\t" + "}, \r\n"; 
     } 
     toWrite += "}" 

     stream.write(toWrite) 
     stream.end(); 
    }); 
}); 

Ожидаемый результат - текстовый файл с информацией, отформатированной как объект JSON.

Это должно выглядеть как различные экземпляры этого

"QINHUANGDAO - GUANGZHOU (50,000-60,000DWT)": { 
     "2016-09-29": 26.7, 
    "2016-09-30": 26.8, 
}, 

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

Я попробовал На самом деле просто установил setTimeout в разных местах в коде. Скрипт будет затронут только разработчиками, которые могут позволить себе запускать скрипт несколько раз, если он несколько раз терпит неудачу. Поэтому, хотя и не идеально, даже setTimeout (до 5 секунд) будет достаточно хорошим.

Оказалось, что расчеты не работают. Я подозреваю, что как только я попрошу страницу, я застрял на снимке страницы «как есть», когда я ее получу, и я на самом деле не смотрю на живое, что могу дождаться загрузки его динамического контента.

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

ответ

1

SetTimeout не имеет значения, даже если вы увеличите его до часа. Проблема заключается в том, что вы делаете запрос против этого URL-адреса: http://www1.chineseshipping.com.cn/en/indices/cbcfinew.jsp

и их сервер возвращает обратно html, и в этом html есть импорт js и css. Это конец вашего дела, у вас просто есть html, и все. Вместо этого браузер знает, как использовать и анализировать html-документ, чтобы он мог понимать скрипты javascript и выполнять/запускать их, и это именно ваша проблема. Ваша программа не может понять, что имеет какое-то отношение к содержимому HTML. Вам нужно найти или написать скребок, который может запускать javascript. Я только что нашел этот подобный вопрос на StackOverflow: Web-scraping JavaScript page with Python

Парень там предлагает https://github.com/niklasb/dryscrape и, кажется, что этот инструмент может работать JavaScript. Это написано на python.

+0

Ваше объяснение укрепило мои подозрения, спасибо. Хотя я не могу использовать python, я буду исследовать, как я могу разобрать страницу. Возможно, я мог бы взглянуть на размещение страницы и передать результаты или что-то еще. – NachoDawg

+0

Если вы ищете в google что-то вроде: node.js scraper framework, вы получите несколько результатов. Эта статья, возможно, будет полезна: http://blog.webkid.io/nodejs-scraping-libraries/ Если вы хотите, вы можете принять ответ :) –

+1

Со ссылкой в ​​вашем последнем комментарии, включая ответ, подходящее. рассмотрите возможность его редактирования в ответ :) – NachoDawg

1

Вы пытаетесь очистить исходную страницу, которая не включает данные, которые вам нужны. Когда страница загружается, браузер оценивает JS-код, который он включает, и этот код знает, где и как получить данные.

Первый вариант - оценить тот же код, что и PhantomJS.

Другой (и вам кажется, что его интересует) - это исследование сетевой активности страницы и понимание того, какие дополнительные запросы вы должны выполнить, чтобы получить нужные вам данные. В вашем случае, это:

http://index.chineseshipping.com.cn/servlet/cbfiDailyGetContrast?SpecifiedDate=&jc=jsonp1475577615267&_=1475577619626

и

http://index.chineseshipping.com.cn/servlet/allGetCurrentComposites?date=Tue%20Oct%2004%202016%2013:40:20%20GMT+0300%20(MSK)&jc=jsonp1475577615268&_=1475577620325

В обоих запросов:

  • _ является параметром decache, чтобы предотвратить кэширование.
  • jc это имя функции-оболочки JS, который должен быть вызван с результатом (https://en.wikipedia.org/wiki/JSONP)

Таким образом, слом шаблон таблицы в http://www1.chineseshipping.com.cn/en/indices/cbcfinew.jsp и выполнения двух дополнительных request S вы сможете объединить их в ту же структуру данных, которую вы видите в браузере.

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