通过 API 接收一个远程文件 URL,然后服务器从该 URL 下载文件,再将其转换为 PDF,并将前两页转换为图片,最终上传到 阿里云 OSS。这里不再是通过文件上传的方式,而是通过提交远程 URL 地址。
调整后的解决方案
我们将修改之前的 Flask API,让它接受 远程文件 URL 作为输入。
依赖库安装
首先,确保安装以下所需的依赖:
pip install flask requests pdf2image oss2 python-docx
sudo yum install libreoffice poppler-utils
完整示例代码
from flask import Flask, request, jsonify
import os
import shutil
import requests
import subprocess
from pdf2image import convert_from_path
import oss2
# Flask 应用实例
app = Flask(__name__)
UPLOAD_FOLDER = '/tmp'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# 阿里云 OSS 配置
ACCESS_KEY_ID = 'your_access_key_id'
ACCESS_KEY_SECRET = 'your_access_key_secret'
BUCKET_NAME = 'your_bucket_name'
ENDPOINT = 'your_endpoint'
bucket = oss2.Bucket(oss2.Auth(ACCESS_KEY_ID, ACCESS_KEY_SECRET), ENDPOINT, BUCKET_NAME)
# 允许上传的文件扩展名
ALLOWED_EXTENSIONS = {'pdf', 'docx', 'txt', 'pptx'}
def allowed_file(filename):
"""检查文件是否是允许的格式"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def download_file(url):
"""从远程 URL 下载文件"""
local_filename = os.path.join(UPLOAD_FOLDER, url.split("/")[-1])
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(local_filename, 'wb') as f:
f.write(response.content)
return local_filename
return None
def convert_to_pdf(input_file):
"""使用 LibreOffice 将文件转换为 PDF"""
output_file = os.path.splitext(input_file)[0] + '.pdf'
command = f'libreoffice --headless --convert-to pdf "{input_file}" --outdir {UPLOAD_FOLDER}'
subprocess.run(command, shell=True)
pdf_file = os.path.join(UPLOAD_FOLDER, os.path.basename(output_file))
if os.path.exists(pdf_file):
return pdf_file
return None
def pdf_to_images(pdf_path):
"""将 PDF 前两页转换为图片"""
images = convert_from_path(pdf_path, first_page=1, last_page=2)
image_paths = []
for i, image in enumerate(images):
image_path = os.path.join(UPLOAD_FOLDER, f'page_{i + 1}.png')
image.save(image_path, 'PNG')
image_paths.append(image_path)
return image_paths
def upload_to_oss(file_path):
"""上传文件到阿里云 OSS"""
filename = os.path.basename(file_path)
oss_path = f'uploads/{filename}'
bucket.put_object_from_file(oss_path, file_path)
return f'https://{BUCKET_NAME}.{ENDPOINT}/{oss_path}'
def cleanup_temp_files(*file_paths):
"""删除临时文件"""
for file_path in file_paths:
if os.path.exists(file_path):
os.remove(file_path)
@app.route('/upload', methods=['POST'])
def upload_file():
"""处理上传 URL 请求"""
file_url = request.form.get('url')
if not file_url:
return jsonify({'code': 1, 'message': '未提供 URL'}), 400
# 从 URL 下载文件
local_file = download_file(file_url)
if not local_file or not allowed_file(local_file):
return jsonify({'code': 1, 'message': '文件下载失败或文件类型不支持'}), 400
try:
# 1. 判断文件类型并转换为 PDF
if local_file.endswith('.pdf'):
pdf_file = local_file
else:
pdf_file = convert_to_pdf(local_file)
if not pdf_file:
return jsonify({'code': 1, 'message': '文件转换为 PDF 失败'}), 500
# 2. 转换 PDF 前两页为图片
image_paths = pdf_to_images(pdf_file)
# 3. 上传 PDF 和图片到 OSS
pdf_url = upload_to_oss(pdf_file)
image_urls = [upload_to_oss(img) for img in image_paths]
# 4. 返回结果
return jsonify({
'code': 0,
'data': {
'pdfurl': pdf_url,
'views': image_urls
}
})
finally:
# 5. 清理临时文件
cleanup_temp_files(local_file, pdf_file, *image_paths)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
代码说明
Flask 接口:
POST /upload
:接收一个包含远程 URL 的请求。- 检查文件是否可以从 URL 下载并保存到本地。
文件下载与处理:
- 从 URL 下载文件到服务器。
- 如果文件是非 PDF 格式,则使用
LibreOffice
将其转换为 PDF。 - 使用
pdf2image
将 PDF 的前两页转换为 PNG 图片。
阿里云 OSS 上传:
- 上传 PDF 和图片到 OSS,并返回 URL。
清理临时文件:
- 上传完成后,自动删除服务器上的临时文件。
使用示例
使用 curl
命令进行测试:
curl --request POST \
--url http://localhost:5000/upload \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'url=http://qiye.dev.udwz.cn/123.docx'
示例响应
{
"code": 0,
"data": {
"pdfurl": "https://your_bucket.your_endpoint/uploads/123.pdf",
"views": [
"https://your_bucket.your_endpoint/uploads/page_1.png",
"https://your_bucket.your_endpoint/uploads/page_2.png"
]
}
}
注意事项
- 确保替换阿里云 OSS 的配置信息(
ACCESS_KEY_ID
,ACCESS_KEY_SECRET
,BUCKET_NAME
,ENDPOINT
)。 - 确保
LibreOffice
和poppler-utils
已正确安装,以支持文档转换。 - 请确保服务器
/tmp
目录有写入权限。
{"code":0,"data":{"pdfurl":"https://orangerescue2022.oss-cn-hangzhou.aliyuncs.com/pdf/123-d60becd4-1de5-4ed0-9ec3-0b3972b781f2.pdf","views":["https://orangerescue2022.oss-cn-hangzhou.aliyuncs.com/pdf/9f09ceb9-8ff0-4ad2-9030-771dc0cd86fc.png","https://orangerescue2022.oss-cn-hangzhou.aliyuncs.com/pdf/a7cb30b9-fe72-4e44-949d-f6a7b5352052.png"]}}