繁体   English   中英

如何使用 get 请求的响应通过 aiohttp 上传文件?

[英]How can I upload files through aiohttp using response from get request?

首先,我正在为 WordPress REST API 编写一个异步包装器。我在 Bluehost 上托管了一个 Wordpress 网站。 我正在使用媒体(图像)上传端点。 我已成功上传图片,但我想进行 2 处更改。 第二个变化是我真正想要的,但出于好奇,我也想知道如何实施变化 1。 我会先提供代码,然后再提供一些细节。

工作代码

async def upload_local_pic2(self, local_url, date, title):
    url = f'{self.base_url}/wp-json/wp/v2/media'
    with aiohttp.MultipartWriter() as mpwriter:
      json = {'title': title, 'status':'publish'}
      mpwriter.append_json(json)
      with open(local_url, 'rb') as f:
        print(f)
        payload = mpwriter.append(f)
        async with self.session.post(url, data=payload) as response:
          x = await response.read()
          print(x)

变化 1

第一个变化是使用 aiofiles.open() 而不是仅仅使用 open() 上传,因为我希望处理大量文件。 以下代码不起作用。

async def upload_local_pic(self, local_url, date, title):
    url = f'{self.base_url}/wp-json/wp/v2/media'
    with aiohttp.MultipartWriter() as mpwriter:
      json = {'title': title, 'status':'publish'}
      mpwriter.append_json(json)
      async with aiofiles.open(local_url, 'rb') as f:
        print(f)
        payload = mpwriter.append(f)
        async with self.session.post(url, data=payload) as response:
          x = await response.read()
          print(x)

变2

我的另一个变化是我想再有一个function可以直接把文件上传到WordPress的服务器,不用本地下载。 所以我不想获取本地图片,而是想传入一张在线图片的url。 以下代码也不起作用。

async def upload_pic(self, image_url, date, title):
    url = f'{self.base_url}/wp-json/wp/v2/media'
    with aiohttp.MultipartWriter() as mpwriter:
      json = {'title':title, 'status':'publish'}
      mpwriter.append_json(json)
      async with self.session.get(image_url) as image_response:
        image_content = image_response.content
        print(image_content)
        payload = mpwriter.append(image_content)
        async with self.session.post(url, data = payload) as response:
          x = await response.read()
          print(x)

细节/调试

我试图弄清楚为什么每个都不起作用。 我认为关键是调用print(image_content)print(f)显示我输入到mpwriter.append的内容

在我只使用标准 Python open() function 的示例中,我显然传入了<_io.BufferedReader name='/redactedfilepath/index.jpeg'>

在带有 aiofile 的更改 1 示例中,我传入<aiofiles.threadpool.binary.AsyncBufferedReader object at 0x7fb803122250> Wordpress 将返回此 html:

b'<head><title>Not Acceptable.</title></head><body><h1>Not Acceptable.</h1><p>An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.</p></body></html>'

最后,在更改 2 中,我尝试将 get 请求传递给 url 给我,我得到了<StreamReader 292 bytes> WordPress 返回的响应与上面的 Mod Security 相同。

知道如何使这些示例起作用吗? 看起来它们都是某种类型的 io 阅读器,但我猜底层 aiohttp 代码对它们的处理方式不同。

此外,这并不重要, 但这是我传递给更改 2 示例的 url。

好的,所以我想出了两个变化。

对于尝试使用aiofiles读取文件时的第一个更改,我只需要读取整个文件而不是传入文件处理程序。 另外,我需要手动设置内容配置。

async def upload_local_pic(self, local_url, date, title):
    url = f'{self.base_url}/wp-json/wp/v2/media'
    with aiohttp.MultipartWriter() as mpwriter:
      json = {'status':'publish'}
      mpwriter.append_json(json)
      async with aiofiles.open(local_url, mode='rb') as f:
        contents = await f.read()
        payload = mpwriter.append(contents)
        payload.set_content_disposition('attachment', filename= title+'.jpg')
        async with self.session.post(url, data=payload) as response:
          x = await response.read()
          print(x)

对于第二个更改,它是一个类似的概念,只是直接从 URL 上传文件。 我需要先读取整个内容,而不是传入将读取内容的处理程序。 我还需要手动设置内容配置。

async def upload_pic(self, image_url, date, title):
    url = f'{self.base_url}/wp-json/wp/v2/media'
    with aiohttp.MultipartWriter() as mpwriter:
      json = {'status':'publish'}
      mpwriter.append_json(json)
      async with self.session.get(image_url) as image_response:
        image_content = await image_response.read()
        payload = mpwriter.append(image_content)
        payload.set_content_disposition('attachment', filename=title+'.jpg')
        async with self.session.post(url, data = payload) as response:
          x = await response.read()
          print(x)

我只会回答帖子的标题(而不是中间的问题)。

下面的代码应该给出一个简短的示例,说明如何将文件从 URL#1 上传到 URL#2(无需将文件下载到本地计算机,然后才进行上传)。

我在这里举两个例子:

  1. 将文件全部内容读入memory(不是下载)。 这在处理大文件时当然不太好......
  2. 以块的形式读取和发送文件(因此我们不会一次读取所有文件内容)。

示例 #1:一次读取所有文件内容并上传

import asyncio
import aiohttp 

async def http_upload_from_url(src, dst):
    async with aiohttp.ClientSession() as session:
        src_resp = await session.get(src)
        #print(src_resp)
        dst_resp = await session.post(dst, data=src_resp.content)
        #print(dst_resp)

try:
    asyncio.run(http_upload_from_url(SRC_URL, DST_URL))
except Exception as e:
    print(e)

示例 #2:以块的形式读取文件内容并上传

import asyncio
import aiohttp 

async def url_sender(url=None, chunk_size=65536):
    async with aiohttp.ClientSession() as session:
        resp = await session.get(url)
        #print(resp)
        async for chunk in resp.content.iter_chunked(chunk_size):
            #print(f"send chunk with size {len(chunk)}")
            yield chunk

async def chunked_http_upload_from_url(src, dst):
    async with aiohttp.ClientSession() as session:
        resp = await session.post(dst, data=url_sender(src))
        #print(resp)
        #print(await resp.text())

try:
    asyncio.run(chunked_http_upload_from_url(SRC_URL, DST_URL))
except Exception as e:
    print(e)

一些注意事项:

  • 您需要定义 SRC_URL 和 DST_URL。
  • 我只添加了用于调试的打印件(以防您没有收到 [200 OK] 响应)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM