现有的 Cheerio 选择属性有时会返回 undefined(使用 Puppeteer 获取 HTML)

3
我使用 Puppeteer 获取网站 HTML,然后用 Cheerio 爬取数据。这是我的代码的一部分。它几乎每次都能正常工作,但有时从 companyAddress 和 companyIntro 中得到 undefined。起初,我认为可能是由于不同页面之间的差异,但即使在不同时间爬取相同页面时也会出现这种情况(大多数时候我可以获取数据,但有时它是未定义的)。页面已成功渲染,并且通过 devtool 确认了属性及其值存在。我想知道背后的原因。可能是 Puppeteer 在抓取期间出了问题吗?Cheerio 代码是同步的,所以我不认为 Cheerio 是问题所在。我从未收到错误:无法获取未定义的 attr('profile'),这意味着有一个 header 元素,但我会收到错误:substring() of undefined。这就是为什么我在它之前放置了一个条件来检查的原因。
const puppeteer = require('puppeteer')
const cheerio = require('cheerio')
const baseUrl = 'https://www.104.com.tw'

const sleep = (milisecond) => {
  return new Promise((resolve, reject) => setTimeout(resolve, milisecond))
}

const scrapeCompanyPage = async (dataList, page) => {
  for (let i = 0; i < dataList.length; i++) {
    await page.goto(dataList[i].companyUrl)
    const html = await page.content()
    const $ = cheerio.load(html)
    const header = $('div.header')
    //sometimes company data below is undefined, but header exists
    dataList[i].companyAddress = header.attr('address') ? header.attr('address') : null
    dataList[i].companyIntro = header.attr('profile') ? header.attr('profile').substring(0, 50) : null 
    await sleep(1000)
  }
  return dataList
}

这段代码要爬取的网站是:https://www.104.com.tw/company/1a2x6bk72b?jobsource=2018indexpoc。不同的companyUrl会有不同的内容,但结构相同。
下面是我想要选择的HTML标签。

<div data-v-690c5d70="" data-v-09405bf2="" class="header mb-4" productpictures="" custno="13000000010336" industrydesc="..." indcat="..." empno="30" capital="80" address="..." custlink="https://unnotech.com"profile="..." management="..." phone="..." fax="..." hrname="HR" lat="25.0755569" lon="121.5756586" news="" newslink="" linkmore="[object Object]" corpimage1="" corpimage3="" corplink2="" corplink1="" corplink3="" envpictures="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" historys="" addrnodesc="..." reporturl="//www.104.com.tw/question_admin/reaction.cfm? j=5070426e34463e6730323a632c2e365f2444a42252525256a47682e2987j48" postalcode=""
        >...</div>


你能展示一下那个的HTML吗? - pguardiario
你是指特定的标签吗?@pguardiario - Jackson162
@pguardiario,我添加了HTML。你能帮我看一下吗?谢谢。因为似乎被屏蔽了,所以我删除了内容中的汉字。 - Jackson162
好的,下面请检查我的答案 - pguardiario
2个回答

0

链接中的那个有一个配置文件和地址属性, 所以那里不会出现这种情况。

如果属性缺失,您将获得未定义的值,例如 $(div).attr('foo')。

对于Node 14+,您可以使用可选链? 运算符来避免这些问题:

dataList[i].companyIntro = header.attr('profile')?.substring(0, 50)

这就是让我感到好奇的原因。有时候我可以获取数据,但有时候在完全相同的页面上却无法获取。谢谢分享新的语法。 - Jackson162

0

按下Ctrl-U,您将看到主内容的源代码为空。该网站可能由React、Vue或其他Javascript库进行渲染。因此,您需要等待元素出现。

但是,如果我在开发者工具>网络选项卡>XHR过滤器中检查网站,并重新加载页面,您将看到它们调用的API以获取这些元数据,例如地址、个人资料等... 您可能不需要爬取HTML。


1
这就是使用 Puppeteer 抓取客户端渲染网站的目的。看起来我没有权限访问那些 API。 - Jackson162

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接