Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون

مضمون کے مصنف، جس کا ترجمہ ہم آج شائع کر رہے ہیں، کا کہنا ہے کہ اس کا مقصد سیلینیم کا استعمال کرتے ہوئے ازگر میں ایک ویب سکریپر کی ترقی کے بارے میں بات کرنا ہے، جو ایئر لائن ٹکٹ کی قیمتوں کو تلاش کرتا ہے۔ ٹکٹوں کی تلاش کرتے وقت، لچکدار تاریخیں استعمال کی جاتی ہیں (مخصوص تاریخوں کے مقابلے میں +- 3 دن)۔ سکریپر تلاش کے نتائج کو ایکسل فائل میں محفوظ کرتا ہے اور تلاش کرنے والے شخص کو جو کچھ ملا اس کے خلاصے کے ساتھ ای میل بھیجتا ہے۔ اس پروجیکٹ کا مقصد مسافروں کو بہترین سودے تلاش کرنے میں مدد کرنا ہے۔

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون

اگر، مواد کو سمجھنے کے دوران، آپ کھوئے ہوئے محسوس کرتے ہیں، تو اس پر ایک نظر ڈالیں۔ یہ مضمون

ہم کیا تلاش کرنے جا رہے ہیں؟

آپ یہاں بیان کردہ نظام کو اپنی مرضی کے مطابق استعمال کرنے کے لیے آزاد ہیں۔ مثال کے طور پر، میں نے اسے اپنے آبائی شہر کے ویک اینڈ ٹورز اور ٹکٹس تلاش کرنے کے لیے استعمال کیا۔ اگر آپ منافع بخش ٹکٹ تلاش کرنے میں سنجیدہ ہیں، تو آپ اسکرپٹ کو سرور پر چلا سکتے ہیں (سادہ سرور, 130 rubles ایک ماہ کے لئے، اس کے لئے کافی موزوں ہے) اور یقینی بنائیں کہ یہ دن میں ایک یا دو بار چلتا ہے۔ تلاش کے نتائج آپ کو بذریعہ ای میل بھیجے جائیں گے۔ اس کے علاوہ، میں ہر چیز کو ترتیب دینے کی تجویز کرتا ہوں تاکہ اسکرپٹ ایکسل فائل کو تلاش کے نتائج کے ساتھ ڈراپ باکس فولڈر میں محفوظ کرے، جو آپ کو ایسی فائلوں کو کہیں سے بھی اور کسی بھی وقت دیکھنے کی اجازت دے گا۔

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
مجھے ابھی تک غلطیوں والے ٹیرف نہیں ملے ہیں، لیکن میرے خیال میں یہ ممکن ہے۔

تلاش کرتے وقت، جیسا کہ پہلے ہی ذکر کیا گیا ہے، ایک "لچکدار تاریخ" استعمال کی جاتی ہے؛ اسکرپٹ میں ایسی پیشکشیں ملتی ہیں جو دی گئی تاریخوں کے تین دن کے اندر ہوتی ہیں۔ اگرچہ اسکرپٹ کو چلاتے وقت، یہ صرف ایک سمت میں پیشکشوں کو تلاش کرتا ہے، اس میں ترمیم کرنا آسان ہے تاکہ یہ پرواز کی کئی سمتوں پر ڈیٹا اکٹھا کر سکے۔ اس کی مدد سے، آپ غلط ٹیرف بھی تلاش کر سکتے ہیں؛ اس طرح کے نتائج بہت دلچسپ ہو سکتے ہیں۔

آپ کو ایک اور ویب سکریپر کی ضرورت کیوں ہے؟

جب میں نے پہلی بار ویب سکریپنگ شروع کی تو مجھے ایمانداری سے اس میں کوئی خاص دلچسپی نہیں تھی۔ میں پیشن گوئی ماڈلنگ، مالیاتی تجزیہ، اور ممکنہ طور پر متن کے جذباتی رنگت کا تجزیہ کرنے کے میدان میں مزید پروجیکٹس کرنا چاہتا تھا۔ لیکن معلوم ہوا کہ یہ جاننا بہت دلچسپ تھا کہ ایسا پروگرام کیسے بنایا جائے جو ویب سائٹس سے ڈیٹا اکٹھا کرے۔ جیسا کہ میں نے اس موضوع پر غور کیا، میں نے محسوس کیا کہ ویب سکریپنگ انٹرنیٹ کا "انجن" ہے۔

آپ کو لگتا ہے کہ یہ بہت جرات مندانہ بیان ہے۔ لیکن غور کریں کہ گوگل نے ایک ویب سکریپر کے ساتھ آغاز کیا جسے لیری پیج نے جاوا اور ازگر کا استعمال کرتے ہوئے بنایا تھا۔ گوگل کے روبوٹس انٹرنیٹ کو تلاش کر رہے ہیں، اپنے صارفین کو ان کے سوالات کے بہترین جوابات فراہم کرنے کی کوشش کر رہے ہیں۔ ویب سکریپنگ کے لامتناہی استعمال ہوتے ہیں، اور یہاں تک کہ اگر آپ ڈیٹا سائنس میں کسی اور چیز میں دلچسپی رکھتے ہیں، تو آپ کو اس ڈیٹا کو حاصل کرنے کے لیے کچھ اسکریپنگ مہارتوں کی ضرورت ہوگی جس کی آپ کو تجزیہ کرنے کی ضرورت ہے۔

مجھے یہاں استعمال ہونے والی کچھ تکنیکیں بہت اچھی لگیں۔ کتاب ویب سکریپنگ کے بارے میں، جو میں نے حال ہی میں حاصل کیا ہے۔ جو کچھ آپ نے سیکھا ہے اس کے عملی اطلاق کے لیے اس میں بہت سی آسان مثالیں اور آئیڈیاز ہیں۔ اس کے علاوہ، reCaptcha چیک کو نظرانداز کرنے کا ایک بہت ہی دلچسپ باب ہے۔ یہ میرے لیے خبر کے طور پر آیا، کیونکہ میں یہ بھی نہیں جانتا تھا کہ اس طرح کے مسائل کو حل کرنے کے لیے خصوصی ٹولز اور یہاں تک کہ پوری خدمات موجود ہیں۔

کیا آپ سفر کرنا پسند کرتے ہیں؟!

اس سیکشن کے عنوان میں پوچھے گئے سادہ اور بے ضرر سوال کا، آپ اکثر ایک مثبت جواب سن سکتے ہیں، اس کے ساتھ اس شخص کے سفر کی چند کہانیاں بھی شامل ہیں جن سے یہ پوچھا گیا تھا۔ ہم میں سے اکثر اس بات سے متفق ہوں گے کہ نئے ثقافتی ماحول میں اپنے آپ کو غرق کرنے اور اپنے افق کو وسیع کرنے کا سفر ایک بہترین طریقہ ہے۔ تاہم، اگر آپ کسی سے پوچھیں کہ کیا وہ ایئر لائن ٹکٹوں کی تلاش پسند کرتے ہیں، تو مجھے یقین ہے کہ جواب اتنا مثبت نہیں ہوگا۔ حقیقت کے طور پر، Python یہاں ہماری مدد کے لیے آتا ہے۔

ہوائی ٹکٹوں پر معلومات کی تلاش کے لیے ایک نظام بنانے کے راستے میں پہلا کام جسے حل کرنے کی ضرورت ہے وہ ایک مناسب پلیٹ فارم کا انتخاب کرنا ہے جہاں سے ہم معلومات لیں گے۔ اس مسئلے کو حل کرنا میرے لیے آسان نہیں تھا لیکن آخر کار میں نے کیاک سروس کا انتخاب کیا۔ میں نے Momondo، Skyscanner، Expedia، اور چند دیگر کی خدمات آزمائیں، لیکن ان وسائل پر روبوٹ کے تحفظ کا طریقہ کار ناقابل تسخیر تھا۔ کئی کوششوں کے بعد، جس کے دوران مجھے ٹریفک لائٹس، پیدل چلنے والوں کے کراسنگ اور سائیکلوں سے نمٹنا پڑا، سسٹمز کو یہ باور کرانے کی کوشش کی کہ میں انسان ہوں، میں نے فیصلہ کیا کہ کیاک میرے لیے سب سے موزوں ہے، اس حقیقت کے باوجود کہ اگر بہت سارے صفحات لوڈ ہو جائیں۔ تھوڑی ہی دیر میں، اور چیک بھی شروع ہو جاتے ہیں۔ میں بوٹ کو 4 سے 6 گھنٹے کے وقفوں سے سائٹ پر درخواستیں بھیجنے میں کامیاب ہو گیا، اور سب کچھ ٹھیک ہو گیا۔ وقتاً فوقتاً، کیاک کے ساتھ کام کرتے وقت مشکلات پیدا ہوتی ہیں، لیکن اگر وہ آپ کو چیک کے ذریعے پریشان کرنا شروع کر دیتے ہیں، تو آپ کو یا تو ان کے ساتھ دستی طور پر نمٹنے اور پھر بوٹ لانچ کرنے کی ضرورت ہے، یا چند گھنٹے انتظار کریں اور چیک بند ہو جائیں۔ اگر ضروری ہو تو، آپ آسانی سے دوسرے پلیٹ فارم کے لیے کوڈ کو اپنا سکتے ہیں، اور اگر آپ ایسا کرتے ہیں، تو آپ تبصروں میں اس کی اطلاع دے سکتے ہیں۔

اگر آپ ابھی ویب سکریپنگ کے ساتھ شروعات کر رہے ہیں اور نہیں جانتے کہ کچھ ویب سائٹس اس کے ساتھ کیوں جدوجہد کرتی ہیں، تو اس سے پہلے کہ آپ اس علاقے میں اپنا پہلا پروجیکٹ شروع کریں، اپنے آپ پر احسان کریں اور "ویب سکریپنگ کے آداب" کے الفاظ پر گوگل سرچ کریں۔ . اگر آپ غیر دانشمندی سے ویب سکریپنگ کرتے ہیں تو آپ کے تجربات آپ کی سوچ سے جلد ختم ہو سکتے ہیں۔

شروع کریں

ہمارے ویب سکریپر کوڈ میں کیا ہوگا اس کا ایک عمومی جائزہ یہ ہے:

  • مطلوبہ لائبریریاں درآمد کریں۔
  • گوگل کروم ٹیب کھولنا۔
  • ایک فنکشن کو کال کریں جو بوٹ کو شروع کرتا ہے، اسے شہروں اور تاریخوں کو پاس کرتا ہے جو ٹکٹوں کی تلاش میں استعمال ہوں گی۔
  • یہ فنکشن پہلے تلاش کے نتائج لیتا ہے، بہترین کے لحاظ سے ترتیب دیا جاتا ہے، اور مزید نتائج لوڈ کرنے کے لیے ایک بٹن پر کلک کرتا ہے۔
  • ایک اور فنکشن پورے صفحے سے ڈیٹا اکٹھا کرتا ہے اور ڈیٹا فریم لوٹاتا ہے۔
  • دو پچھلے مراحل ٹکٹ کی قیمت (سستے) اور پرواز کی رفتار (تیز ترین) کے لحاظ سے چھانٹی کی اقسام کا استعمال کرتے ہوئے انجام دیے جاتے ہیں۔
  • اسکرپٹ کے استعمال کنندہ کو ایک ای میل بھیجی جاتی ہے جس میں ٹکٹ کی قیمتوں کا خلاصہ ہوتا ہے (سب سے سستے ٹکٹ اور اوسط قیمت)، اور ایک ڈیٹا فریم جس میں مندرجہ بالا تین اشارے کے مطابق ترتیب دی گئی معلومات کو ایکسل فائل کے طور پر محفوظ کیا جاتا ہے۔
  • مندرجہ بالا تمام اعمال ایک مخصوص مدت کے بعد ایک چکر میں انجام پاتے ہیں۔

واضح رہے کہ ہر سیلینیم پروجیکٹ ویب ڈرائیور سے شروع ہوتا ہے۔ میں استعمال کروم ڈرائیورمیں گوگل کروم کے ساتھ کام کرتا ہوں، لیکن اس کے علاوہ اور بھی اختیارات ہیں۔ فینٹم جے ایس اور فائر فاکس بھی مقبول ہیں۔ ڈرائیور کو ڈاؤن لوڈ کرنے کے بعد، آپ کو اسے مناسب فولڈر میں رکھنے کی ضرورت ہے، اور یہ اس کے استعمال کی تیاری مکمل کرتا ہے۔ ہماری اسکرپٹ کی پہلی سطریں ایک نیا کروم ٹیب کھولتی ہیں۔

یاد رکھیں کہ میں اپنی کہانی میں ہوائی ٹکٹوں پر زبردست سودے تلاش کرنے کے لیے نئے افق کھولنے کی کوشش نہیں کر رہا ہوں۔ ایسی پیشکشوں کو تلاش کرنے کے بہت زیادہ جدید طریقے ہیں۔ میں صرف اس مواد کے قارئین کو اس مسئلے کو حل کرنے کا ایک آسان لیکن عملی طریقہ پیش کرنا چاہتا ہوں۔

یہ وہ کوڈ ہے جس کے بارے میں ہم نے اوپر بات کی ہے۔

from time import sleep, strftime
from random import randint
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import smtplib
from email.mime.multipart import MIMEMultipart

# Используйте тут ваш путь к chromedriver!
chromedriver_path = 'C:/{YOUR PATH HERE}/chromedriver_win32/chromedriver.exe'

driver = webdriver.Chrome(executable_path=chromedriver_path) # Этой командой открывается окно Chrome
sleep(2)

کوڈ کے شروع میں آپ پیکیج امپورٹ کمانڈز دیکھ سکتے ہیں جو ہمارے پورے پروجیکٹ میں استعمال ہوتے ہیں۔ تو، randint نیا سرچ آپریشن شروع کرنے سے پہلے بوٹ کو سیکنڈوں کی بے ترتیب تعداد میں "سو جانے" کے لیے استعمال کیا جاتا ہے۔ عام طور پر، ایک بھی بوٹ اس کے بغیر نہیں کر سکتا۔ اگر آپ مندرجہ بالا کوڈ کو چلاتے ہیں، تو ایک کروم ونڈو کھل جائے گی، جسے بوٹ سائٹس کے ساتھ کام کرنے کے لیے استعمال کرے گا۔

آئیے ایک چھوٹا سا تجربہ کریں اور kayak.com ویب سائٹ کو ایک علیحدہ ونڈو میں کھولیں۔ ہم اس شہر کا انتخاب کریں گے جہاں سے ہم اڑان بھرنے جا رہے ہیں، اور جس شہر میں ہم جانا چاہتے ہیں، اس کے ساتھ ساتھ پرواز کی تاریخوں کا بھی انتخاب کریں گے۔ تاریخوں کا انتخاب کرتے وقت، یقینی بنائیں کہ +-3 دنوں کی رینج استعمال کی گئی ہے۔ میں نے کوڈ اس بات کو مدنظر رکھتے ہوئے لکھا ہے کہ اس طرح کی درخواستوں کے جواب میں سائٹ کیا تیار کرتی ہے۔ اگر، مثال کے طور پر، آپ کو صرف مخصوص تاریخوں کے لیے ٹکٹ تلاش کرنے کی ضرورت ہے، تو اس بات کا زیادہ امکان ہے کہ آپ کو بوٹ کوڈ میں ترمیم کرنا پڑے گی۔ جب میں کوڈ کے بارے میں بات کرتا ہوں، تو میں مناسب وضاحت فراہم کرتا ہوں، لیکن اگر آپ کو الجھن محسوس ہو تو مجھے بتائیں۔

اب سرچ بٹن پر کلک کریں اور ایڈریس بار میں موجود لنک کو دیکھیں۔ یہ اس لنک سے ملتا جلتا ہونا چاہئے جو میں نیچے دی گئی مثال میں استعمال کرتا ہوں جہاں متغیر کا اعلان کیا گیا ہے۔ kayak، جو URL کو ذخیرہ کرتا ہے، اور طریقہ استعمال کیا جاتا ہے۔ get ویب ڈرائیور. تلاش کے بٹن پر کلک کرنے کے بعد، نتائج صفحہ پر ظاہر ہونے چاہئیں۔

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
جب میں نے کمانڈ استعمال کیا۔ get چند منٹوں میں دو یا تین سے زیادہ بار، مجھ سے کہا گیا کہ reCaptcha کا استعمال کرتے ہوئے تصدیق مکمل کریں۔ آپ اس چیک کو دستی طور پر پاس کر سکتے ہیں اور اس وقت تک تجربہ جاری رکھ سکتے ہیں جب تک کہ سسٹم نیا چیک چلانے کا فیصلہ نہ کرے۔ جب میں نے اسکرپٹ کا تجربہ کیا تو ایسا لگتا تھا کہ پہلا سرچ سیشن ہمیشہ آسانی سے چلا گیا، لہذا اگر آپ کوڈ کے ساتھ تجربہ کرنا چاہتے ہیں، تو آپ کو وقتاً فوقتاً دستی طور پر چیک کرنا پڑے گا اور تلاش کے سیشنوں کے درمیان طویل وقفوں کا استعمال کرتے ہوئے کوڈ کو چلنے دینا پڑے گا۔ اور، اگر آپ اس کے بارے میں سوچتے ہیں، تو کسی شخص کو تلاشی کی کارروائیوں کے درمیان 10 منٹ کے وقفوں پر ٹکٹ کی قیمتوں کے بارے میں معلومات کی ضرورت نہیں ہوگی۔

XPath کا استعمال کرتے ہوئے صفحہ کے ساتھ کام کرنا

تو، ہم نے ایک ونڈو کھولی اور سائٹ کو لوڈ کیا۔ قیمت اور دیگر معلومات حاصل کرنے کے لیے، ہمیں XPath ٹیکنالوجی یا CSS سلیکٹرز استعمال کرنے کی ضرورت ہے۔ میں نے XPath کے ساتھ قائم رہنے کا فیصلہ کیا اور CSS سلیکٹرز کو استعمال کرنے کی ضرورت محسوس نہیں کی، لیکن اس طرح کام کرنا کافی ممکن ہے۔ XPath کا استعمال کرتے ہوئے کسی صفحے کے گرد گھومنا پھرنا مشکل ہوسکتا ہے، اور یہاں تک کہ اگر آپ وہ تکنیک استعمال کرتے ہیں جن میں میں نے بیان کیا ہے۔ اس مضمون، جس میں صفحہ کے کوڈ سے متعلقہ شناخت کنندگان کو کاپی کرنا شامل تھا، میں نے محسوس کیا کہ درحقیقت یہ ضروری عناصر تک رسائی کا بہترین طریقہ نہیں ہے۔ ویسے، میں اس کتاب XPath اور CSS سلیکٹرز کا استعمال کرتے ہوئے صفحات کے ساتھ کام کرنے کی بنیادی باتوں کی بہترین وضاحت فراہم کرتی ہے۔ متعلقہ ویب ڈرائیور کا طریقہ ایسا لگتا ہے۔

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
تو، آئیے بوٹ پر کام جاری رکھیں۔ آئیے سب سے سستے ٹکٹوں کو منتخب کرنے کے لیے پروگرام کی صلاحیتوں کا استعمال کریں۔ مندرجہ ذیل تصویر میں، XPath سلیکٹر کوڈ کو سرخ رنگ میں نمایاں کیا گیا ہے۔ کوڈ دیکھنے کے لیے، آپ کو صفحہ کے اس عنصر پر دائیں کلک کرنے کی ضرورت ہے جس میں آپ دلچسپی رکھتے ہیں اور ظاہر ہونے والے مینو سے Inspect کمانڈ کو منتخب کریں۔ اس کمانڈ کو صفحہ کے مختلف عناصر کے لیے بلایا جا سکتا ہے، جس کا کوڈ کوڈ ویور میں ڈسپلے اور ہائی لائٹ کیا جائے گا۔

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
صفحہ کا کوڈ دیکھیں

کوڈ سے سلیکٹرز کو کاپی کرنے کے نقصانات کے بارے میں میرے استدلال کی تصدیق تلاش کرنے کے لیے، درج ذیل خصوصیات پر توجہ دیں۔

جب آپ کوڈ کاپی کرتے ہیں تو یہ آپ کو ملتا ہے:

//*[@id="wtKI-price_aTab"]/div[1]/div/div/div[1]/div/span/span

اس طرح کی کوئی چیز کاپی کرنے کے لیے، آپ کو کوڈ کے اس حصے پر دائیں کلک کرنے کی ضرورت ہے جس میں آپ دلچسپی رکھتے ہیں اور ظاہر ہونے والے مینو سے Copy > Copy XPath کمانڈ کو منتخب کریں۔

یہ ہے جو میں نے سب سے سستا بٹن کی وضاحت کرنے کے لیے استعمال کیا تھا:

cheap_results = ‘//a[@data-code = "price"]’

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
کاپی کمانڈ> کاپی ایکس پاتھ

یہ بالکل واضح ہے کہ دوسرا آپشن بہت آسان لگتا ہے۔ جب استعمال کیا جاتا ہے، تو یہ ایک ایسے عنصر کی تلاش کرتا ہے جس میں وصف ہو۔ data-code، برابر price. پہلا آپشن استعمال کرتے وقت، عنصر کو تلاش کیا جاتا ہے۔ id جس کے برابر ہے wtKI-price_aTab، اور عنصر کا XPath راستہ ایسا لگتا ہے۔ /div[1]/div/div/div[1]/div/span/span. کسی صفحے پر اس طرح کا XPath استفسار چال کرے گا، لیکن صرف ایک بار۔ میں ابھی یہ کہہ سکتا ہوں۔ id اگلی بار صفحہ لوڈ ہونے پر تبدیل ہو جائے گا۔ کردار کی ترتیب wtKI جب بھی صفحہ لوڈ ہوتا ہے متحرک طور پر تبدیل ہوتا ہے، اس لیے اگلے صفحے کے دوبارہ لوڈ ہونے کے بعد اس کو استعمال کرنے والا کوڈ بیکار ہو جائے گا۔ تو XPath کو سمجھنے کے لیے کچھ وقت نکالیں۔ یہ علم آپ کی اچھی طرح خدمت کرے گا۔

تاہم، یہ واضح رہے کہ XPath سلیکٹرز کو کاپی کرنا کافی آسان سائٹس کے ساتھ کام کرتے وقت کارآمد ثابت ہوسکتا ہے، اور اگر آپ اس سے مطمئن ہیں، تو اس میں کوئی حرج نہیں ہے۔

اب آئیے سوچتے ہیں کہ اگر آپ کو فہرست کے اندر تلاش کے تمام نتائج کو کئی سطروں میں حاصل کرنے کی ضرورت ہو تو کیا کریں۔ بہت آسان. ہر نتیجہ کلاس کے ساتھ کسی چیز کے اندر ہوتا ہے۔ resultWrapper. تمام نتائج کو لوڈ کرنا نیچے دکھائے گئے نتائج کی طرح ایک لوپ میں کیا جا سکتا ہے۔

واضح رہے کہ اگر آپ مندرجہ بالا کو سمجھتے ہیں، تو آپ کو زیادہ تر کوڈ کو آسانی سے سمجھ لینا چاہیے جس کا ہم تجزیہ کریں گے۔ جیسا کہ یہ کوڈ چلتا ہے، ہم کسی قسم کے راستے کی وضاحت کرنے والے میکانزم (XPath) کا استعمال کرتے ہوئے اس تک رسائی حاصل کرتے ہیں جس کی ہمیں ضرورت ہوتی ہے (حقیقت میں، وہ عنصر جس میں نتیجہ لپیٹا جاتا ہے)۔ یہ عنصر کا متن حاصل کرنے اور اسے کسی ایسی شے میں رکھنے کے لیے کیا جاتا ہے جہاں سے ڈیٹا پڑھا جا سکتا ہے (پہلے استعمال flight_containers، پھر - flights_list).

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
پہلی تین لائنیں ظاہر ہوتی ہیں اور ہم اپنی ضرورت کی ہر چیز کو واضح طور پر دیکھ سکتے ہیں۔ تاہم، ہمارے پاس معلومات حاصل کرنے کے مزید دلچسپ طریقے ہیں۔ ہمیں ہر عنصر سے الگ الگ ڈیٹا لینے کی ضرورت ہے۔

کام پر لگ جاؤ!

فنکشن لکھنے کا سب سے آسان طریقہ اضافی نتائج لوڈ کرنا ہے، تاکہ ہم یہیں سے شروع کریں گے۔ میں ان پروازوں کی تعداد کو زیادہ سے زیادہ کرنا چاہوں گا جن کے بارے میں پروگرام معلومات حاصل کرتا ہے، سروس میں شکوک و شبہات پیدا کیے بغیر، اس لیے میں ہر بار صفحہ ظاہر ہونے پر مزید نتائج لوڈ کریں بٹن پر کلک کرتا ہوں۔ اس کوڈ میں، آپ کو بلاک پر توجہ دینا چاہئے try، جسے میں نے شامل کیا کیونکہ بعض اوقات بٹن ٹھیک سے لوڈ نہیں ہوتا ہے۔ اگر آپ بھی اس کا سامنا کرتے ہیں تو، فنکشن کوڈ میں اس فنکشن پر کالز کو کمنٹ کریں۔ start_kayak، جسے ہم ذیل میں دیکھیں گے۔

# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
def load_more():
    try:
        more_results = '//a[@class = "moreButton"]'
        driver.find_element_by_xpath(more_results).click()
        # Вывод этих заметок в ходе работы программы помогает мне быстро выяснить то, чем она занята
        print('sleeping.....')
        sleep(randint(45,60))
    except:
        pass

اب، اس فنکشن کے طویل تجزیے کے بعد (کبھی کبھی میں بہہ سکتا ہوں)، ہم ایک فنکشن کا اعلان کرنے کے لیے تیار ہیں جو صفحہ کو کھرچ دے گا۔

میں نے پہلے ہی درج ذیل فنکشن میں ضرورت کی زیادہ تر چیزیں جمع کر لی ہیں۔ page_scrape. کبھی کبھی واپس آنے والے راستے کے ڈیٹا کو جوڑ دیا جاتا ہے، لہذا میں اسے الگ کرنے کے لیے ایک آسان طریقہ استعمال کرتا ہوں۔ مثال کے طور پر، جب میں پہلی بار متغیرات استعمال کرتا ہوں۔ section_a_list и section_b_list. ہمارا فنکشن ڈیٹا فریم واپس کرتا ہے۔ flights_df، یہ ہمیں مختلف ڈیٹا چھانٹنے کے طریقوں سے حاصل کردہ نتائج کو الگ کرنے اور بعد میں ان کو یکجا کرنے کی اجازت دیتا ہے۔

def page_scrape():
    """This function takes care of the scraping part"""
    
    xp_sections = '//*[@class="section duration"]'
    sections = driver.find_elements_by_xpath(xp_sections)
    sections_list = [value.text for value in sections]
    section_a_list = sections_list[::2] # так мы разделяем информацию о двух полётах
    section_b_list = sections_list[1::2]
    
    # Если вы наткнулись на reCaptcha, вам может понадобиться что-то предпринять.
    # О том, что что-то пошло не так, вы узнаете исходя из того, что вышеприведённые списки пусты
    # это выражение if позволяет завершить работу программы или сделать ещё что-нибудь
    # тут можно приостановить работу, что позволит вам пройти проверку и продолжить скрапинг
    # я использую тут SystemExit так как хочу протестировать всё с самого начала
    if section_a_list == []:
        raise SystemExit
    
    # Я буду использовать букву A для уходящих рейсов и B для прибывающих
    a_duration = []
    a_section_names = []
    for n in section_a_list:
        # Получаем время
        a_section_names.append(''.join(n.split()[2:5]))
        a_duration.append(''.join(n.split()[0:2]))
    b_duration = []
    b_section_names = []
    for n in section_b_list:
        # Получаем время
        b_section_names.append(''.join(n.split()[2:5]))
        b_duration.append(''.join(n.split()[0:2]))

    xp_dates = '//div[@class="section date"]'
    dates = driver.find_elements_by_xpath(xp_dates)
    dates_list = [value.text for value in dates]
    a_date_list = dates_list[::2]
    b_date_list = dates_list[1::2]
    # Получаем день недели
    a_day = [value.split()[0] for value in a_date_list]
    a_weekday = [value.split()[1] for value in a_date_list]
    b_day = [value.split()[0] for value in b_date_list]
    b_weekday = [value.split()[1] for value in b_date_list]
    
    # Получаем цены
    xp_prices = '//a[@class="booking-link"]/span[@class="price option-text"]'
    prices = driver.find_elements_by_xpath(xp_prices)
    prices_list = [price.text.replace('$','') for price in prices if price.text != '']
    prices_list = list(map(int, prices_list))

    # stops - это большой список, в котором первый фрагмент пути находится по чётному индексу, а второй - по нечётному
    xp_stops = '//div[@class="section stops"]/div[1]'
    stops = driver.find_elements_by_xpath(xp_stops)
    stops_list = [stop.text[0].replace('n','0') for stop in stops]
    a_stop_list = stops_list[::2]
    b_stop_list = stops_list[1::2]

    xp_stops_cities = '//div[@class="section stops"]/div[2]'
    stops_cities = driver.find_elements_by_xpath(xp_stops_cities)
    stops_cities_list = [stop.text for stop in stops_cities]
    a_stop_name_list = stops_cities_list[::2]
    b_stop_name_list = stops_cities_list[1::2]
    
    # сведения о компании-перевозчике, время отправления и прибытия для обоих рейсов
    xp_schedule = '//div[@class="section times"]'
    schedules = driver.find_elements_by_xpath(xp_schedule)
    hours_list = []
    carrier_list = []
    for schedule in schedules:
        hours_list.append(schedule.text.split('n')[0])
        carrier_list.append(schedule.text.split('n')[1])
    # разделяем сведения о времени и о перевозчиках между рейсами a и b
    a_hours = hours_list[::2]
    a_carrier = carrier_list[1::2]
    b_hours = hours_list[::2]
    b_carrier = carrier_list[1::2]

    
    cols = (['Out Day', 'Out Time', 'Out Weekday', 'Out Airline', 'Out Cities', 'Out Duration', 'Out Stops', 'Out Stop Cities',
            'Return Day', 'Return Time', 'Return Weekday', 'Return Airline', 'Return Cities', 'Return Duration', 'Return Stops', 'Return Stop Cities',
            'Price'])

    flights_df = pd.DataFrame({'Out Day': a_day,
                               'Out Weekday': a_weekday,
                               'Out Duration': a_duration,
                               'Out Cities': a_section_names,
                               'Return Day': b_day,
                               'Return Weekday': b_weekday,
                               'Return Duration': b_duration,
                               'Return Cities': b_section_names,
                               'Out Stops': a_stop_list,
                               'Out Stop Cities': a_stop_name_list,
                               'Return Stops': b_stop_list,
                               'Return Stop Cities': b_stop_name_list,
                               'Out Time': a_hours,
                               'Out Airline': a_carrier,
                               'Return Time': b_hours,
                               'Return Airline': b_carrier,                           
                               'Price': prices_list})[cols]
    
    flights_df['timestamp'] = strftime("%Y%m%d-%H%M") # время сбора данных
    return flights_df

میں نے متغیرات کو نام دینے کی کوشش کی تاکہ کوڈ سمجھ میں آجائے۔ یاد رکھیں کہ متغیرات سے شروع ہوتا ہے۔ a راستے کے پہلے مرحلے سے تعلق رکھتے ہیں، اور b - دوسرے کو. آئیے اگلے فنکشن کی طرف چلتے ہیں۔

سپورٹ میکانزم

ہمارے پاس اب ایک فنکشن ہے جو ہمیں اضافی تلاش کے نتائج اور ان نتائج پر کارروائی کرنے کے لیے ایک فنکشن لوڈ کرنے کی اجازت دیتا ہے۔ یہ مضمون یہاں ختم ہو سکتا تھا، کیونکہ یہ دو فنکشن آپ کو صفحات کو کھرچنے کے لیے درکار ہر چیز فراہم کرتے ہیں جسے آپ خود کھول سکتے ہیں۔ لیکن ہم نے ابھی تک اوپر زیر بحث کچھ معاون طریقہ کار پر غور نہیں کیا ہے۔ مثال کے طور پر، یہ ای میلز اور کچھ دوسری چیزوں کو بھیجنے کا کوڈ ہے۔ یہ سب فنکشن میں پایا جا سکتا ہے۔ start_kayak، جس پر ہم اب غور کریں گے۔

اس فنکشن کے کام کرنے کے لیے، آپ کو شہروں اور تاریخوں کے بارے میں معلومات درکار ہیں۔ اس معلومات کا استعمال کرتے ہوئے، یہ متغیر میں ایک لنک بناتا ہے۔ kayak، جس کا استعمال آپ کو ایک ایسے صفحہ پر لے جانے کے لیے کیا جاتا ہے جس میں تلاش کے نتائج کو استفسار سے ان کے بہترین مماثلت کے مطابق ترتیب دیا جائے گا۔ پہلے سکریپنگ سیشن کے بعد، ہم صفحہ کے اوپری حصے میں ٹیبل میں قیمتوں کے ساتھ کام کریں گے۔ یعنی، ہمیں ٹکٹ کی کم از کم قیمت اور اوسط قیمت مل جائے گی۔ یہ سب سائٹ کی طرف سے جاری کردہ پیشین گوئی کے ساتھ ای میل کے ذریعے بھیجا جائے گا۔ صفحہ پر، متعلقہ جدول اوپری بائیں کونے میں ہونا چاہیے۔ اس ٹیبل کے ساتھ کام کرنا، ویسے، درست تاریخوں کا استعمال کرتے ہوئے تلاش کرتے وقت غلطی کا سبب بن سکتا ہے، کیونکہ اس صورت میں ٹیبل صفحہ پر ظاہر نہیں ہوتا ہے۔

def start_kayak(city_from, city_to, date_start, date_end):
    """City codes - it's the IATA codes!
    Date format -  YYYY-MM-DD"""
    
    kayak = ('https://www.kayak.com/flights/' + city_from + '-' + city_to +
             '/' + date_start + '-flexible/' + date_end + '-flexible?sort=bestflight_a')
    driver.get(kayak)
    sleep(randint(8,10))
    
    # иногда появляется всплывающее окно, для проверки на это и его закрытия можно воспользоваться блоком try
    try:
        xp_popup_close = '//button[contains(@id,"dialog-close") and contains(@class,"Button-No-Standard-Style close ")]'
        driver.find_elements_by_xpath(xp_popup_close)[5].click()
    except Exception as e:
        pass
    sleep(randint(60,95))
    print('loading more.....')
    
#     load_more()
    
    print('starting first scrape.....')
    df_flights_best = page_scrape()
    df_flights_best['sort'] = 'best'
    sleep(randint(60,80))
    
    # Возьмём самую низкую цену из таблицы, расположенной в верхней части страницы
    matrix = driver.find_elements_by_xpath('//*[contains(@id,"FlexMatrixCell")]')
    matrix_prices = [price.text.replace('$','') for price in matrix]
    matrix_prices = list(map(int, matrix_prices))
    matrix_min = min(matrix_prices)
    matrix_avg = sum(matrix_prices)/len(matrix_prices)
    
    print('switching to cheapest results.....')
    cheap_results = '//a[@data-code = "price"]'
    driver.find_element_by_xpath(cheap_results).click()
    sleep(randint(60,90))
    print('loading more.....')
    
#     load_more()
    
    print('starting second scrape.....')
    df_flights_cheap = page_scrape()
    df_flights_cheap['sort'] = 'cheap'
    sleep(randint(60,80))
    
    print('switching to quickest results.....')
    quick_results = '//a[@data-code = "duration"]'
    driver.find_element_by_xpath(quick_results).click()  
    sleep(randint(60,90))
    print('loading more.....')
    
#     load_more()
    
    print('starting third scrape.....')
    df_flights_fast = page_scrape()
    df_flights_fast['sort'] = 'fast'
    sleep(randint(60,80))
    
    # Сохранение нового фрейма в Excel-файл, имя которого отражает города и даты
    final_df = df_flights_cheap.append(df_flights_best).append(df_flights_fast)
    final_df.to_excel('search_backups//{}_flights_{}-{}_from_{}_to_{}.xlsx'.format(strftime("%Y%m%d-%H%M"),
                                                                                   city_from, city_to, 
                                                                                   date_start, date_end), index=False)
    print('saved df.....')
    
    # Можно следить за тем, как прогноз, выдаваемый сайтом, соотносится с реальностью
    xp_loading = '//div[contains(@id,"advice")]'
    loading = driver.find_element_by_xpath(xp_loading).text
    xp_prediction = '//span[@class="info-text"]'
    prediction = driver.find_element_by_xpath(xp_prediction).text
    print(loading+'n'+prediction)
    
    # иногда в переменной loading оказывается эта строка, которая, позже, вызывает проблемы с отправкой письма
    # если это прозошло - меняем её на "Not Sure"
    weird = '¯_(ツ)_/¯'
    if loading == weird:
        loading = 'Not sure'
    
    username = '[email protected]'
    password = 'YOUR PASSWORD'

    server = smtplib.SMTP('smtp.outlook.com', 587)
    server.ehlo()
    server.starttls()
    server.login(username, password)
    msg = ('Subject: Flight Scrapernn
Cheapest Flight: {}nAverage Price: {}nnRecommendation: {}nnEnd of message'.format(matrix_min, matrix_avg, (loading+'n'+prediction)))
    message = MIMEMultipart()
    message['From'] = '[email protected]'
    message['to'] = '[email protected]'
    server.sendmail('[email protected]', '[email protected]', msg)
    print('sent email.....')

میں نے آؤٹ لک اکاؤنٹ (hotmail.com) کا استعمال کرتے ہوئے اس اسکرپٹ کا تجربہ کیا۔ میں نے جی میل اکاؤنٹ کے ساتھ صحیح طریقے سے کام کرنے کے لیے اس کا تجربہ نہیں کیا ہے، یہ ای میل سسٹم کافی مقبول ہے، لیکن بہت سے ممکنہ آپشنز موجود ہیں۔ اگر آپ ہاٹ میل اکاؤنٹ استعمال کرتے ہیں، تو ہر چیز کے کام کرنے کے لیے، آپ کو صرف کوڈ میں اپنا ڈیٹا داخل کرنے کی ضرورت ہے۔

اگر آپ یہ سمجھنا چاہتے ہیں کہ اس فنکشن کے لیے کوڈ کے مخصوص حصوں میں کیا کیا جا رہا ہے، تو آپ انہیں کاپی کر کے ان کے ساتھ تجربہ کر سکتے ہیں۔ کوڈ کے ساتھ تجربہ کرنا اسے صحیح معنوں میں سمجھنے کا واحد طریقہ ہے۔

تیار نظام

اب جب کہ ہم نے وہ سب کچھ کر لیا ہے جس کے بارے میں ہم نے بات کی ہے، ہم ایک سادہ لوپ بنا سکتے ہیں جو ہمارے افعال کو کال کرتا ہے۔ اسکرپٹ صارف سے شہروں اور تاریخوں کے بارے میں ڈیٹا کی درخواست کرتی ہے۔ اسکرپٹ کو مسلسل دوبارہ شروع کرنے کے ساتھ جانچ کرتے وقت، آپ کو ہر بار اس ڈیٹا کو دستی طور پر داخل کرنے کا امکان نہیں ہوتا ہے، اس لیے جانچ کے وقت کے لیے متعلقہ لائنوں کو ان کے نیچے والے کو غیر تبصرہ کرکے تبصرہ کیا جاسکتا ہے، جس میں ڈیٹا کی ضرورت ہوتی ہے۔ اسکرپٹ ہارڈ کوڈ ہے۔

city_from = input('From which city? ')
city_to = input('Where to? ')
date_start = input('Search around which departure date? Please use YYYY-MM-DD format only ')
date_end = input('Return when? Please use YYYY-MM-DD format only ')

# city_from = 'LIS'
# city_to = 'SIN'
# date_start = '2019-08-21'
# date_end = '2019-09-07'

for n in range(0,5):
    start_kayak(city_from, city_to, date_start, date_end)
    print('iteration {} was complete @ {}'.format(n, strftime("%Y%m%d-%H%M")))
    
    # Ждём 4 часа
    sleep(60*60*4)
    print('sleep finished.....')

اسکرپٹ کا ٹیسٹ رن ایسا ہی لگتا ہے۔
Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون
اسکرپٹ کا ٹیسٹ رن

کے نتائج

اگر آپ نے اسے یہاں تک پہنچایا ہے، مبارک ہو! اب آپ کے پاس ایک کام کرنے والا ویب سکریپر ہے، حالانکہ میں اسے بہتر بنانے کے بہت سے طریقے دیکھ سکتا ہوں۔ مثال کے طور پر، اسے Twilio کے ساتھ مربوط کیا جا سکتا ہے تاکہ یہ ای میلز کے بجائے ٹیکسٹ پیغامات بھیجے۔ آپ متعدد سرورز سے بیک وقت نتائج حاصل کرنے کے لیے VPN یا کچھ اور استعمال کر سکتے ہیں۔ وقتاً فوقتاً سائٹ استعمال کرنے والے کو چیک کرنے میں بھی مسئلہ پیدا ہوتا ہے کہ آیا وہ کوئی شخص ہے، لیکن یہ مسئلہ بھی حل کیا جا سکتا ہے۔ کسی بھی صورت میں، اب آپ کے پاس ایک بنیاد ہے جسے آپ چاہیں تو بڑھا سکتے ہیں۔ مثال کے طور پر، یقینی بنائیں کہ ایکسل فائل صارف کو ای میل کے منسلکہ کے طور پر بھیجی گئی ہے۔

Python - سفر کرنا پسند کرنے والوں کے لیے سستے ہوائی ٹکٹ تلاش کرنے میں ایک معاون

سروے میں صرف رجسٹرڈ صارفین ہی حصہ لے سکتے ہیں۔ سائن ان، برائے مہربانی.

کیا آپ ویب سکریپنگ ٹیکنالوجیز استعمال کرتے ہیں؟

  • جی ہاں

  • کوئی

8 صارفین نے ووٹ دیا۔ 1 صارف نے پرہیز کیا۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں