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