【问题标题】:NodeJs Pagination,recursive promise problemNodeJs分页,递归承诺问题
【发布时间】: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 的风格。

标签: javascript node.js recursion web-scraping 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
    猜你喜欢
    • 2022-01-04
    • 1970-01-01
    • 2020-07-22
    • 2021-11-21
    • 2014-02-04
    • 1970-01-01
    • 2018-07-02
    • 2018-05-29
    • 2017-11-01
    相关资源
    最近更新 更多