带有cheerio和请求的节点js中的增量和非增量url

Posted

技术标签:

【中文标题】带有cheerio和请求的节点js中的增量和非增量url【英文标题】:Incremental and non-incremental urls in node js with cheerio and request 【发布时间】:2014-09-25 23:24:29 【问题描述】:

我正在尝试使用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,我们称之为 2a) 6) 提取 url 2b (http://example2.com/693) 7) 转到 url 2b 8) 提取一些数据并保存等...

我正在努力解决如何做到这一点(注意,我只熟悉这个任务的 node 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 需要递增 s=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 新手

【问题讨论】:

OP 不寻求帮助调试代码@mrueg;这本质上是在询问逻辑。 @Ben 是正确的 - 逻辑是我在这里失败的原因。欢迎提出任何建议。 为了清晰起见,我已经更新了代码示例。任何帮助表示赞赏。 让我以另一种方式继续我的回答。您可以使用 JavaScript 数组实现task queue,如此 SO 问题中所述:***.com/questions/1590247/…。 task queue 将包含要做的事情列表,例如要处理的 url 列表,例如ids 变量列表或函数列表或其他任何可用作 task 的列表。您在理解网站复制器的内部结构方面是否有问题,或者您在使用 JavaScript 编码时遇到问题,或两者兼而有之? 我不知道如何在 javascript 中为 node js 编写代码。我是 javascript 新手。 【参考方案1】:

您可以通过研究现有的著名网站复制器(闭源或开源)来了解如何做到这一点

例如 - 使用 http://www.tenmax.com/teleport/pro/home.htm 的试用版来废弃您的页面,然后尝试使用 http://www.httrack.com 进行相同操作,您应该清楚地了解他们是如何做到的(以及如何做到这一点)。

关键的编程概念是lookup cachetask queue

如果您的解决方案应该很好地扩展到多个 node.js 工作进程和多个页面,那么递归在这里不是一个成功的概念

编辑:澄清 cmets 后

在开始将报废引擎改造成更具可扩展性的架构之前,作为新的 Node.js 开发人员,您可以简单地从 @lucio-m 创建的 wait.for 包提供的 Node.js callback hell 的同步替代方案开始-土豆。

下面的代码与您提供的链接一起为我工作

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);

【讨论】:

【参考方案2】:

您可以使用附加的异步模块来处理多个请求并通过多个页面进行迭代。在https://github.com/caolan/async 阅读更多关于异步的信息。

【讨论】:

以上是关于带有cheerio和请求的节点js中的增量和非增量url的主要内容,如果未能解决你的问题,请参考以下文章

增量静态再生中的重新验证过程如何工作?

增量静态再生中的重新验证过程如何工作?

如何使用带有 CollectionViewSource 的增量加载集合对 UWP 中的列表视图项进行分组?

Redis主从之全量复制和增量复制

PHP中的前置增量和后置增量

损坏:带有增量计数器的 For 循环中的 Elif