javascript - 为什么 .text() 和 .html() 不能与 cheerio js 和 node-fetch 一起使用?

标签 javascript node.js cheerio node-fetch

我是 Node JS 的新手,使用 node-fetch 和 cheerio 包。我试图从不同的网站抓取数据,所以我通过传递许多不同的 URL 和选择器来进行测试。但是,在下面的代码中,无论我将什么选择器或 URL 作为输入传递,.text() 都会返回一个空字符串,而 .html() 会返回 null。

const cheerio= require('cheerio');
const fetch = require('node-fetch');

fetch('https://www.npmjs.com/package/node-fetch/')
    .then((res)=>{ 
        if(res.ok){       
            let $=cheerio.load(res);
            console.log(res);
            let siteData = $('#readme > p:nth-child(8)');
            console.log(siteData.text());
            console.log(siteData.html());
            return res.text();
        }else{
            throw new Error(res.statusText);
        }
    }) 
    .then(body => console.log(body))       
    .catch(error => console.log(error))

我什至将 res.text() 的输出写入文件,并将其与网站的源 HTML 进行比较。这几乎是一样的。 res的值打印如下:

Response {
  size: 0,
  timeout: 0,
  prev: null,
  next: null,
  root: {
    type: 'root',
    name: 'root',
    namespace: 'http://www.w3.org/1999/xhtml',
    attribs: [Object: null prototype] {},
    'x-attribsNamespace': [Object: null prototype] {},
    'x-attribsPrefix': [Object: null prototype] {},
    children: [ [Circular] ],
    parent: null,
    prev: null,
    next: null
  },
  parent: null,
  [Symbol(Body internals)]: {
    body: Gunzip {
      _writeState: [Uint32Array],
      _readableState: [ReadableState],
      readable: true,
      _events: [Object: null prototype],
      _eventsCount: 6,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: true,
      allowHalfOpen: true,
      _transformState: [Object],
      _hadError: false,
      bytesWritten: 0,
      _handle: [Zlib],
      _outBuffer: <Buffer 80 00 f4 9f 03 02 00 00 f0 80 f2 9f 03 02 00 00 20 46 00 00 00 00 00 00 d8 73 dd 9f 03 02 00 00 0f 00 00 00 7f ae f8 39 01 5d dd 9f 03 02 00 00 d0 68 ... 16334 more bytes>,
      _outOffset: 0,
      _chunkSize: 16384,
      _defaultFlushFlag: 2,
      _finishFlushFlag: 2,
      _defaultFullFlushFlag: 3,
      _info: undefined,
      _level: -1,
      _strategy: 0,
      [Symbol(kCapture)]: false
    },
    disturbed: false,
    error: null
  },
  [Symbol(Response internals)]: {
    url: 'https://www.npmjs.com/package/node-fetch',
    status: 200,
    statusText: 'OK',
    headers: Headers { [Symbol(map)]: [Object: null prototype] },
    counter: 1
  }
}

连 siteData 的对象也打印如下:

initialize {
  options: {
    withDomLvl1: true,
    normalizeWhitespace: false,
    xml: false,
    decodeEntities: true
  },
  _root: initialize {
    '0': {
      type: 'root',
      name: 'root',
      namespace: 'http://www.w3.org/1999/xhtml',
      attribs: [Object: null prototype] {},
      'x-attribsNamespace': [Object: null prototype] {},
      'x-attribsPrefix': [Object: null prototype] {},
      children: [Array],
      parent: null,
      prev: null,
      next: null
    },
    options: {
      withDomLvl1: true,
      normalizeWhitespace: false,
      xml: false,
      decodeEntities: true
    },
    length: 1,
    _root: [Circular]
  },
  length: 0,
  prevObject: initialize {
    '0': {
      type: 'root',
      name: 'root',
      namespace: 'http://www.w3.org/1999/xhtml',
      attribs: [Object: null prototype] {},
      'x-attribsNamespace': [Object: null prototype] {},
      'x-attribsPrefix': [Object: null prototype] {},
      children: [Array],
      parent: null,
      prev: null,
      next: null
    },
    options: {
      withDomLvl1: true,
      normalizeWhitespace: false,
      xml: false,
      decodeEntities: true
    },
    length: 1,
    _root: [Circular]
  }
}

仍然,siteData.text() 是一个空字符串,而 siteData.html() 是 null。请告知这段代码有什么问题,我浏览了许多堆栈溢出页面,并阅读了 cheerio 文档,但我仍然没有找到答案。

在此先感谢您。

最佳答案

这是我使用的 Cheerio/fetch 样板(fetch 现在在 Node 18 中是原生的,所以我省略了导入):

const cheerio = require("cheerio"); // 1.0.0-rc.12

const url = "https://www.npmjs.com/package/node-fetch/";

fetch(url)
  .then(response => {
    if (!response.ok) {
      throw Error(response.statusText);
    }

    return response.text();
  })
  .then(html => {
    const $ = cheerio.load(html);

    // work with $
  })
  .catch(error => console.log(error));

请注意,我们调用了 response.text() 并解决了将 HTML 提供给 Cheerio 的 promise ,而不是尝试使用 Cheerio 解析响应元数据。

这也可以通过 async/await 来完成:

const cheerio = require("cheerio");

const url = "https://www.npmjs.com/package/node-fetch/";

(async () => {
  const response = await fetch(url);

  if (!response.ok) {
    throw Error(response.statusText);
  }

  const html = await response.text();
  const $ = cheerio.load(html);

  // work with $
})()
  .catch(error => console.log(error));

一般来说,请记住 Cheerio 不执行任何 JS,因此您从 fetch 响应中获得的唯一数据是纯静态 HTML(如果您 view-source: 在页面上)仅此而已。

关于javascript - 为什么 .text() 和 .html() 不能与 cheerio js 和 node-fetch 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64873385/

相关文章:

javascript - 当可观察数组被修改时如何触发函数

Javascript - BackboneJS - Backbone.sync 覆盖 - YDN - 异步错误

javascript - 如何从 meteor shell 将任何内容记录到控制台?

javascript - 停止 Rxjs 观察者的下一次执行?

node.js - 如何处理需求循环?

javascript - 如何使敌人看起来与英雄不同 Canvas socket.io

javascript - Nodejs如何从mysql检索变量值

javascript - 在nodejs中保存从url保存的图像时出现问题

javascript - jquery SlideDown() 不起作用,但 fadeIn() 起作用

node.js - Cheerio 返回不在 dom 中的文本