كيفية تنزيل ملف عبر HTTP مع إذن في Python 3.0، يعمل حول الأخطاء؟
-
23-08-2019 - |
سؤال
لدي برنامج نصي أود متابعة استخدامه، ولكن يبدو أنه يجب علي إيجاد بعض الحلول لعلة في Python 3، أو الرجوع إلى 2.6، وبالتالي الحاجة إلى خفض البرامج النصية الأخرى أيضا ...
نأمل أن يكون شخص ما هنا بالفعل من العثور على حل
المشكلة هي أنه نظرا للتغييرات الجديدة في Python 3.0 فيما يتعلق بايتات وسلاسل، لا يتم اختبار كل رمز المكتبة على ما يبدو.
لدي برنامج نصي يقوم بتنزيل صفحة من خادم ويب. مرت هذا البرنامج النصي اسم مستخدم وكلمة مرور كجزء من عنوان URL في بيثون 2.6، ولكن في بيثون 3.0، هذا لا يعمل بعد الآن.
على سبيل المثال، هذا:
import urllib.request;
url = "http://username:password@server/file";
urllib.request.urlretrieve(url, "temp.dat");
فشل مع هذا الاستثناء:
Traceback (most recent call last):
File "C:\Temp\test.py", line 5, in <module>
urllib.request.urlretrieve(url, "test.html");
File "C:\Python30\lib\urllib\request.py", line 134, in urlretrieve
return _urlopener.retrieve(url, filename, reporthook, data)
File "C:\Python30\lib\urllib\request.py", line 1476, in retrieve
fp = self.open(url, data)
File "C:\Python30\lib\urllib\request.py", line 1444, in open
return getattr(self, name)(url)
File "C:\Python30\lib\urllib\request.py", line 1618, in open_http
return self._open_generic_http(http.client.HTTPConnection, url, data)
File "C:\Python30\lib\urllib\request.py", line 1576, in _open_generic_http
auth = base64.b64encode(user_passwd).strip()
File "C:\Python30\lib\base64.py", line 56, in b64encode
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
TypeError: expected bytes, not str
على ما يبدو، يحتاج Base64-Encoding الآن بايتات، وتخرج سلسلة، وبالتالي Urlretrieve (أو بعض الكود الموجود به) والتي تقوم ببناء سلسلة من اسم المستخدم: كلمة المرور، وتحاول Base64 - تشفير هذا للحصول على إذن بسيط، يفشل.
إذا حاولت بدلا من ذلك استخدام Urlopen، مثل هذا:
import urllib.request;
url = "http://username:password@server/file";
f = urllib.request.urlopen(url);
contents = f.read();
ثم فشل مع هذا الاستثناء:
Traceback (most recent call last):
File "C:\Temp\test.py", line 5, in <module>
f = urllib.request.urlopen(url);
File "C:\Python30\lib\urllib\request.py", line 122, in urlopen
return _opener.open(url, data, timeout)
File "C:\Python30\lib\urllib\request.py", line 359, in open
response = self._open(req, data)
File "C:\Python30\lib\urllib\request.py", line 377, in _open
'_open', req)
File "C:\Python30\lib\urllib\request.py", line 337, in _call_chain
result = func(*args)
File "C:\Python30\lib\urllib\request.py", line 1082, in http_open
return self.do_open(http.client.HTTPConnection, req)
File "C:\Python30\lib\urllib\request.py", line 1051, in do_open
h = http_class(host, timeout=req.timeout) # will parse host:port
File "C:\Python30\lib\http\client.py", line 620, in __init__
self._set_hostport(host, port)
File "C:\Python30\lib\http\client.py", line 632, in _set_hostport
raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
http.client.InvalidURL: nonnumeric port: 'password@server'
على ما يبدو تحليل URL في هذا "مكتبة استرجاع URL المقبل التالي" لا يعرف ما يجب القيام به مع اسم المستخدم وكلمات المرور في عنوان URL.
ما هي الخيارات الأخرى التي لدي؟
المحلول
مباشرة من مستندات PY3K: http://docs.python.org/dev/py3k/library/urllib.request.html#examples.
import urllib.request
# Create an OpenerDirector with support for Basic HTTP Authentication...
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
uri='https://mahler:8092/site-updates.py',
user='klem',
passwd='kadidd!ehopper')
opener = urllib.request.build_opener(auth_handler)
# ...and install it globally so it can be used with urlopen.
urllib.request.install_opener(opener)
urllib.request.urlopen('http://www.example.com/login.html')
نصائح أخرى
ستكون نصيحتي هي الحفاظ على فرع 2. * * كفرع الإنتاج الخاص بك حتى تتمكن من الحصول على 3.0 أشياء فرزها.
سأنتظر بعض الوقت قبل الانتقال إلى Python 3.0. يبدو أن هناك الكثير من الناس في عجلة اندفاع، لكنني أريد فقط أن كل شيء تم فرزه، واختيار لائق لمكتبات الطرف الثالث. قد يستغرق هذا عام، وقد يستغرق الأمر 18 شهرا، ولكن الضغط على "الترقية" منخفض حقا بالنسبة لي.