【问题标题】:How to get element from multiple URLs appending each one?如何从附加每个 URL 的多个 URL 中获取元素?
【发布时间】:2020-04-09 06:46:57
【问题描述】:

我有一个网站,其主 URL 包含多个链接。我想从该主页上的每个链接中获取第一个 <p> 元素。

我有以下代码可以很好地从主页获取所需的链接并将它们存储在urls 数组中。但我的问题是 我不知道如何进行循环以从 urls 数组加载每个 url 并在每次迭代中打印每个 first <p> 或附加它们 在一个变量中并在最后打印所有内容。

我该怎么做?谢谢

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

var main_url = 'http://www.someurl.com';

request(main_url, function(err, resp, body){
$ = cheerio.load(body);
links = $('a'); //get all hyperlinks from main URL
var urls = [];

//With this part I get the links (URLs) that I want to scrape.
$(links).each(function(i, link){
    lnk = 'http://www.someurl.com/files/' + $(link).attr('href');
    urls.push(lnk);
});

//In this part I don't know how to make a loop to load each url within urls array and get first <p>
    for (i = 0; i < urls.length; i++) { 

        var p = $("p:first") //first <p> element
        console.log(p.html());
    }
});

【问题讨论】:

    标签: node.js request cheerio


    【解决方案1】:

    如果您可以成功地从第一个 &lt;p&gt; 获取 URL,那么您已经知道要执行此操作的所有内容,所以我想您对 request 的工作方式有问题,尤其是基于回调的工作流程。

    我的建议是删除 request,因为它已被弃用。您可以使用基于 Promise 的 got 之类的东西,因此您可以使用它附带的较新的 async/await 功能(这通常意味着更轻松的工作流程)(不过,您至少需要使用 nodejs 8!) .

    您的循环将如下所示:

    for (const i = 0; i < urls.length; i++) {
      const source = await got(urls[i]);
      // Do your cheerio determination
      console.log(new_p.html());
    }
    

    请注意,您的函数签名需要调整。在您的情况下,您根本没有指定函数,因此使用了模块的函数签名,这意味着您不能使用await。所以为此编写一个函数:

    async function pullAllUrls() {
      const mainSource = await got(main_url);
      ...
    }
    

    如果你不想使用async/await,你可以减少一些承诺,但我认为这相当麻烦。然后回到 Promise 并使用像 async 这样的工作流库来帮助您管理 URL 获取。

    使用 async/await 的真实示例:

    在一个真实的例子中,我会创建一个函数来获取我想要获取的页面的源代码,就像这样(不要忘记将 got 添加到你的 script/package.json):

    async function getSourceFromUrl(thatUrl) {
      const response = await got(thatUrl);
      return response.body;
    }
    

    然后你有一个工作流逻辑来获取其他页面中的所有这些链接。我是这样实现的:

    async function grabLinksFromUrl(thatUrl) {
      const mainSource = await getSourceFromUrl(thatUrl);
      const $ = cheerio.load(mainSource);
      const hrefs = [];
    
      $('ul.menu__main-list').each((i, content) => {
        $('li a', content).each((idx, inner) => {
          const wantedUrl = $(inner).attr('href');
          hrefs.push(wantedUrl);
        });
      }).get();
    
      return hrefs;
    }
    

    我决定要获取&lt;nav&gt; 元素中的链接,这些链接通常包含在&lt;ul&gt;&lt;li&gt; 的元素中。所以我们只拿那些。

    然后您需要一个工作流程来处理这些链接。这就是for 循环所在的位置。我决定要每页的标题。

    async function mainFlow() {
      const urls = await grabLinksFromUrl('https://netzpolitik.org/');
      for (const url of urls) {
        const source = await getSourceFromUrl(url);
    
        const $ = cheerio.load(source);
        // Netpolitik has two <title> in their <head>
        const title = $('head > title').first().text();
        console.log(`${title} (${url}) has source of ${source.length} size`);
    
        // TODO: More work in here
      }
    }
    

    最后,您需要调用该工作流函数:

    return mainFlow();
    

    您在屏幕上看到的结果应如下所示:

    Dossiers & Recherchen (https://netzpolitik.org/dossiers-recherchen/) has source of 413853 size
    Der Netzpolitik-Podcast (https://netzpolitik.org/podcast/) has source of 333354 size
    14 Tage (https://netzpolitik.org/14-tage/) has source of 402312 size
    Official Netzpolitik Shop (https://netzpolitik.merchcowboy.com/) has source of 47825 size
    Über uns (https://netzpolitik.org/ueber-uns/#transparenz) has source of 308068 size
    Über uns (https://netzpolitik.org/ueber-uns) has source of 308068 size
    netzpolitik.org-Newsletter (https://netzpolitik.org/newsletter) has source of 291133 size
    netzwerk (https://netzpolitik.org/netzwerk/?via=nav) has source of 299694 size
    Spenden für netzpolitik.org (https://netzpolitik.org/spenden/?via=nav) has source of 296190 size
    

    【讨论】:

    • 您好,感谢您的回答。我有点失落。我需要在我已经拥有的代码中插入您共享的循环,或者应该进行哪些其他更改?我需要完全删除 request() 部分吗?如果你有机会,也许你可以展示一个更完整的例子,因为我对 JavaScript 和 nodejs 很陌生。谢谢
    • 嗨,我编辑了答案。也许现在最好理解我的意思。
    • 非常感谢您的帮助。现在我明白你的想法了。这似乎对我有用。我想知道是否总是需要创建一个 package.json?如果我在 js 文件中只有你的脚本会起作用吗?
    • 抱歉回复晚了。嗯...可以在没有 package.json 的情况下使用它,但这很不方便。你可以只开发你的应用程序,如果你想保持私有,只需执行npm pack,包将被打包到 something.tgz。您可以使用npm install something.tgz 安装它并很好地部署它。
    猜你喜欢
    • 2019-10-23
    • 1970-01-01
    • 2021-04-22
    • 2014-05-14
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    相关资源
    最近更新 更多