Инкрементные и неинкрементные URL-адреса в узле js с cheerio и запросом

Я пытаюсь очистить данные со страницы с помощью cheerio и запросить следующим образом:

  • 1) перейти к url 1a (http://example.com/0)
  • 2) извлечь url 1b (http://example2.com/52)
  • 3) перейти к url 1b
  • 4) извлеките некоторые данные и сохраните
  • 5) перейдите к URL-адресу 1a + 1 (http://example.com/1, позвоните ему 2а)
  • 6) извлечь url 2b (http://example2.com/693)
  • 7) перейти к url 2b
  • 8) извлекать некоторые данные и сохранять и т.д....

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

РЕДАКТИРОВАТЬ

Позвольте мне попробовать это по-другому. вот первая часть кода:

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

 request('http://api.trove.nla.gov.au/result?key=6k6oagt6ott4ohno&zone=book&l-advformat=Thesis&sortby=dateDesc&q=+date%3A[2000+TO+2014]&l-availability=y&l-australian=y&n=1&s=0', function(error, response, html) {

 if (!error && response.statusCode == 200) {
 var $ = cheerio.load(html, {
 xmlMode: true
 });

 var id = ($('work').attr('id'))
 var total = ($('record').attr('total'))
 }
});

Первая возвращенная страница выглядит так:

<response>
 <query>date:[2000 TO 2014]</query>
 <zone name="book">
 <records s="0" n="1" total="69977" next="/result?l-advformat=Thesis&sortby=dateDesc&q=+date%3A%5B2000+TO+2014%5D&l-availability=y&l-australian=y&n=1&zone=book&s=1">
 <work id="189231549" url="/work/189231549">
 <troveurl>http://trove.nla.gov.au/work/189231549</troveurl>
 <title>
 Design of physiological control and magnetic levitation systems for a total artificial heart
 </title>
 <contributor>Greatrex, Nicholas Anthony</contributor>
 <issued>2014</issued>
 <type>Thesis</type>
 <holdingscount>1</holdingscount>
 <versioncount>1</versioncount>
 <relevance score="0.001961126">vaguely relevant</relevance>
 <identifier type="url" linktype="fulltext">http://eprints.qut.edu.au/65642/</identifier>
 </work>
 </records>
 </zone>
</response>

Приведенный выше URL должен увеличиваться постепенно с = 0, s = 1 и т.д. Для "общего" количества раз. 'id' необходимо ввести в url ниже во втором запросе:

request('http://api.trove.nla.gov.au/work/" +(id)+ "?key=6k6oagt6ott4ohno&reclevel=full', function(error, response, html) {

 if (!error && response.statusCode == 200) {
 var $ = cheerio.load(html, {
 xmlMode: true
 });

 //extract data here etc.

 }
});

Например, при использовании id = "189231549", возвращенного первым запросом, вторая возвращенная страница выглядит так:

<work id="189231549" url="/work/189231549">
 <troveurl>http://trove.nla.gov.au/work/189231549</troveurl>
 <title>
 Design of physiological control and magnetic levitation systems for a total artificial heart
 </title>
 <contributor>Greatrex, Nicholas Anthony</contributor>
 <issued>2014</issued>
 <type>Thesis</type>
 <subject>Total Artificial Heart</subject>
 <subject>Magnetic Levitation</subject>
 <subject>Physiological Control</subject>
 <abstract>
 Total Artificial Hearts are mechanical pumps which can be used to replace the failing natural heart. This novel study developed a means of controlling a new design of pump to reproduce physiological flow bringing closer the realisation of a practical artificial heart. Using a mathematical model of the device, an optimisation algorithm was used to determine the best configuration for the magnetic levitation system of the pump. The prototype device was constructed and tested in a mock circulation loop. A physiological controller was designed to replicate the Frank-Starling like balancing behaviour of the natural heart. The device and controller provided sufficient support for a human patient while also demonstrating good response to various physiological conditions and events. This novel work brings the design of a practical artificial heart closer to realisation.
 </abstract>
 <language>English</language>
 <holdingscount>1</holdingscount>
 <versioncount>1</versioncount>
 <tagcount>0</tagcount>
 <commentcount>0</commentcount>
 <listcount>0</listcount>
 <identifier type="url" linktype="fulltext">http://eprints.qut.edu.au/65642/</identifier>
</work>

Итак, теперь мой вопрос: как мне связать эти две части (циклы) вместе для достижения результата (загрузить и проанализировать около 70000 страниц)?

Я не знаю, как закодировать это в JavaScript для Node.js. Я новичок в JavaScript

2 ответа

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

Например, используйте пробную копию http://www.tenmax.com/teleport/pro/home.htm, чтобы отказаться от ваших страниц, а затем попробуйте сделать то же самое с http://www.httrack.com, и вы должны понять, как они сделали это (и как вы это сделаете) достаточно четко.

Ключевыми понятиями программирования являются lookup cache и task queue

Рекурсия не является успешной концепцией здесь, если ваше решение должно масштабироваться до нескольких рабочих процессов node.js и до многих страниц

EDIT: после уточнения комментариев

Прежде чем вы начнете перерабатывать свой утилизируемый движок в более масштабируемую архитектуру, как новый разработчик Node.js, вы можете начать просто с синхронизированной альтернативы аддону обратного вызова Node.js, как это предусмотрено пакетом wait.for, созданным с помощью @lucio-m- тато.

Код ниже работал для меня со ссылками, которые вы предоставили

var request = require('request');
var cheerio = require('cheerio');
var wait = require("wait.for");

function requestWaitForWrapper(url, callback) {
 request(url, function(error, response, html) {
 if (error)
 callback(error, response);
 else if (response.statusCode == 200)
 callback(null, html);
 else
 callback(new Error("Status not 200 OK"), response);
 });
}

function readBookInfo(baseUrl, s) {
 var html = wait.for(requestWaitForWrapper, baseUrl + '&s=' + s.toString());
 var $ = cheerio.load(html, {
 xmlMode: true
 });

 return {
 s: s,
 id: $('work').attr('id'),
 total: parseInt($('records').attr('total'))
 };
}

function readWorkInfo(id) {
 var html = wait.for(requestWaitForWrapper, 'http://api.trove.nla.gov.au/work/' + id.toString() + '?key=6k6oagt6ott4ohno&reclevel=full');
 var $ = cheerio.load(html, {
 xmlMode: true
 });

 return {
 title: $('title').text(),
 contributor: $('contributor').text()
 }
}

function main() {
 var baseBookUrl = 'http://api.trove.nla.gov.au/result?key=6k6oagt6ott4ohno&zone=book&l-advformat=Thesis&sortby=dateDesc&q=+date%3A[2000+TO+2014]&l-availability=y&l-australian=y&n=1';
 var baseInfo = readBookInfo(baseBookUrl, 0);

 for (var s = 0; s < baseInfo.total; s++) {
 var bookInfo = readBookInfo(baseBookUrl, s);
 var workInfo = readWorkInfo(bookInfo.id);
 console.log(bookInfo.id + ";" + workInfo.contributor + ";" + workInfo.title);
 }
}

wait.launchFiber(main);


Вы можете использовать дополнительный асинхронный модуль для обработки нескольких запросов и итераций через несколько страниц. Подробнее о async здесь https://github.com/caolan/async.

licensed under cc by-sa 3.0 with attribution.