NodeJs分页,递归承诺问题
Posted
技术标签:
【中文标题】NodeJs分页,递归承诺问题【英文标题】:NodeJs Pagination,recursive promise problem 【发布时间】:2021-06-30 07:33:56 【问题描述】:我在 node.js 中使用cheerio 和 axios 抓取多个页面 我在使用 Promises 时遇到了困难,如果我点击最后一页,有人可以帮我返回 JSON 吗?谢谢!
const getWebsiteContent = async (url) =>
await axios.get(url).then(res =>
const $ = cheerio.load(res.data)
pageNum = getTotalpages($); // Get the pagination
console.log(url);
//Some scraping here
)
indexPage++; // Increment to the next page
const nextPageLink = baseUrl + '&page=' + indexPage; // get next page
if (indexPage > pageNum)
var editedText = text.slice(0, text.length - 1);
editedText += ']';
editedText = JSON.parse(editedText); // I want to return this and use elsewhere
return editedText;
setTimeout(async () =>
getWebsiteContent(nextPageLink); // Call itself
, 1000);
var myJSON= await getWebsiteContent(baseUrl); // something like this
【问题讨论】:
我在一些my answers 中使用asyncUnfold
。我写这些已经有一段时间了,但它非常适合这种问题。如果今晚晚些时候我有时间,我可以向您展示如何使用异步生成器:D
您要返回哪个 JSON?
1:谢谢,我等着! 2:在 if(indexPage>pageNum) 中,我连接 JSON 字符串的最后一位,将其解析为 JSON。我想返回该 JSON。
不要混用 async
/await
、.then()
和传递回调。将setTimeout
包装在一个promise 中,并决定一种处理promise 的风格。
【参考方案1】:
我会写 getPages
作为异步生成器 -
async function* getPages (href, initPage = 0)
const res = await axios.get(setPage(href, initPage))
const $ = cheerio.load(res.data)
const pages = getTotalpages($)
yield page: initPage, dom: $
for (let p = initPage; p < pages; p++)
await sleep(1000)
const r = await axios.get(setPage(href, p))
yield page: p, dom: cheerio.load(r.data)
这取决于帮助器setPage
,它使用url module 操作href 页码,这比手动将字符串拼凑在一起要安全得多-
function setPage (href, page)
const u = new URL(href)
u.searchParams.set("page", page)
return u.toString()
还有另一个助手sleep
,它可以防止setTimeout
与基于async
的代码混合。这让我们可以轻松地在页面之间暂停 -
async function sleep (ms)
return new Promise(r => setTimeout(r, ms))
最后我们编写scrape
,它是getPages
的简单包装。这允许我们重用getPages
函数来根据需要抓取各种元素。使用这种方法的一个好处是调用者可以确定每个页面发生了什么。下面我们推送到result
数组,但作为另一个示例,我们可以使用fs
模块将每个页面写入磁盘。显然这由你决定 -
async function scrape (href)
const result = []
for await (const page, dom of getPages(href))
console.log("scraped page", page) // some status message
result.push(getSomeData(dom)) // get something from each page
return result
scrape(myUrl).then(console.log, console.error)
【讨论】:
【参考方案2】:您不应该将 then
与您的 async / await 代码一起使用。
分页应该是这样的:
let response = await axios.get(url)
let $ = cheerio.load(response.data)
// do some scraping
while(url = $('[rel=next]').attr('href'))
response = await axios.get(url)
$ = cheerio.load(response.data)
// do more scraping
【讨论】:
不,这不能解决我的问题。我的输出是这样的: url/page1 undefined url/page2 url/page3 END 我的输出应该是这样的: url/page1 url/page2 url/page3 JSON END以上是关于NodeJs分页,递归承诺问题的主要内容,如果未能解决你的问题,请参考以下文章
NodeJS 中的 Firebase javascript 承诺
NodeJS 不能等待 MySQL 数据库承诺,而是等待其他承诺