【问题标题】:existing attribute selected by Cheerio sometimes return undefined (get HTML with Puppeteer)Cheerio 选择的现有属性有时会返回未定义(使用 Puppeteer 获取 HTML)
【发布时间】:2021-05-26 00:26:50
【问题描述】:

我使用 Puppeteer 获取网站 HTML,然后使用 Cheerio 抓取数据。这是我的代码的一部分。它几乎每次都能正常工作,但有时我从 companyAddress 和 companyIntro 得到未定义。一开始,我以为这可能是由于不同页面的差异,但即使我在不​​同时间抓取同一页面也会发生这种情况(大多数时候我得到数据,但有时它是未定义的)。页面渲染成功,通过 devtool 确认属性及其值存在。我想知道它背后的原因。会不会是Puppeteer在抓取时的问题? Cheerio 代码是同步的,所以我不认为 Cheerio 是问题所在。我从来没有得到错误:不能得到未定义的attr('profile'),所以这意味着有一个标题元素,但我得到错误:未定义的子字符串()。这就是为什么我在它前面加上一个条件来检查。

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 我添加了 html。你介意看看我吗?谢谢。我删除了内容,因为普通话似乎被屏蔽了。
  • 好的,在下面查看我的答案

标签: javascript web-scraping puppeteer cheerio


【解决方案1】:

按Ctrl-U,你会看到主要内容的源代码是空的。该网站可能由 React、Vue 或其他 Javascript 库进行渲染。所以你需要等待元素出现。

但是,如果我检查Developer Tools > Network tab > XHR Filter 中的网站,重新加载页面,你会看到他们调用的 API 来获取这些元数据,如地址、个人资料等......你可能不会需要抓取html。

【讨论】:

  • 这就是使用 puppeteer 抓取客户端渲染网站的意义所在。看来我没有访问这些 API 的权限。
【解决方案2】:

那个链接上的那个有个人资料和地址属性,所以不会在那里发生。

如果缺少该属性,您将得到未定义,例如 $(div).attr('foo')

对于节点 14+,您可以使用可选链接?运营商以避免这些问题:

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

【讨论】:

  • 这就是让我好奇的地方。有时我会得到数据,但有时我不会得到完全相同的页面。感谢分享新语法
猜你喜欢
  • 2018-11-14
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2019-04-26
相关资源
最近更新 更多