Javascript 使用Rx.js在页面上迭代的Web scraper

Javascript 使用Rx.js在页面上迭代的Web scraper,javascript,asynchronous,reactive-programming,rxjs,Javascript,Asynchronous,Reactive Programming,Rxjs,大约一个月前,我建立了一个异步的方式收集信息的网络刮板。我正试着用同样的工具再次制造同样的刮板。我已经阅读了所有的文档,这似乎是有道理的,开始是最困难的一点,但在那之后,我取得了一些进展 您可以在这里看到,我获得了站点的第一个页面(第0页),我需要使用该页面来获得页面数(大约6000页)。我有这个计数,并且使用getPageURI(page)我可以创建每个页面URL,但是我的问题是我不知道如何触发,或者触发,或者将信息传输回原始pageRequestStream。我有这个页面计数编号,我需要一种

大约一个月前,我建立了一个异步的方式收集信息的网络刮板。我正试着用同样的工具再次制造同样的刮板。我已经阅读了所有的文档,这似乎是有道理的,开始是最困难的一点,但在那之后,我取得了一些进展

您可以在这里看到,我获得了站点的第一个页面(第0页),我需要使用该页面来获得页面数(大约6000页)。我有这个计数,并且使用
getPageURI(page)
我可以创建每个页面URL,但是我的问题是我不知道如何
触发
,或者
触发
,或者
信息传输回原始
pageRequestStream
。我有这个页面计数编号,我需要一种方法来迭代它,将数据推回到第一个原始
pageRequestStream

import cheerio from 'cheerio'
import Rx from 'rx'
import fetch from 'isomorphic-fetch'

const DIGITAL_NYC_URI = 'http://www.digital.nyc'
let getPageURI = (page) => `${DIGITAL_NYC_URI}/startups?page=${page}`
let getProfileURI = (profile) => `${DIGITAL_NYC_URI}${profile}`

function fetchURL(stream, dataType = 'json') {
  return stream.flatMap(requestURL => {
    return Rx.Observable.fromPromise(fetch(requestURL).then(res => res[dataType]()))
  })
}

function getNumberOfPages($) {
  let summary = $('.result-summary').text()
  let match = summary.match(/Showing 1 - 20 of (\d+) Startups/)
  return parseInt(match[1], 10)
}

function getCompaniesOnPage ($) {
  let companySelector = 'h3.node-title a'
  let companies = $(companySelector).map(function (i, el) {
    let name = $(this).text()
    let profile = $(this).attr('href')
    return {
      'name': name,
      'profile': profile
    }
  }).get()
  return companies
}

let pageRequestStream = Rx.Observable.just(getPageURI(0))

let pageResponseStream = fetchURL(pageRequestStream, 'text')

let parsedPageHTMLStream = pageResponseStream.map(html => cheerio.load(html))

let numberOfPagesStream = parsedPageHTMLStream.map(html => getNumberOfPages(html))

// not sure how to get this to iterate over count and fire url's into pageRequestStream
numberOfPagesStream.subscribe(pageCount => console.log(pageCount))

let companiesOnPageStream = parsedPageHTMLStream.flatMap(html => getCompaniesOnPage(html))

// not sure how to build up the company object to include async value company.profileHTML
companiesOnPageStream.subscribe(companies => console.log(companies))


// let companyProfileStream = companiesOnPageStream.map((company) => {
//   return fetch(getProfileURI(company.profile))
//     .then(res => res.html())
//     .then(html => {
//       company.profileHTML = html
//       return company
//     })
// })
看一看,它们可以让你边走边触发事件

也许这能给我们一些启发

import cheerio from 'cheerio';
import Rx from 'rx';
import fetch from 'isomorphic-fetch';

function getCheerio(url) {
  var promise = fetch(url)
        .then(response => response.text())
        .then(body => cheerio.load(body));
  return Rx.Observable.fromPromise(promise);
}

const DIGITAL_NYC_URI = 'http://www.digital.nyc';

var pageRequest = new Rx.Subject();

pageRequest
  .flatMap(pageUrl => getCheerio(pageUrl))
  .flatMap(page$ => {
    // here we pipe back urls into our original observable.
    var nextPageUrl = page$('ul.pagination li.arrow a').attr('href');
    if(nextPageUrl) pageRequest.onNext(DIGITAL_NYC_URI + '/' + nextPageUrl);

    var profileUrls = page$('h3.node-title a')
          .map(function() {
            var url = page$(this).attr('href');
            return DIGITAL_NYC_URI + '/' + url;
          });
    return Rx.Observable.from(profileUrls);
  })
  .flatMap(url => getCheerio(url))
  .map(profile$ => {
    // build the company profile here
    return profile$('title').text();
  })
  .subscribe(value => console.log('profile ',  value));

pageRequest.onNext(DIGITAL_NYC_URI + '/startups');