商品数据分析与可视化之 项目错误记录(五)

项目更多开发细节参见:


1、执行 pipenv install xxx 命令安装包时报错

问题描述:

创建完虚拟环境后,执行 pipenv install flask 后出现报错。

报错如下:

RuntimeError: Failed to lock Pipfile.lock!

期间通过上网查找相关资料,尝试以下方式解决,均无效:

(1) 尝试修改 Pipfile 文件中的 url

[[source]]
url = "https://pypi.tuna.tsinghua.edu.cn/simple/"
verify_ssl = true
name = "tsinghua"

(2) 尝试在安装时添加国内镜像源:

pipenv install flask -i http://mirrors.aliyun.com/pypi/simple/

(3) 尝试在安装前删除 Pipfile.lock 文件。

结论:
初步推测问题为网络问题,可能需要借助代理或VPN来下载。

解决方案(待优化): 借助代理后成功下载依赖包。


2、执行 flask run 命令后报错

问题描述:

将文件名从 app.py 修改为 hello.py 后无法启动内置服务器。

报错如下:

Error: Could not locate a Flask application.You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.

报错原因:

Flask 内部存在自动探测程序实例,会根据环境变量FLASK_APP 对应的值寻找对应的文件名(默认为 app)。

因为修改了文件名,所以环境变量 FLASK_APP 对应的值也得一并修改。

解决方案:

(1) 方法一:手动设置环境变量

set FLASK_APP=hello

执行 flask run 命令后可成功启动内置服务器:

启动内置服务器

存在的问题: 每次打开项目都得设置该环境变量,且在 vscode 中无法成功设置。

(2) 方法二:借助 python-dotenv 设置环境变量 (推荐)

python-dotenv: Flask的自动发现程序实例机制如果发现安装了 python-dotenv ,则会在使用 flask run 或其他命令时自动从 .flaskenv 文件和 .env 文件中加载环境变量。

.flaskenv 文件(手动创建):用来存储和Flask相关的公开环境变量。
.env 文件(手动创建):用来存储包含敏感信息的环境变量。

当安装了python-dotenv时,Flask在加载环境变量的优先级是:手动设置的环境变量 > .env中设置的环境变量 > .flaskenv设置的环境变量

① 安装 python-dotenv :

pipenv install python-dotenv

② 在项目根目录下创建一个 .flaskenv 文件,文件内容如下:
FLASK_APP = hello

③ 现在重新执行 flask run 命令即可启动服务


3、Vue项目打包部署到服务器出现报错 net::ERR_ABORTED 404 (NOT FOUND)

问题描述:

vue项目执行打包命令 yarn run build 将项目打包后,生成 dist 文件夹,将该文件夹中的文件移动至 flask项目中的 static 文件夹中,并添加相应加载代码启动服务后访问 http://localhost:5000 出现报错。

flask项目中的 app.py 文件内容如下:

from flask import Flask,render_template

app = Flask(__name__,template_folder="static")

@app.route('/')
def index():
    return render_template('index.html')

浏览器报错截图:

浏览器报错截图

报错原因:

对应资源路径不完整导致的报错,经测试发现只需在 static/index.html 文件中在相应资源的路径前添加 static 即可拼接成完整路径。虽说此时访问 http://localhost:5000 已经不会出现以上报错,已经可以加载出基本框架,但文件中的图片,字体图标等资源的路径依然不完整,相应资源也无法成功加载,所以使用手动修改路径的方式并不合适。

手动修改路径:

<link rel="icon" href="static/favicon.ico">
<script defer="defer" src="static/js/chunk-vendors.b8da2c66.js"></script>
<script defer="defer" src="static/js/app.fbf03e7f.js"></script>
<link href="static/css/app.089e31f9.css" rel="stylesheet">

解决方案:

修改vue项目中的 vue.config.js 文件,并添加以下代码,重新打包项目,并将相应资源移动至 flask项目的 static 文件夹中即可。

module.exports = defineConfig({
    // 检测当前环境 如果是生产环境,则追加 static
    publicPath: process.env.NODE_ENV == "production" ? "static" : "/",
})

参考链接(转载):https://blog.csdn.net/qq_41115965/article/details/102678246

4、img标签中的图片无法正常显示

问题描述:

图片链接可以正常访问,但是写入img标签的src后无法正常显示。

浏览器控制台报错如下:

GET https://qny.smzdm.com/202311/16/65560e0d237903818.jpg_d200.jpg 403

报错原因:

原因未知,推测可能是目标网站设置的安全措施,以往使用其他网站的图片链接时并未出现该问题。

参考链接(转载):https://imququ.com/post/referrer-policy.html

解决方案:

public 文件夹中的 index.html 文件的 <head></head> 标签内写入如下内容:

<!DOCTYPE html>
<html lang="">
  <head>
    ...
    <meta name="referrer" content="no-referrer">
    ...
  </head>
  <body>
    ...
  </body>
</html>

经测试,图片可正常加载,但是不知为何,即便将以上语句注释,图片依然可以正常显示,甚至打开新项目不追加以上语句也可以显示图片。

参考链接(转载):https://blog.csdn.net/weixin_43869439/article/details/106621186

5、使用 vue-socket.io 出现跨域问题

项目环境:

前端:Vue2
后端:Flask

问题描述:

为了实现前后端的双向数据通信,我在前端安装了 vue-socket.io ,后端安装 flask_socketio

(1) 前端安装 vue-socket.io :(此处安装当前最新版本)

yarn add vue-socket.io@latest

(2) 后端安装 flask_socketio

pipenv install flask_socketio

安装后对应版本:

vue-socket.io:3.0.10

flask_socketio:5.3.6

前端组件内代码如下:

<template>
<button @click="startSpiderBtn">获取数据</button>
<div>{{ output }}</div>
</template>

<script>
export default {
    name: "SpiderGetData",
    data() {
        return {
            output: '',
        }
    },
    sockets: {
    },
    mounted() {
        this.sockets.subscribe('console_output', (msg) => {
            this.output += '\n' + msg.data;
        })
    },
    methods: {
        startSpiderBtn() {
            this.$socket.emit("start_spider","start");
        },
    }
}
</script>

前端 main.js 文件部分代码如下:

import Vue from 'vue'
import VueSocketIO from 'vue-socket.io'

Vue.use(new VueSocketIO({
    debug: true,
    connection: "http://localhost:5000",
}))

后端代码:

from flask import Flask,request
from flask_socketio import SocketIO

app = Flask(__name__)

socketio = SocketIO(app,cors_allowed_origins='*')

@socketio.on('start_spider')
def start_spider(msg):
    print(msg)
    socketio.emit("console_output",{"data": "test"})

if __name__ == "__main__":
    socketio.run(app,debug=True)

报错截图如下:

浏览器报错截图:

浏览器报错截图

后端报错截图:

后端报错截图

尝试解决:

期间通过上网查找各种资料,尝试以下方法解决,均无效

(1) 安装 flask_cors,进行后端的跨域配置

pipenv install flask_cors

更新后端代码,app.py 文件追加以下代码:

from flask_cors import CORS

CORS(app,cors_allowed_origins="*")  

(2) 前端修改 vue.config.js 配置文件

修改内容如下:

module.exports = defineConfig({
    devServer: {
        proxy: {
            '/socket.io': {
                target: 'http://localhost:5000',
                ws: true,
                changeOrigin: true
            },
            '/sockjs-node': {
                target: 'http://localhost:5000',
                ws: false,
                changeOrigin: true
            },
        }
    }
})

(3) 查看浏览器响应标头,如图所示,表明跨域相关的配置修改成功,但是控制台却依然报错

浏览器响应标头:

浏览器响应标头

报错原因:

虽说浏览器报错显示的问题为跨域的问题,但是期间通过各种方式进行相关的配置均无效,因为主要问题在 vue-socket.io 相关的依赖包与 flask_socketio 包中的 SocketIO 版本不兼容。

突破口在于后端的报错:

The client is using an unsupported version of the Socket.IO or Engine.IO protocols (further occurrences of this error will be logged with level INFO)

一开始以为是 EngineIO 版本太低的问题,企图去修改 node_modules/socket.io-client/package.json 中的 engine.io-client 版本,之后执行 yarn install,但遗憾的是此方法无效,最后无意间找到了网友分享的一篇博客才得知需升级 socket.io-client 包的版本(参考链接详见底部)。

安装 vue-socket.io 时对应依赖包的版本,如图所知,socket.io-client 包的版本太低,需升级至3.x.x版本才可兼容。

在这里插入图片描述

各版本兼容性:

各版本兼容性

各版本兼容性参见:https://flask-socketio.readthedocs.io/en/latest/intro.html#version-compatibility

解决方案:

方法一:

更新 socket.io-client

yarn add socket.io-client@3

执行以上命令下载3.x.x版本,经实践发现更新完 socket.io-client 包版本后,engine.io-client 包版本自动升级到了4.x.x版本。

方法二:

修改 node_modules/socket.io-client/package.json 中的 socket.io-client 版本,如图所示:

解决方案二

之后执行命令更新:

yarn install

在升级完依赖包后,修改前端 main.js 文件中的内容如下:

import Vue from 'vue'
import VueSocketIO from 'vue-socket.io'
import SocketIO from 'socket.io-client'

Vue.use(new VueSocketIO({
    debug: true,
    connection: SocketIO("http://localhost:5000"),
}))

-------------

后端 app.py 完整代码如下:

from flask import Flask,request 
from flask_socketio import SocketIO
from flask_cors import CORS

app = Flask(__name__)
CORS(app,cors_allowed_origins="*")  
socketio = SocketIO(app,cors_allowed_origins='*')

@socketio.on('start_spider')
def start_spider(msg):
    print(msg)
    socketio.emit("console_output",{"data": "test"})

if __name__ == "__main__":
    socketio.run(app,debug=True)

再次感谢网友分享的解决方法,详情参考链接(转载):https://www.cnblogs.com/code1992/p/14336803.html

6、使用 pipenv 创建的虚拟环境下调用 scrapy 创建的爬虫项目出现 python 环境不同导致的报错

项目环境:

前端:Vue2
后端:Flask(运行在 pipenv 创建的 python 虚拟环境下)

项目结构:

项目结构

项目背景:

我使用 scrapy 命令提前创建了两个爬虫项目,并复制到 flask 项目中,期望通过 flask 项目调用这两个爬虫项目。

pipenv 创建的虚拟环境下,我安装了 flaskpandas 等包。

在 scrapy 创建的项目中,我使用的主要的包有 scrapypandas 等。

问题描述:

在 flask 项目中调用 Scrapy 创建的爬虫项目时,出现某个包不存在的报错,但该包明明已经安装在虚拟环境中。

报错如下:

ModuleNotFoundError: No module named 'pandas'

尝试解决:

我感到疑惑,明明已经在虚拟环境中安装了 pandas ,并且已经配置了 flask 项目使用的 python 环境为 pipenv 创建的虚拟环境。

尝试进入 scrapy_basic 项目查看所运行的环境:

查看所运行的环境

如图可知,程序已经处于虚拟环境下。

后续再次执行还是报错,但是留意到了报错的文件路径居然是全局环境下的 python,并非虚拟环境下的 python。

File "c:\users\asus\appdata\local\programs\python\python39-32\lib\importlib\__init__.py",line 127,in import_module   
return _bootstrap._gcd_import(name[level:], package, level)

报错原因:

由于我是在全局环境下通过 scrapy 命令创建的项目,所以使用的是全局环境下的 python,但是全局环境下我并没有安装 pandas,所以才会报错。此时,只需要在全局环境下也安装 pandas ,即可解决,但是这并不是一个好方法,我希望 scrapy_basic 项目使用的也是 pipenv 创建的 python 虚拟环境,而不是全局的 python 环境。

解决方案:

现在的问题是怎么把 scrapy_basic 项目所使用的环境转为 pipenv 创建的 python 虚拟环境。

我在 pipenv 创建的 python 虚拟环境下安装 scrapypandas

pipenv install scrapy

pipenv install pandas

再次通过 flask 项目调用 scrapy_basic 项目爬取后发现,环境居然自动转为 pipenv 创建的 python 虚拟环境,推测可能是因为之前虚拟环境中没有安装 scrapy,所以自动向上查找了,并使用了全局环境下的 scrapy

不过又出现了新的报错:

ImportError: DLL load failed while importing _sqlite3: 找不到指定的模块。

通过上网查找资料,得知可在 D:\Anaconda\Library\bin 目录下复制一份 sqlite3.dll 文件至虚拟环境下 D:\桌面\GoodsDataAnalysis\GoodsFlask\PIPENV_VENV_IN_PROJECT\GoodsFlask-S_qAB8d7\Scripts 即可解决。

期间我尝试复制全局环境下的 sqlite3.dll 文件似乎无法解决,后复制 Anaconda 下的 sqlite3.dll 文件才最早解决。

参考链接+其他解决方案(转载):https://blog.csdn.net/sayWhat_sayHello/article/details/114464801

接着,又出现了新的报错(可能因为我在爬虫程序中将数据写入 excel 文件,所以才出现以下报错,程序其实已经可以正常爬取了):

ModuleNotFoundError: No module named 'openpyxl'

这个问题比较好处理,只需在虚拟环境下安装 openpyxl 即可解决:

pipenv install openpyxl

7、在 flask 项目中使用 axios 上传文件时出现的问题

项目环境:

前端:Vue2
后端:Flask

问题描述:

前端在使用 axios 上传文件时,服务端出现415报错。

前端代码如下:

<template>
    <div class="data_shape_tools_bar">
        <ul>
            <input type="file" ref="file_input" hidden @change="fileUploadData">
            <!-- 上传文件 -->
            <li @click="fileUpload">上传</li>
        </ul>
    </div>
</template>

<script>
import axios from 'axios';

export default {
    name: "DataShapeToolsBar",
    data() {
        return {
            uploadFiles: null,
        }
    },
    methods: {
        // 点击input框,弹出文件选择对话框
        fileUpload() {
            this.$refs.file_input.click();
        },
        // 获取文件信息
        fileUploadData(e) {
            this.uploadFiles = e.target.files[0];
        },
        // 点击按钮上传文件
        uploadFile() {
            let formData = new FormData();
            formData.append('file', this.uploadFiles);
            // 打印文件信息,检查是否添加成功
            console.log(formData.get('file'));

            axios.post('http://localhost:8080/api/fileUpload', formData,
                {
                    headers: {
                        'Content-Type': 'multipart/form-data'
                    },
                }
            ).then(
                response => {
                    console.log(response.data);
                },
                error => {
                    console.log(error);
                }
            )
        },
    }
}
</script>

后端代码如下:

from flask import Flask,request
from flask_cors import CORS

app = Flask(__name__)

CORS(app,cors_allowed_origins="*")

# 文件上传
@app.route('/api/fileUpload',methods=['POST'])

def file_upload():
    print(request.headers.get('Content-Type'))
    print(request.json)
    file = request.files.get('file')
    print(file)

    return '1'

报错截图:

报错截图

尝试解决:

上网查找资料得知该报错的主要原因是前端发送的资源的类型与后端所要求接收的资源类型不一致。

尝试修改 axios 请求中的 Content-Type

...
axios.post('http://localhost:8080/apifileUpload', formData,
    {
        headers: {
            // 'Content-Type': 'multipart/form-data'
            'Content-Type': 'application/json'
        },
    }
).then(...)

再次上传文件后发现,确实不报错了,但是上传的文件为空,后端根本没接收到。

后端控制台打印信息如下:

application/json
{'file': {}}
None

报错原因:

在多番尝试解决均无效的情况下,反复检查了前端代码,感觉并无任何问题,猜测问题可能出现在后端,注释掉其他代码后,只进行 return 语句的简单返回,发现并无报错,更加坚定了自己的看法,最终,发现了问题所在。

解决方案:

修改后端代码如下:

from flask import Flask,request
from flask_cors import CORS

app = Flask(__name__)

CORS(app,cors_allowed_origins="*")

# 文件上传
@app.route('/api/fileUpload',methods=['POST'])

def file_upload():
    print(request.headers.get('Content-Type'))

    # 注释或删除该打印语句!!!
    # print(request.json)

    file = request.files.get('file')
    print(file)

    return '1'

原来问题出在语句 print(request.json) ,推测可能这样写了之后,后端会去获取请求中的 json 类型的数据,而上传的文件并非 json 类型的数据,所有才导致报错。

还有一点,关于前端 axios 上传文件时是否需要添加 headers: {'Content-Type': 'multipart/form-data'} 的问题,经测试,可写可不写均可上传文件。

8、后端发送至前端的 json 数据变成 string 类型的数据

项目环境:

前端:Vue2
后端:Flask

问题描述:

我在前端通过 axios.post 上传文件至后端,希望后端读取该文件内的数据并对数据做适当的处理后再将其返回至前端,现在有一个 smzdm.xlsx 文件和 scrapy_smzdm.xlsx 两个文件。但让我感到不解的是,我上传文件 smzdm.xlsx 至后端,处理后可正常返回 json 类型的数据,但是 scrapy_smzdm.xlsx 返回的却是 string 类型的数据,明明两个数据的格式都是一致的,只是内容不一样。

前后端部分代码:

前端文件上传部分代码如下:

...

let formData = new FormData();
formData.append('file', this.uploadFiles);
// 打印文件信息
console.log(formData.get('file'));

axios.post('http://localhost:8080/api/fileUpload', formData).then(
    response => {
        // 查看响应的数据类型
        console.log(typeof response.data);
    },
    error => {
        console.log(error);
    }
)

后端代码如下:

# 文件上传
@app.route('/api/fileUpload',methods=['POST'])

def file_upload():
    file = request.files.get('file')
    # 读取上传的文件
    df = pd.read_excel(file)

    # 存储所有关于上传的文件的信息
    uploadFileInfoObj = {}

    # 将其转换为字典类型的数据
    upload_file_data_list = df.to_dict(orient='records')

    # df.to_dict 会将数据中的列表类型的数据转换成字符串类型的数据,
    # 故需使用 eval() 再做进一步处理,此处省略 ......

    uploadFileInfoObj["upload_file_data_list"] = upload_file_data_list
   
    return jsonify(uploadFileInfoObj)

文件对比:

smzdm.xlsx 文件上传后,后端响应的内容(数据类型符合预期,为 json 类型的数据):

后端响应的内容1

scrapy_smzdm.xlsx 文件上传后,后端响应的内容(数据类型为 string 类型,不符合预期):

后端响应的内容2

两个文件上传后,对应的文件信息及后端响应的数据类型:

文件信息

查看浏览器响应体中 Content-Type:application/json ,服务端返回的是 json 类型数据,应该是没错的才对:

查看浏览器标头

报错原因:

报错原因未知。两个文件的主要区别在于内容,其次是文件大小、名称,不清楚是什么因素影响的,但好在还有解决方案。

解决方案:

通过上网寻求解决方案得知,可使用 JSON.parse() 进行转换,但是在使用的过程中,可能因为响应的数据可能不是有效的 json 字符串,导致了报错:

报错截图

针对非有效的 json 字符串,最终使用 eval() 方法成功转换,前端代码如下:

axios.post('http://localhost:8080/api/fileUpload', formData).then(
    response => {
        console.log(typeof response.data);

        let response_data = response.data;
        if(typeof response_data == 'string') {
            // 通过该方法,成功转化数据
            response_data = eval("(" + response_data + ")");
        }
        console.log(response_data);
    },
    error => {
        console.log(error);
    }
)

参考链接(转载):https://www.cnblogs.com/xyyt/p/13896988.html

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值