使用 pyodide 从 URL 下载文件?

Download files from URL with pyodide?

提问人:ssp24 提问时间:11/10/2023 更新时间:11/10/2023 访问量:27

问:

我正在尝试将 python 脚本转换为使用 pyodide 运行,但我无法从 url 下载文件,或者可能对我来说,或者确切地说,我无法获取或访问我想要下载的 acutal 对象(pdf 或纯文本,两者目前都不适合我)。

我尝试的代码如下所示:

url = 'https://d-nb.info/1205215212/04/text'

res = await pyfetch(url, mode="no-cors")
print(res.text)

pyfetch 返回一个 fetch 响应对象,但是当我尝试实际获取带有 .text 的文本时,我得到了以下信息:<bound method FetchResponse.text of <pyodide.http.FetchResponse object at 0x28fa8a0>>

我试图找出它的含义,但我没有成功。同样的方法确实适用于 API 请求,所以我不确定为什么它在这里不起作用。也许是模式,但如果我不添加 mode=“no-cors”,我总是会出现网络错误。

我尝试的另一种方法是:

from pyodide.http import open_url

url_contents = open_url(url)

url_contents.read()
print(url_contents)

返回 IO。StringIO 对象,但我也不确定如何从那里继续访问实际文本?更糟糕的是,我也想从这样的网址下载 PDF。任何帮助将不胜感激。 (我通常使用 requests 和 wget 执行此操作,这工作正常,但不幸的是两者都不适用于 pyodide,这需要这样做,以便我可以在 jupyter-lite 环境中运行它)。

python download fetch pyodide

评论


答:

0赞 ma9 11/10/2023 #1

该问题是由于同源策略和安全限制造成的。当您使用 mode=“no-cors” 时,您实际上是在发出跨域请求,而无法访问 JavaScript 中的响应内容,这可能是您无法使用 .text 检索文本的原因。

要解决此问题,您可以使用 open_url 函数,但您需要从 io 中读取内容。StringIO 对象 correctly.to 下载 PDF,应使用适当的方法将内容保存到文件中。 下面是一个示例:

from pyodide.http import open_url
import io
import urllib.request

url = 'https://d-nb.info/1205215212/04/text'

# Open the URL
url_contents = open_url(url)

if url_contents:
    if url_contents.info().get_content_type() == "text/plain":
        # If the content is plain text, read and print it
        text_content = url_contents.read()
        print(text_content)
    elif url_contents.info().get_content_type() == "application/pdf":
        # If the content is a PDF, save it to a file
        with open('downloaded.pdf', 'wb') as pdf_file:
            pdf_file.write(url_contents.read())

# Close the URL
url_contents.close()

评论

0赞 ssp24 11/10/2023
谢谢你的解释,这是有道理的!但是,尝试您的代码时,我现在收到一个属性错误“_io。StringIO' 对象没有属性 'info'”。我还尝试简单地读取url_contents对象,而不先检查它是否是文本,但它似乎几乎是空的(当我阅读然后打印它时,它只是一行空行。
0赞 ma9 11/10/2023
编辑行 if url_contents.info().get_content_type() == “text/plain”: to if url_contents.headers.get('Content-Type') == “text/plain”:
0赞 ssp24 11/10/2023
感谢您的回复 - 不幸的是,这仍然会产生错误:“_io。StringIO 对象没有属性“headers”。但是,由于跳过 if 条件并立即使用 .read() 读取 url_contents 变量只会返回一个空字符串,因此我认为问题实际上是无法实际从 url 中获取内容。open_url(url) 确实创建了一个对象,但它似乎完全是空的,这也可以解释为什么我无法访问它的内容 - 似乎根本没有。任何想法为什么会失败?
0赞 ma9 11/13/2023
您可以尝试直接使用 fetch 函数而不是 open_url
0赞 ma9 11/13/2023
from js import fetch url = 'd-nb.info/1205215212/04/text' async def fetch_url(url): response = await fetch(url, {'mode': 'no-cors'}) return await response.text() result = await fetch_url(url) print(result)