运行以下命令后,我在弄清楚如何阅读cheerio的响应时遇到了一些困难:
const axios = require('axios')
const cheerio = require('cheerio')
axios.get('https://bulbapedia.bulbagarden.net/wiki/Galar_Route_5')
.then(({data}) => {
const $ = cheerio.load(data)
const tableData = $('table:first').after('span#Hidden_encounters')
console.log(tableData)
})
当我运行上面的代码时,我得到一个相当长的响应:
LoadedCheerio {
'0': <ref *1> Element {
parent: Element {
parent: [Element],
prev: null,
next: [Text],
startIndex: null,
endIndex: null,
children: [Array],
name: 'div',
attribs: [Object: null prototype],
type: 'tag',
namespace: 'http://www.w3.org/1999/xhtml',
'x-attribsNamespace': [Object: null prototype],
'x-attribsPrefix': [Object: null prototype]
},
prev: null,
next: Text {
parent: [Element],
prev: [Circular *1],
next: [Text],
startIndex: null,
endIndex: null,
data: 'span#Hidden_encounters',
type: 'text'
},
startIndex: null,
endIndex: null,
children: [ [Text], [Element] ],
name: 'table',
attribs: [Object: null prototype] {
class: 'roundy',
style: 'background: #75C977; width: 30%; max-width: 30%; margin-left: 5px; margin-bottom: 5px; border: 3px solid #4AA14D; float:right; text-align:center'
},
type: 'tag',
namespace: 'http://www.w3.org/1999/xhtml',
'x-attribsNamespace': [Object: null prototype] { class: undefined, style: undefined },
'x-attribsPrefix': [Object: null prototype] { class: undefined, style: undefined }
},
length: 1,
options: { xml: false, decodeEntities: true },
_root: <ref *2> LoadedCheerio {
'0': Document {
parent: null,
prev: null,
next: null,
startIndex: null,
endIndex: null,
children: [Array],
type: 'root',
'x-mode': 'no-quirks'
},
length: 1,
options: { xml: false, decodeEntities: true },
_root: [Circular *2]
},
prevObject: <ref *3> LoadedCheerio {
'0': Document {
parent: null,
prev: null,
next: null,
startIndex: null,
endIndex: null,
children: [Array],
type: 'root',
'x-mode': 'no-quirks'
},
length: 1,
options: { xml: false, decodeEntities: true },
_root: [Circular *3]
}
}
我通读了文档,其中似乎没有任何关于如何阅读或解释响应的内容。
我在其他地方搜索过(youtube、这里、duckduckgo),但我无法找到任何真正告诉您如何解释响应的资源。
您看到的是 Cheerio 节点对象,而不是 HTTP 响应。尽管可以看到一些有用的信息,但您本身并不一定需要能够“阅读”它。只需从 Cheerio API 调用函数,例如 .text()
、
.find()
。 .map()
等等,操作对象并从中提取数据。最终,这个想法是将 Cheerio 节点树处理成一些普通的 JS 数据结构或原始值。对于这个例子,虽然您没有分享您的目标或期望的输出,但我认为您或多或少需要下表数据:
const axios = require("axios"); // ^1.6.8
const cheerio = require("cheerio"); // ^1.0.0-rc.12
axios
.get("<Your URL>")
.then(({data}) => {
const $ = cheerio.load(data);
const [headers, ...tableData] = [
...$("#Hidden_encounters")
.closest("h1, h2, h3, h4, h5, h6")
.next("table")
.find("tr"),
]
.map(e =>
[...$(e).find("th, td")].map(e => $(e).text().trim())
)
.filter(e => e.length > 1);
console.log(headers);
console.table(tableData);
});
[ 'Pokémon', 'Games', 'Location', 'Levels', 'Rate' ]
┌─────────┬────────────┬──────┬──────┬──────────────┬─────────┬────────┐
│ (index) │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │
├─────────┼────────────┼──────┼──────┼──────────────┼─────────┼────────┤
│ 0 │ 'Lombre' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '20%' │
│ 1 │ 'Nuzleaf' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '20%' │
│ 2 │ 'Nincada' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '5%' │
│ 3 │ 'Espurr' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '20%' │
│ 4 │ 'Spritzee' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '14%' │
│ 5 │ 'Swirlix' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '14%' │
│ 6 │ 'Dewpider' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '5%' │
│ 7 │ 'Dottler' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '26%' │
│ 8 │ 'Applin' │ 'Sw' │ 'Sh' │ 'Grass' │ '16-18' │ '10%' │
│ 9 │ 'Skwovet' │ 'Sw' │ 'Sh' │ 'Berry tree' │ '16-18' │ '100%' │
│ 10 │ 'Goldeen' │ 'Sw' │ 'Sh' │ 'Fishing' │ '16-18' │ '10%' │
│ 11 │ 'Magikarp' │ 'Sw' │ 'Sh' │ 'Fishing' │ '16-18' │ '70%' │
│ 12 │ 'Chewtle' │ 'Sw' │ 'Sh' │ 'Fishing' │ '16-18' │ '20%' │
└─────────┴────────────┴──────┴──────┴──────────────┴─────────┴────────┘
可以做更多的工作将两个“游戏”单元组合为一个,但这至少可以让您开始并处理 Cheerio 部分。
Cheerio 的抓取表上还存在许多其他线程。查看以下答案应该可以阐明抓取行的两步模式,然后是具有嵌套
.map
调用的单元格,如上所示: