Reactor 3.x(Java):用于web抓取

Reactor 3.x(Java):用于web抓取,java,project-reactor,Java,Project Reactor,这里没有反应堆 这更像是一个如何解决的问题 比方说,我有一个网站,我想刮包含一个页面集的搜索结果。搜索结果页的数量未知。每个搜索页都有一个指向下一页的链接。我想从所有页面中刮取所有搜索结果并处理每个搜索结果 我如何使用Reactor(Mono/Flux)在Java中实现这一点 我想尽可能地“反应性地”做这件事 基本上,以下命令伪代码的Reactor(3.x)版本: String url = "http://example.com/search/1"; Optional<Do

这里没有反应堆

这更像是一个如何解决的问题

比方说,我有一个网站,我想刮包含一个页面集的搜索结果。搜索结果页的数量未知。每个搜索页都有一个指向下一页的链接。我想从所有页面中刮取所有搜索结果并处理每个搜索结果

我如何使用Reactor(Mono/Flux)在Java中实现这一点

我想尽可能地“反应性地”做这件事

基本上,以下命令伪代码的Reactor(3.x)版本:

    String url = "http://example.com/search/1";
    Optional<Document> docOp = getNextPage(url);    (1)
    while (docOp.isPresent()) {
        Document doc = docOp.get();
        processDoc(doc);                            (2)
        docOp = getNextPage(getNextUrl(doc));       (3)
    }

    // (1) Get the first page of search results
    // (2) Process all the search results on this page asynchronously
    // (3) Find the next page URL, and get that page
stringurl=”http://example.com/search/1";
可选docOp=getNextPage(url);(1)
while(docOp.isPresent()){
Document doc=docOp.get();
processDoc(doc);(2)
docOp=getNextPage(getnextur(doc));(3)
}
//(1)获取搜索结果的第一页
//(2)异步处理此页面上的所有搜索结果
//(3)找到下一页URL,并获取该页
在我的帮助下,我找到了这个解决方案。这可能并不理想。我很想得到任何人可能看到的问题的反馈

public void scrape() {

    Try<Document> firstDocTry = this.getSearchResultsPage(Option.<Document>none().toTry());    (1)

    // Generate a flux where each element in the flux is created using the current element
    Flux.<Try<Document>, Try<Document>>generate(() -> firstDocTry, (docTry, sink) -> {         (2)
            docTry = this.getSearchResultsPage(docTry);
            docTry.isFailure() ? sink.complete() : sink.next(docTry);
            return docTry;
        })
        .flatMap(docTry -> this.transformToScrapedLoads(docTry))                               (3)
        .log()
        .subscribe(scrapedLoad ->
            scrapedLoadRepo.save(scrapedLoad)                                                  (4)
        );
}

protected Try<Document> getSearchResultsPage(Try<Document> docTry) {
    ...
}

protected Flux<ScrapedLoad> transformToScrapedLoads(Try<Document> docTry) {
    ...
}
public void scrape(){
尝试firstDocTry=this.getSearchResultsPage(Option.none().toTry());(1)
//生成通量,其中通量中的每个元素都是使用当前元素创建的
生成(()->firstDocTry,(docTry,sink)->{(2)
docTry=this.getSearchResultsPage(docTry);
docTry.isFailure()?sink.complete():sink.next(docTry);
返回博士学位;
})
.flatMap(docTry->this.transformToScrapedLoads(docTry))(3)
.log()
.订阅(scrapedLoad->
scrapedLoadRepo.save(scrapedLoad)(4)
);
}
受保护的Try getSearchResultsPage(Try docTry){
...
}
受保护的通量转换到压缩负载(请尝试docTry){
...
}
(1) 在这里使用Javaslang的单子Try和OptionfirstDocTry的种子是发电机的种子。getSearchResultsPage()知道 如果没有提供文档,则从搜索的第一页开始

(2) 在这里使用发电机。通量中发布的每个元素由先前的元素确定

(3) transform方法将每个文档转换为一个流量,将其组合并作为单个流量发送给订阅

(4) 用户对通量产生的每个元素进行操作。在这种情况下,坚持他们