Requests: تدفق الردود بصيغة gzip

تم إنشاؤها على ٣١ يوليو ٢٠١٤  ·  10تعليقات  ·  مصدر: psf/requests

أحتاج إلى معالجة استجابات XML الكبيرة كتدفق. يمكن أن يصل حجم الاستجابات غير المضغوطة إلى مئات الميجابايت ، لذا فإن تحميلها بالكامل في الذاكرة قبل تسليمها إلى المحلل اللغوي XML ليس خيارًا.

أنا أستخدم lxml للتحليل وقد قمت فقط بتسليم response.raw إلى الوظيفة iterparse() ، كما هو موضح في مكان ما في مستندات الطلبات. هذا يعمل بشكل جيد للردود غير المضغوطة.

لسوء الحظ ، فإن واجهة برمجة التطبيقات التي أتصل بها ليست جيدة بشكل خاص. لذلك سيعود أحيانًا Content-Encoding: gzip حتى لو طلبت صراحةً بيانات غير مضغوطة. أيضًا ، نسبة الضغط على ملفات XML المكررة والمطولة هذه جيدة حقًا (10x +) ، لذلك أود حقًا الاستفادة من الاستجابات المضغوطة.

هل هذا ممكن مع الطلبات؟ لم أتمكن من العثور عليه في الوثائق. عند البحث بشكل أعمق في urllib3 ، يبدو أن أسلوب HTTPResponse.read () الخاص به يدعم معلمة decode_content . إذا لم يتم التعيين ، فسيعود urllib3 إلى ما تم تعيينه في المنشئ. عندما تستدعي الطلبات المُنشئ في request.adapters.HTTPAdapter.send () ، فإنه يعين صراحةً decode_content إلى False.

هل هناك سبب لماذا تطلب ذلك؟

الغريب أن iter_content() يعين decode_content=True أثناء القراءة. لماذا هنا؟ كل شيء يبدو تعسفيا بعض الشيء. لا أفهم حقًا الدافع للقيام بذلك بطريقة ما هنا وطريقة أخرى هناك.
أنا شخصياً لا يمكنني استخدام iter_content() بالطبع لأنني بحاجة إلى كائن يشبه الملف لـ lxml.

لقد كتبت سابقًا كائنًا يشبه الملف الخاص بي يمكنني ربطه بين الطلبات و lxml ، ولكن بالطبع التخزين المؤقت صعب وأشعر أن الأشخاص الأكثر ذكاءً مني قد كتبوا هذا من قبل ، لذلك أفضل ألا أضطر إلى إنشاء ملف خاص بي .

ما نصيحتك لكيفية التعامل مع هذا؟ هل يجب تغيير الطلبات إلى الإعداد الافتراضي لإعداد decode_content=True في urllib3؟

Contributor Friendly Documentation Planned

التعليق الأكثر فائدة

لقد فعلت هذا في الماضي

r = requests.get('url', stream=True)
r.raw.decode_content = True
...

ال 10 كومينتر

لا ، لا ينبغي أن يتم تعيين ذلك بشكل افتراضي لمجموعة متنوعة من الأسباب. ما يجب عليك فعله هو استخدام functools.partial لاستبدال طريقة read في الاستجابة (أو لفها بطريقة أخرى فقط) بحيث تفعل شيئًا مثل:

response.raw.read = functools.partial(response.raw.read, decode_content=True)

ثم قم بتمرير response.raw إلى المحلل اللغوي الخاص بك.

@ sigmavirus24 شكرًا ، هذا بالتأكيد حل أنيق للمشكلة التي أشرت إليها أعلاه!

أوصي بإضافة ذلك إلى وثائق الطلبات ، على سبيل المثال في الأسئلة الشائعة: http://docs.python-requests.org/en/latest/community/faq/#encoded -data
في الوقت الحالي ، العبارة "تؤدي الطلبات إلى إلغاء ضغط الردود المشفرة تلقائيًا" غير صحيحة لحالة stream=True ويمكن أن تؤدي إلى مفاجآت.

بالنسبة لمشكلتي ، كما قرأت عن

لكن هذا لم يعد مشكلة للطلبات.

كما تشعر في هذا يمكن أن يغلق؟

@ sigmavirus24 أعتقد أنه يجب توثيقه ، لأن التوثيق الحالي غير صحيح.

لكن إذا كنت لا توافق على ذلك ، نعم ، أغلق!

يمكن أن تكون الوثائق أكثر وضوحا. بالنسبة لي (وهذا تمامًا لأنني مطور أساسي) ، تتحدث الفقرة الأولى إلى 90٪ من المستخدمين الذين لن يلمسوا الاستجابة الأولية أبدًا ، بينما تناقض الفقرة الثانية الأولى في قولها "ولكن إذا كنت بحاجة إلى الوصول إلى البيانات الخام ، فهي متوفرة لك ". كما قلت ، هذا واضح بالنسبة لي ، لكن يمكنني أن أرى كيف يمكن توضيح ذلك. سأعمل على ذلك الليلة.

بالنسبة لي ، فإنني كنت سأفسر "البيانات الأولية" على أنها "حمولة خام" ، أي تيار غير مضغوط. أنا فقط يجب أن أقرأها في أي أجزاء أحتاجها. على عكس .content ، وهو عبارة عن blob غير مضغوط (أيضًا الحمولة ، ولكن في شكل مختلف).

يبدو إلغاء الضغط الفعلي وكأنه مصدر قلق لمكتبة HTTP بالنسبة لي - تفاصيل تنفيذ HTTP إذا أردت ، والتي أتوقع أن يتم تجريدها بعيدًا. سواء قرأت الحمولة من الطلبات كتدفق أو ككعب بيانات تم جلبه مسبقًا ، فلن يحدث فرقًا. في كلتا الحالتين ، ستلخص الطلبات "ضغط" تفاصيل التنفيذ.

(كان هذا الافتراض أيضًا في صميم طلبي الأصلي بالتخلف من decode_content إلى True . بالطبع الآن بعد أن رأيت ما هو هذا التجريد المتسرب ، لم أعد أقترح ذلك.)

لكن نعم ، أوافق تمامًا على أن 99٪ من المستخدمين لن يتأثروا أبدًا بهذه التفاصيل.

لا تتردد في إغلاق هذه القضية.

هذا يؤدي في الواقع إلى شيء ما كان يدور في رأسي لفترة ولم أقترحه بعد لأنه سيكون تغييرًا مهمًا في واجهة برمجة التطبيقات.

لا أحب حقيقة أننا نقترح على الأشخاص استخدام r.raw لأنه كائن لا نوثقه وهو كائن مقدم من urllib3 (والذي زعمنا في الماضي أنه المزيد من تفاصيل التنفيذ). مع وضع ذلك في الاعتبار ، كنت أتلاعب بفكرة توفير طرق لكائن Response والذي يكون وكيلًا فقط لطرق urllib3 ( read سيكون وكيلًا لـ raw.read ، إلخ.). يمنحنا هذا مرونة إضافية حول urllib3 ويسمح لنا بالتعامل (نيابة عن المستخدمين) مع تغيير واجهة برمجة التطبيقات urllib3 (والذي لم يكن يمثل مشكلة من الناحية التاريخية تقريبًا ، لذلك لا توجد أي مشكلة الاستعجال في ذلك).

مع ذلك ، لدينا بالفعل طرق كافية على كائن Response في رأيي وتنمية API الخاصة بنا ليست مثالية. أفضل واجهة برمجة تطبيقات هي واجهة برمجة التطبيقات التي لم يتبق منها أي شيء لإزالته. لذلك أنا باستمرار على الحياد بشأن هذا.


كان هذا الافتراض أيضًا في صميم طلبي الأصلي الخاص بـ decode_content الافتراضي إلى True. بالطبع الآن بعد أن رأيت ما هو هذا التجريد المتسرب ، لم أعد أقترح ذلك.

بالنسبة للآخرين الذين يجدون هذا وقد لا يكونون متأكدين من سبب صحة ذلك ، اسمحوا لي أن أشرح ذلك.

يوجد العديد من مستخدمي الطلبات الذين يقومون بإيقاف تشغيل إلغاء الضغط التلقائي للتحقق من طول الاستجابة ، أو للقيام بأشياء مهمة أخرى معها. أحد المستهلكين من النوع السابق هو OpenStack. يقوم العديد من عملاء OpenStack بالتحقق من صحة رأس Content-Length المرسل إلى العميل والطول الفعلي للجسم المستلم. بالنسبة لهم ، يعتبر التعامل مع تخفيف الضغط مقايضة عادلة للتأكد من تلقيهم استجابة صحيحة والتعامل معها.

مستهلك آخر هو Betamax (أو في الحقيقة أي أداة (تعيد) بناء كائنات الاستجابة) لأنه عندما يتعامل مع العملية الكاملة لتقديم استجابة صحيحة تمامًا ، فإنه يحتاج إلى أن يكون المحتوى بتنسيق مضغوط.

أنا متأكد من أن هناك آخرين لا أعرفهمLukasa ولا أعرف عن ذلك يعتمدون أيضًا بشكل كبير على هذا السلوك.

واجهت نفس المشكلة اليوم ، وانتهى الأمر إلى افتراض نفس الافتراض حيث لا توجد طريقة أخرى لدفق الردود في الوقت الحالي.

بدلاً من عدة طرق جديدة في الاستجابة ، لماذا لا توجد سمة جديدة واحدة ، مثل response.stream والتي ستلعب نفس دور الوكيل لـ .raw ؟ سيعكس أيضًا بشكل جيد الإعداد / المعلمة stream=True ، ولن يؤثر على المستخدمين الذين يحتاجون إلى السلوك الحالي .raw .

لقد فعلت هذا في الماضي

r = requests.get('url', stream=True)
r.raw.decode_content = True
...

لاحظ أن الحل البديل بواسطة @ sigmavirus24 يكسر دلالات طريقة tell ، والتي ستعيد إزاحات غير صحيحة.

واجهت هذا عند دفق رد كتحميل قابل للاستئناف في Google Cloud Storage API ، والذي يستخدم tell() لمعرفة عدد البايتات التي تمت قراءتها للتو ( هنا ).

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات