React中useEffect请求数据导致Bing爬虫抓取内容为空如何解决
问题原因
该问题是客户端渲染(CSR)的固有特性导致的:你写的React代码会在用户/爬虫的浏览器端执行JS、发起接口请求、拿到数据后才会更新DOM填充内容。必应爬虫虽然支持部分JS执行,但如果接口请求耗时较长、或者爬虫没有等待异步逻辑执行完毕就抓取页面源码,就会拿到未填充内容的空标签。另外你提供的代码本身存在几个可修复的语法和逻辑问题。
现有代码问题修复
当前代码存在的问题:
export default const App语法错误,正确写法是先声明组件再导出- 根组件返回了多个并列节点,没有用Fragment包裹,会触发编译错误
useEffect没有传入依赖数组,每次组件渲染都会重新发起请求,存在无限执行的bug
修复后的基础客户端代码示例:
import { useState, useEffect, Fragment } from 'react' const App = () => { // 可以设置兜底默认值,就算JS未执行也有基础内容 const [data, setData] = useState("默认站点标题"); // 加空依赖数组,仅组件挂载时发起一次请求 useEffect(() => { server.get().then(res => { setData(res) }) }, []) return( <Fragment> <title>{data}</title> <h1>{data}</h1> </Fragment> ) } export default App
根治爬虫抓取问题的方案
- 方案1:改用服务端渲染(SSR)或静态站点生成(SSG)
这是最稳定的解决方案,推荐使用Next.js等框架实现:- 如果是内容固定的静态站点,用SSG在构建阶段就请求接口拿到数据,直接把内容渲染到静态HTML文件中,爬虫拿到的就是完整内容
- 如果是动态内容,用SSR在服务端完成接口请求和页面渲染,返回给爬虫的就是已经填充好内容的HTML
Next.js SSG示例代码:
// pages/index.js export async function getStaticProps() { // 构建阶段执行接口请求 const data = await server.get() return { props: { data } } } export default function Home({ data }) { return ( <> <title>{data}</title> <h1>{data}</h1> </> ) } - 方案2:接入预渲染服务
如果不想改动现有React CSR的架构,可以接入预渲染工具,检测到访问来源是爬虫时,返回提前渲染好的带内容的静态HTML,普通用户访问还是走正常的客户端渲染逻辑。 - 方案3:添加静态兜底内容
可以在入口HTML文件的title和h1位置提前写好默认内容,React渲染时会自动替换成动态请求的内容,就算爬虫没有执行JS,也能拿到基础的兜底内容。
内容的提问来源于stack exchange,提问作者John Sneijder
相关产品推荐
相关产品推荐

