从前端进行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的模块。

    1. 在项目的根目录下创建一个名为”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
image.png

如果在执行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
广告
将在 10 秒后关闭
bannerAds