如何将 UTF-8 中的网络抓取图像链接编码为 ASCII 但仍有功能链接?

Posted

技术标签:

【中文标题】如何将 UTF-8 中的网络抓取图像链接编码为 ASCII 但仍有功能链接?【英文标题】:How to encode a webscraped image link in UTF-8 to ASCII but still have a functional link? 【发布时间】:2021-03-13 10:34:25 【问题描述】:

我正在尝试对图像的链接进行网络抓取,以便在我的 Kivy 应用程序中使用它。问题是图像地址中有波兰语符号(ę,ł,ó,ą),我收到此错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 36-37: ordinal not in range(128)

完整的错误回溯:

Traceback (most recent call last):
  File "F:\Kivy\lib\site-packages\kivy\loader.py", line 342, in _load_urllib
    fd = opener.open(request)
  File "c:\users\user\appdata\local\programs\python\python36\lib\urllib\request.py", line 526, in open
    response = self._open(req, data)
  File "c:\users\user\appdata\local\programs\python\python36\lib\urllib\request.py", line 544, in _open
    '_open', req)
  File "c:\users\user\appdata\local\programs\python\python36\lib\urllib\request.py", line 504, in _call_chain
    result = func(*args)
  File "c:\users\user\appdata\local\programs\python\python36\lib\urllib\request.py", line 1361, in https_open
    context=self._context, check_hostname=self._check_hostname)
  File "c:\users\user\appdata\local\programs\python\python36\lib\urllib\request.py", line 1318, in do_open
    encode_chunked=req.has_header('Transfer-encoding'))
  File "c:\users\user\appdata\local\programs\python\python36\lib\http\client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "c:\users\user\appdata\local\programs\python\python36\lib\http\client.py", line 1250, in _send_request
    self.putrequest(method, url, **skips)
  File "c:\users\user\appdata\local\programs\python\python36\lib\http\client.py", line 1117, in putrequest
    self._output(request.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode character '\u0142' in position 36: ordinal not in range(128)
[INFO   ] [GL          ] NPOT texture support is available
[INFO   ] [WindowSDL   ] exiting mainloop and closing.
[INFO   ] [Base        ] Leaving application in progress...

Process finished with exit code 0

这是一个例子,你可以明白我的意思。图片加载正常,没有错误,第二个输出UnicodeEncodeError并显示黑色。

from kivy.app import App
from kivy.lang import Builder

build_structure = """
Screen:
    BoxLayout:
        AsyncImage:
            # This doesnt load because it's in UTF-8 and outputs the error above 
            # but it doesn't break the app.

            source: app.link_to_image_bad
        AsyncImage:
            # This one does load
            source: app.link_to_image_good
"""


class ImageApp(App):
    # This link has Polish signs in it so it will give the UnicodeEncodeError
    link_to_image_bad = "https://nowa.1lo.gorzow.pl/wp-content/uploads/2020/11/Szkoła-do-hymnu.png"

    link_to_image_good = "https://nowa.1lo.gorzow.pl/wp-content/uploads/2020/11/Olimpiada-statystyczna.png"

    def build(self):
        return Builder.load_string(build_structure)


if __name__ == '__main__':
    ImageApp().run()

上面代码的输出:

有没有办法避免这个错误并且仍然有一个功能链接?

【问题讨论】:

不清楚代码的哪一部分试图将其重新编码为 ASCII,或者为什么。有什么理由不简单地将其保存在 Unicode 中吗?也许添加完整的回溯会很有用。 我上面的代码,没有部分尝试将其重新编码为 ASCII,因为我不知道该怎么做,这就是我问这个问题的原因。它不能保存在 UTF-8 中,因为它会给出错误 UnicodeEncodeError: 'ascii' codec can't encode characters in position 36-37: ordinal not in range(128) 您可以对链接进行 URL 编码,以便它们是纯 ASCII,但仍能被服务器正确解释。您必须进行一些试验,但可能假设他们使用 UTF-8 作为 URL 编码。 from urllib.parse import quote_plus; url = quote_plus(url) 很遗憾,当我尝试使用你的方法时,我仍然遇到同样的错误 【参考方案1】:

URL 应该已经是 ASCII 兼容的。 Internet 上的流量(又名 HTTP)是这样工作的:只有 ASCII URL(有附加限制)。浏览器现在倾向于取消转义 URL。 [我们在 URL 中部分看到的 %20 和其他 %xx 字符]。注意:现在我们有 UTF-8 编码,并且在顶部有一个 URL 转义。所以,你应该记住你有两层编码。

您应该转义 URL,请参阅URL quoting。我会使用quote()unquote()。在cmets上,我们看到了一个quote_plus(),但是那个也改变了空间,有用一段时间,但是会改变原始数据的意思。

编辑:

好的,我有问题。 kivy 处理 URLS 的方式似乎有些奇怪。 quote() 仅用于路径部分,不适用于 URL 的第一部分。

作为一个 hack(如果你有一个特定的端口,它就不起作用:它会在端口前面引用:):

url = 'https://nowa.1lo.gorzow.pl/wp-content/uploads/2020/11/Szkoła-do-hymnu.png'
url_split = url.split('//')
'//'.join([url_split[0], urllib.parse.quote(url_split[1]))

所以你得到了想要的:浏览器使用的'https://nowa.1lo.gorzow.pl/wp-content/uploads/2020/11/Szko%C5%82a-do-hymnu.png'

您可能希望将其包含在您自己的函数中(并可能检查是否有端口号,以将其排除在引用之外)。

但是等等,也许有人对 Kivy 有真正的解决方案。我从不使用完全限定路径(因此使用协议和域),所以对我来说基本的quote() 就足够了。

【讨论】:

我添加了对问题的完整追溯,也许这会有所帮助。 非常感谢您的回答,但您能否根据我的示例代码指定如何使用这些方法?我厌倦了使用link_to_image_bad = quote(link_to_image_bad),但我现在根本不加载图像,就好像链接死了一样。 我编辑了答案,添加了代码。我忘了那个引用也会引用https:// 中的:。所以现在我的回答很丑。

以上是关于如何将 UTF-8 中的网络抓取图像链接编码为 ASCII 但仍有功能链接?的主要内容,如果未能解决你的问题,请参考以下文章

转载python抓取网页时候,判断网页编码格式

Java中做网络抓取demo用的Jsoup进行url解析如果链接中带中文就会出现乱码

如何在 Python 中将字符串转换为 utf-8

如何通过目标c中的编码将pdf文件转换为图像

如何通过udp获取直播源代码

java爬虫一段话里的部分字符乱码解决