从前端进行Web抓取(react和express连接)
当尝试从前端进行Web爬取时,往往会遇到CORS错误…
虽然有时能够通过对方的设置来避免,但仅依靠前端是无法解决的…
因此,我们尝试使用express简单地创建一个后端服务器来解决这个问题…
我们使用jsdom来进行爬取操作…
在示例中,我们随机获取了Yahoo新闻的图片…
如果您知道如何在前端解决CORS错误,请告诉我一种方法!
执行环境 (shí shī
-
- Windows11
-
- node (v18.17.1) ※インストール済
-
- react@18.2.0
- express@4.18.2
步骤
创建和移动react项目 (create-react-app)
使用create-react-app工具创建项目
项目名称任意!
- プロジェクト作成
npx create-react-app project-name
- プロジェクト移動
cd project-name
安装(后端服务器)
除了安装express之外,还安装了其他可以方便开发等的东西:
– nodemon:用于在启动后自动重新加载后端(express)代码。
– npm-run-all:用于同时启动前端(react)和后端(express)。
– pino:用于输出express的日志。
- express
npm i express
- 起動時反映・同時実行・ログ出力
npm i nodemon npm-run-all express-pino-logger pino-colada
安装jsdom(网络爬取)
安装jsdom以进行Web爬取。
npm i jsdom
创建后端服务器(express框架)
可以在任何地方创建执行模块都可以。
在这里,我们可以在项目的根目录下创建一个名为server的文件夹,然后在该文件夹下创建名为server.js的模块。
-
- 在项目的根目录下创建一个名为”server”的文件夹。
在”server”文件夹的根目录下创建一个名为”server.js”的文件。
server.js
// 导入库
const express = require(‘express’);
const pino = require(‘express-pino-logger’);
const { JSDOM } = require(‘jsdom’);
// 创建express应用
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(pino());
// 返回简单的JSON API
app.get(‘/api/sample1’, async (req, res) => {
res.setHeader(‘Content-Type’, ‘application/json’);
res.send(JSON.stringify({ sample: ‘你好,世界!’ }));
});
// 简单地进行网页抓取并返回JSON API
app.get(‘/api/sample2’, async (req, res) => {
// 使用fetch获取网页并生成DOM
const url = ‘https://news.yahoo.co.jp/’;
const urlRes = await fetch(url);
const urlHtml = await urlRes.text();
const dom = new JSDOM(urlHtml);
// 使用querySelector等方法获取所需信息
const imgSrcs = […dom.window.document.querySelectorAll(‘section img’)].map(
(img) => img.src
);
res.setHeader(‘Content-Type’, ‘application/json’);
res.send(JSON.stringify({ sample: imgSrcs }));
});
// 启动服务器
app.listen(3001, () =>
console.log(‘Express服务器正在localhost:3001上运行’)
);
对服务器进行代理设置
在package.json文件中添加代理设置,可以在任意位置添加。
"proxy": "http://localhost:3001"
添加前端和后端的启动脚本
在package.json文件中添加后端(server.js)的启动脚本以及同时启动前后端的脚本。
npm run server : バックエンド起動するときのコマンド
npm run start-all : フロント・バックエンド同時起動するときのコマンド
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
- "eject": "react-scripts eject"
+ "eject": "react-scripts eject",
+ "server": "nodemon server/server.js | pino-colada",
+ "start-all": "run-p server start"
},
用React前端执行API的简易示例
App.js文件中包含了执行以下后端API的示例代码
可以完全替换原有的代码。
-
- /api/sample1 : 簡易な JSON を返すAPI
- /api/sample2 : 簡易にWebスクレイピングした値を設定した JSON を返すAPI
import { useState } from 'react';
function App() {
const [sample1, setSample1] = useState('');
const [sample2, setSample2] = useState('');
// api/sample1 実行して sample1 に設定する処理
const getApiSample1 = async () => {
const json = await (await fetch('/api/sample1')).json();
setSample1(json.sample);
};
// api/sample2 実行して sample2 に設定する処理
const getApiSample2 = async () => {
const json = await (await fetch('/api/sample2')).json();
const imgs = json.sample.map((src, i) => {
return (
<>
<img src={src} alt={i}></img>
</>
);
});
setSample2(imgs);
};
return (
<>
<button onClick={getApiSample1}>get api sample1</button>
<p>{sample1}</p>
<button onClick={getApiSample2}>get api sample2</button>
<p>{sample2}</p>
</>
);
}
export default App;
确认执行
同时运行前端和后端后,在浏览器上会显示以下画面。如果画面没有显示出来,请在浏览器中访问 htttp://localhost:3000。
- 実行コマンド
npm run start-all
如果在执行React时出现错误
我进行开发时,出现了以下错误,原因尚不明确。可能从一开始这个方法就更稳定。在 React 中,也可以使用以下方式来介绍:
https://create-react-app.dev/docs/proxying-api-requests-in-development/
Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.allowedHosts[0] should be a non-empty string.
安装 http-proxy-middleware
npm i http-proxy-middleware
从package.json中删除代理设置
- "proxy": "http://localhost:3001"
创建 setupProxy.js
在src文件夹的直接下方创建一个名为setupProxy.js的文件。
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = (app) => {
app.use(
'/api/*',
createProxyMiddleware({
target: 'http://localhost:3001',
changeOrigin: true,
})
);
};
确认执行
只要执行方法与以往相同,并且能够无误地执行,就可以了。
npm run start-all