如何从每个附加的多个 URL 中获取元素?

How to get element from multiple URLs appending each one?

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

我有以下代码可以很好地从主页获取所需的 links 并将它们存储在 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());
    }
});

如果您可以从第一个 <p> 成功获得 URLs,那么您已经知道该怎么做,所以我想您对 request 的工作方式有疑问并且特别是基于回调的工作流程。

我的建议是删除 request,因为它已被弃用。您可以使用基于 Promise 的 got 之类的东西,这样您就可以使用它附带的更新的 async/await 功能(这通常意味着更简单的工作流程)(不过,您需要使用 at至少 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;
}

我决定要获取通常包含在 <ul><li> 元素中的 <nav> 元素中的链接。所以我们只拿那些。

那么您需要一个工作流程来处理这些链接。这就是 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