مبادئ وتقنيات علم البيانات

الفصل السابع: تقنيات الويب

فهرس الفصل:


مقدمة

قبل ظهور الإنترنت، كان علماء البيانات يقومون بنقل الأقراص الصلبة بينهم يدوياً لمشاركة البيانات. الآن، يمكننا بسهوله البحث واستيراد البيانات من أجهزة الكمبيوتر حول العالم.

على الرغم من أننا نستخدم الإنترنت لتحميل ومشاركة ملفات البيانات، مواقع الإنترنت أيضا تحتوي على عدد كبير من المعلومات محفوظة كنصوص، صور أو فيديو. بتعلم تقنيات الويب، يمكننا أن نستخدمها كمصدر للبيانات. في هذا الفصل، سنتعرف على HTTP، الطريقة الأساسية للتواصل في الويب، و XML/HTML، التنسيقات الأساسية للملفات في مواقع الإنترنت.

HTTP

ال HTTP (أو HyperText Transfer Protocol) هي وسيلة وبروتوكول للطلب والرد وتسمح لجهاز كمبيوتر بالتواصل مع جهاز آخر عبر الإنترنت.

الطلب والرد

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

أداة سطر الأوامر curl تقدم لنا وسيلة سهله لإرسال طلبات HTTP. في النتيجة التالية، السطر الذي يبدأ ب < يعني أن النص أرسل في الطلب؛ الأسطر الباقية هي رد الخادم:

$ curl -v https://httpbin.org/html

كما ذكرت مُسبقاً في الفصل الثالث، لتشغيل أوامر sh على أجهزة ويندوز قم بتحميل Gitbash

> GET /html HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.55.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Connection: keep-alive
< Server: meinheld/0.6.1
< Date: Wed, 11 Apr 2018 18:15:03 GMT
< 
<html>
  <body>
    <h1>Herman Melville - Moby-Dick</h1>
    <p>
      Availing himself of the mild...
    </p>
  </body>
</html>

تشغيل الأمر curl يجعل جهاز العميل يكتب رسالة تبدو بهذا الشكل:

GET /html HTTP/1.1
Host: httpbin.org
User-Agent: curl/7.55.1
Accept: */*
{blank_line}

تتبع هذه الرسالة شكلاً معيناً: تبدأ ب GET /html HTTP/1.1 والتي تعني أن الرسالة من نوع طلب HTTP GET إلى صفحة /html. الأسطر الثلاثة التي تلي سطر رأس HTTP، هي معلومات اختيارية ترسلها curl إلى الخادم. رؤوس HTTP Headers شكلها كالتالي {name}: {value}. أخيرا، السطر الفارغ في نهاية الرسالة يخبر الخادم أن الرسالة انتهت بعد ثلاث رسائل. لاحظ أننا أشرنا للسطر الفارغ ب {blank_line} في المثال؛ ولكن في رسالة حقيقية تستبدل {blan_line} بسطر فارغ دون أي نص.

إذا، جهاز العميل يستخدم الإنترنت لإرسال رسالة إلى خادم الويب https://httpbin.org. الخادم يعالج الطلب، ثم يقوم بإرسال الرد التالي:

HTTP/1.1 200 OK
Connection: keep-alive
Server: meinheld/0.6.1
Date: Wed, 11 Apr 2018 18:15:03 GMT
{blank_line}

السطر الأول من الرد يشير على أن الطلب تم بنجاح. الأسطر الثلاثة التي تلي سطر HTTP، هي معلومات اختيارية يرسلها الخادم إلى العميل. أخيرا السطر الفارغ يخبر جهاز العميل أن الخادم أنهى رسالته الأولية ثم سيقوم بإرسال المحتوى Body:

<html>
  <body>
    <h1>Herman Melville - Moby-Dick</h1>
    <p>
      Availing himself of the mild...
    </p>
  </body>
</html>

بروتوكول HTTP يستخدم بواسطة أغلب التطبيقات التي تتعامل مع الإنترنت. مثلاً، زيارة الموقع https://httpbin.org/html عبر متصفح يرسل طلب HTTP مشابه لطلب curl. بدلاً من إظهار الرد كنص فقط كما شاهدنا مسبقاً، يتعرف المتصفح أن النص عبارة عن ملف HTML فيظهره بالشكل المطلوب.

عملياً، لن نكتب طلب HTTP كامل كنص. بدلاً من ذلك، سنستخدم أدوات مثل curl أو مكتبات في بايثون لبناء الطلب عنا.

بايثون

مكتبة Requests في بايثون تسمح لنا بإنشاء طلب HTTP. الكود البرمجي التالي ينشأ طلب HTTP مشابه للطلب curl -v https://httpbin.org/html:

import requests

url = "https://httpbin.org/html"
response = requests.get(url)
response
<Response [200]>

الطلب

لنلقي نظره أقرب على الطلب السابق. يمكننا تصفح الطلب الرئيسي باستخدام كائن response؛ سنظهر رأس طلب HTTP:

request = response.request
for key in request.headers: # رأس HTTP في الرد محفوظ في مصفوفه
    print(f'{key}: {request.headers[key]}')
User-Agent: python-requests/2.12.4
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

كل طلب عبر HTTP لديه نوع. في الحالة السابقة، استخدمنا طلب GET والذي يجلب بيانات من الخادم.

request.method
`GET`

الرد

لنتحقق من الرد الذي حصلنا عليه من الخادم. أولاً، سنطبع رأس HTTP للرد:

for key in response.headers:
    print(f'{key}: {response.headers[key]}')
Connection: keep-alive
Server: gunicorn/19.7.1
Date: Wed, 25 Apr 2018 18:32:51 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3741
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0
Via: 1.1 vegur

يحتوي رد HTTP على رمز للحالة، رقم خاص يبين إذا نجح أو فشل الطلب. الرمز 200 يعني أن الطلب تم بنجاح:

response.status_code
200

أخيرا، سنظهر أول 100 حرف من محتوى الرد (الرد الكامل محتواه كبير ولا يظهر بشكل جيد هنا):

response.text[:100]
'<!DOCTYPE html>\n<html>\n  <head>\n  </head>\n  <body>\n      <h1>Herman Melville - Moby-Dick</h1>\n\n     '

أنواع الطلبات

الطلب السابق كان طلب GET. هناك عدة أنواع من طلبات HTTP؛ أكثر الطلبات أهمية هي GET و POST.

طلب GET

طلب GET يستخدم لاستيراد معلومات من الخادم. بما أن المتصفح يقوم بطلب GET كل مرة تدخل فيها رابط لموقع، يعتبر لذلك طلب GET من أكثر الطلبات استخداماً من طلبات HTTP.

تستخدم curl طلب GET دائماً، الأمر curl https://www.google.com يقوم بإنشاء طلب GET ل https://www.google.com.

طلب POST

الطلب POST يستخدم لإرسال معلومات من العميل إلى الخادم. مثلاً، بعض المواقع تحتوي على حقول نحتاج أن نملأها، مثل حقول تسجيل الدخول. عند الضغط على زر إدخال، أكثر المتصفحات ستقوم بإنشاء طلب POST لإرسال البيانات الحقول إلى الخادم ليجري العمليات عليها.

لنرى مثلاً على طلب POST يرسل الكلمة sam في المتغير name. يمكن فعل ذلك كالتالي curl -d 'name=sam' https://httpbin.org/post في سطر الأوامر.

لاحظ أن طلبنا لديه محتوى الآن (عندما عبئنا المتغير في طلب POST)، ومحتوى الرد سيكون مختلف عن محتوى رد GET السابق.

كما في رؤوس HTTP، تستخدم طلبات POST نفس الشكل مفتاح-قيمه key-value. في بايثون، نستخدم requests.post مع تمرير المتغيرات كمصفوفات لإنشاء طلبات POST:

post_response = requests.post("https://httpbin.org/post",
                              data={'name': 'sam'})
post_response
<Response [200]>

الخادم سيرد برمز للحالة لينوه إذا ما كانت عملية طلب POST تمت بنجاح. أيضا، يرسل الخادم عادة محتوى ليعرض للعميل:

post_response.status_code
200
post_response.text
'{\n  "args": {}, \n  "data": "", \n  "files": {}, \n  "form": {\n    "name": "sam"\n  }, \n  "headers": {\n    "Accept": "*/*", \n    "Accept-Encoding": "gzip, deflate", \n    "Connection": "close", \n    "Content-Length": "8", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "httpbin.org", \n    "User-Agent": "python-requests/2.12.4"\n  }, \n  "json": null, \n  "origin": "136.152.143.72", \n  "url": "https://httpbin.org/post"\n}\n'

أنواع رموز الحالة للردود

ردود HTTP السابقة تحتوي على رمز 200 لحالة الرد. هذا الرمز يخبرنا أن الطلب تم بنجاح. هناك الكثير من الرموز الأخرى لحالات الرد ل HTTP. لحسن حظنا أن تم جمعها في مجموعات لتكون أسهل لنا للحفظ: 📝

  • ردود 100: معلوماتية: رد على أنه مطلوب معلومات أكثر من الخادم أو العميل. (مثلاً 100 استمرار، 102 جاري العمل).
  • ردود 200: نجاح: طلب العميل تم بنجاح. (مثلاً 200 نجاح، 202 مقبول).
  • ردود 300: إعادة توجيه: الرابط URL المطلوب موجود بمكان آخر؛ ربما يحتاج لقرار إضافي من المستخدم. (مثلاً 300 اختيارات، 301 منقول بشكل كامل).
  • ردود 400: خطأ من العميل: خطأ من جهة العميل (مثلاً 400 طلب خاطئ, 403 محظور, 404 غير موجود).
  • ردود 500: خطأ من الخادم: خطأ من جهة الخادم أو أن الخادم لا يمكنه من إجراء الطلب (مثلاً 500 خطأ داخلي في الخادم، 503 الخدمة غير موجودة)

يمكننا عرض بعض الأمثلة على الأخطاء:

# هذه الصفحه غير موجوده، سنحصل على رمز الخطأ بعدم وجود الصفحه 404
url = "https://www.youtube.com/404errorwow"
errorResponse = requests.get(url)
print(errorResponse)
<Response [404]>
# رد الرد لهذه الصفحه 500 خطأ في الخادم
url = "https://httpstat.us/500"
serverResponse = requests.get(url)
print(serverResponse)
<Response [500]>

ملخص

تعرفنا على بروتوكولات HTTP، الطرق البسيطة للتواصل بين البرامج التي تستخدم الويب. على الرغم أن البروتوكول يحدد شكل معين للنصوص، ننتقل عادةً لأدوات أخرى لكتابة طلبات HTTP لنا، مثل أداة سطر الأوامر curl أو مكتبة requests في بايثون.