KL.*_*Sea 5 javascript loops querying web-scraping puppeteer
我正在尝试以编程方式从 JavaScript 中的https://rarity.tools/upcoming/页面访问表中的数据。由于该网站通过 JavaScript 加载,因此我一直在使用 puppeteer。该网站有多个表(总共 4 个),我希望能够引用每个表并检查它们有多少行。
我最初尝试使用 nth-of-type,但我尝试从中接收数据的网站似乎没有以允许我使用 nth-of-type 或 nth-child 的方式构建其页面(请请参阅:在 javascript 错误中使用 pupeteer 访问第 n 个表并计算行数:“无法找到与选择器“table:nth-of-type(2) > tr”匹配的元素”” )。
相反,我尝试创建一个 for 循环来将每个表的innerHTML 设置为其自己的变量,然后根据索引分析HTML 字符串。如果我对数字进行硬编码,以下内容将返回正确的值:
console.log(table_html)
let table_html = await page.evaluate(
() => document.querySelectorAll('table')[2].innerHTML
)
Run Code Online (Sandbox Code Playgroud)
但是,一旦我将其设置为循环:
for (let j = 0; j < numTables; j++) {
let table_html = await page.evaluate(
(j) => document.querySelectorAll('table')[j].innerHTML
)
console.log(table_html)
}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
错误:评估失败:TypeError:无法在ExecutionContext._evaluateInternal 处的puppeteer_evaluation_script :1:46 处读取未定义的属性(读取“innerHTML”)(C:\Users\kylel\Desktop\NFTSorter_IsolatedJS\node_modules\puppeteer\lib\cjs
puppeteer\common \ExecutionContext.js:221:19) 在 processTicksAndRejections (internal/process/task_queues.js:95:5) 在异步 ExecutionContext.evaluate (C:\Users\kylel\Desktop\NFTSorter_IsolatedJS\node_modules\puppeteer\lib\cjs\pup peteer\common\ExecutionContext.js:110:16) 在异步获取 (C:\Users\kylel\Desktop\NFTSorter_IsolatedJS\app.js:35:30)
所有代码:
const puppeteer = require('puppeteer');
let fetch = async () => {
try {
// Puppeteer initialization
const browser = await puppeteer.launch({ headless: true, defaultViewport: null });
const [page] = await browser.pages();
await page.goto('https://rarity.tools/upcoming/');
await page.waitForTimeout(2500) // Timeout so page can load actual content
const numTables = await page.$$eval('table', el => el.length) - 1;
for (let j = 0; j < numTables; j++) {
let table_html = await page.evaluate(
(j) => document.querySelectorAll('table')[j].innerHTML
)
console.log(table_html)
}
}
catch (error) {
console.log(error)
}
}
fetch();
Run Code Online (Sandbox Code Playgroud)
如何修复此 for 循环以允许我为每个表运行 document.querySelectorAll('table') ?
此外,如果有人对我实现目标的方法有任何见解(使用 puppeteer 基于可变数量的表以编程方式访问这些表中的数据),我将不胜感激!如果我最终使用此处描述的方法,有什么建议可以使用哪些工具来分析字符串形式的 HTML?
非常感谢!
这段代码展示了一个经典的 Puppeteer 陷阱:
let table_html = await page.evaluate(
(j) => document.querySelectorAll('table')[j].innerHTML
)
Run Code Online (Sandbox Code Playgroud)
您需要j作为参数传递给,evaluate如如何将变量传递到评估函数?,否则在反j序列化函数并在浏览器控制台中执行时未定义。
let table_html = await page.evaluate(
(j) => document.querySelectorAll('table')[j].innerHTML, j
// ^^^
)
Run Code Online (Sandbox Code Playgroud)
也就是说,我建议使用$$evalandmap而不是计数器for循环,以避免担心索引。另外,这waitForTimeout似乎是不必要的竞争条件。waitForSelector按照文档的建议使用事件驱动的方法似乎更快、更可靠。
const puppeteer = require("puppeteer"); // ^13.5.1
let browser;
(async () => {
browser = await puppeteer.launch({headless: true});
const [page] = await browser.pages();
const url = "https://rarity.tools/upcoming/";
await page.goto(url, {waitUntil: "domcontentloaded"});
await page.waitForSelector("table");
const tableLengths = await page.$$eval("table", els =>
els.map(el => el.querySelectorAll("tr").length)
);
console.log(tableLengths);
const tableHTML = await page.$$eval("table", els =>
els.map(el => el.innerHTML)
);
console.log(tableHTML.map(e => e.slice(0, 50)));
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
Run Code Online (Sandbox Code Playgroud)
输出:
[ 224, 100, 21, 5 ]
[
'<tr class=""><th colspan="4" class="text-xl text-c',
'<tr class=""><th colspan="4" class="text-xl text-c',
'<tr class=""><th colspan="4" class="text-xl text-c',
'<tr class="hidden"><th colspan="4" class="text-xl '
]
Run Code Online (Sandbox Code Playgroud)
关于“如果我最终使用此处描述的方法,有什么建议可以使用哪些工具来分析字符串形式的 HTML?”,我不确定您计划对 HTML 进行什么样的分析,但一般来说也就是说,不要以字符串形式处理 HTML。对于 99% 的用例,请使用 Puppeteer 或浏览器控制台提供的 DOM、XPath 和 CSS 选择器。
例如,如果您想要每个表的平均价格,请选择<td>与价格列相对应的 s,循环遍历这些值,然后将单元格转换为数字并取平均值。使用字符串操作或正则表达式做同样的事情就像用剪刀修剪草坪,而那里有一台割草机。
更好的是,如果可以的话,完全避免刮擦。有一个开放端点https://collections.rarity.tools/upcoming2wget ,因此您可以使用或立即检索数据curl,假设它有您要查找的内容。