पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं

लेख के लेखक, जिसका अनुवाद हम आज प्रकाशित कर रहे हैं, का कहना है कि इसका लक्ष्य सेलेनियम का उपयोग करके पायथन में एक वेब स्क्रैपर के विकास के बारे में बात करना है, जो एयरलाइन टिकट की कीमतों की खोज करता है। टिकटों की खोज करते समय, लचीली तिथियों का उपयोग किया जाता है (निर्दिष्ट तिथियों के सापेक्ष +-3 दिन)। स्क्रैपर खोज परिणामों को एक एक्सेल फ़ाइल में सहेजता है और खोज करने वाले व्यक्ति को जो मिला उसका सारांश के साथ एक ईमेल भेजता है। इस परियोजना का लक्ष्य यात्रियों को सर्वोत्तम सौदे खोजने में मदद करना है।

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं

यदि, सामग्री को समझते समय, आप खोया हुआ महसूस करते हैं, तो एक नज़र डालें यह लेख।

हम क्या खोज कर रहे हैं?

आप यहां वर्णित प्रणाली का अपनी इच्छानुसार उपयोग करने के लिए स्वतंत्र हैं। उदाहरण के लिए, मैंने इसका उपयोग सप्ताहांत पर्यटन और अपने गृहनगर के टिकट खोजने के लिए किया। यदि आप लाभदायक टिकट ढूंढने के बारे में गंभीर हैं, तो आप सर्वर पर स्क्रिप्ट चला सकते हैं (सरल)। सेवक, प्रति माह 130 रूबल के लिए, इसके लिए काफी उपयुक्त है) और सुनिश्चित करें कि यह दिन में एक या दो बार चलता है। खोज परिणाम आपको ईमेल द्वारा भेजे जाएंगे। इसके अलावा, मैं सब कुछ सेट करने की सलाह देता हूं ताकि स्क्रिप्ट ड्रॉपबॉक्स फ़ोल्डर में खोज परिणामों के साथ एक एक्सेल फ़ाइल को सहेज सके, जो आपको ऐसी फ़ाइलों को कहीं से भी और किसी भी समय देखने की अनुमति देगा।

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
मुझे अभी तक त्रुटियों वाले टैरिफ नहीं मिले हैं, लेकिन मुझे लगता है कि यह संभव है

खोज करते समय, जैसा कि पहले ही उल्लेख किया गया है, एक "लचीली तारीख" का उपयोग किया जाता है; स्क्रिप्ट ऐसे ऑफ़र ढूंढती है जो दी गई तारीखों के तीन दिनों के भीतर होते हैं। हालाँकि स्क्रिप्ट चलाते समय, यह केवल एक दिशा में ऑफ़र खोजता है, इसे संशोधित करना आसान है ताकि यह कई उड़ान दिशाओं पर डेटा एकत्र कर सके। इसकी मदद से आप गलत टैरिफ की तलाश भी कर सकते हैं, ऐसी खोजें बहुत दिलचस्प हो सकती हैं।

आपको दूसरे वेब स्क्रैपर की आवश्यकता क्यों है?

जब मैंने पहली बार वेब स्क्रैपिंग शुरू की, तो ईमानदारी से कहूं तो मेरी इसमें विशेष रुचि नहीं थी। मैं पूर्वानुमानित मॉडलिंग, वित्तीय विश्लेषण और, संभवतः, ग्रंथों के भावनात्मक रंग का विश्लेषण करने के क्षेत्र में और अधिक परियोजनाएं करना चाहता था। लेकिन यह पता चला कि यह पता लगाना बहुत दिलचस्प था कि वेबसाइटों से डेटा एकत्र करने वाला प्रोग्राम कैसे बनाया जाए। जैसे ही मैंने इस विषय पर गहराई से विचार किया, मुझे एहसास हुआ कि वेब स्क्रैपिंग इंटरनेट का "इंजन" है।

आप सोच सकते हैं कि यह बहुत साहसिक बयान है। लेकिन विचार करें कि Google की शुरुआत एक वेब स्क्रैपर से हुई जिसे लैरी पेज ने जावा और पायथन का उपयोग करके बनाया था। Google रोबोट इंटरनेट की खोज कर रहे हैं, अपने उपयोगकर्ताओं को उनके प्रश्नों के सर्वोत्तम उत्तर प्रदान करने का प्रयास कर रहे हैं। वेब स्क्रैपिंग के अंतहीन उपयोग हैं, और भले ही आप डेटा साइंस में किसी और चीज़ में रुचि रखते हों, आपको विश्लेषण करने के लिए आवश्यक डेटा प्राप्त करने के लिए कुछ स्क्रैपिंग कौशल की आवश्यकता होगी।

मुझे यहां इस्तेमाल की गई कुछ तकनीकें अद्भुत लगीं किताब वेब स्क्रैपिंग के बारे में, जिसे मैंने हाल ही में हासिल किया है। आपने जो सीखा है उसके व्यावहारिक अनुप्रयोग के लिए इसमें कई सरल उदाहरण और विचार शामिल हैं। इसके अलावा, रीकैप्चा जांच को बायपास करने पर एक बहुत ही दिलचस्प अध्याय है। यह मेरे लिए एक समाचार के रूप में आया, क्योंकि मुझे यह भी नहीं पता था कि ऐसी समस्याओं को हल करने के लिए विशेष उपकरण और यहां तक ​​कि संपूर्ण सेवाएँ भी हैं।

क्या आप यात्रा करना पसंद करते हैं?!

इस खंड के शीर्षक में पूछे गए सरल और हानिरहित प्रश्न के लिए, आप अक्सर एक सकारात्मक उत्तर सुन सकते हैं, जिसके साथ उस व्यक्ति की यात्रा की कुछ कहानियाँ भी शामिल होती हैं जिनसे यह पूछा गया था। हममें से अधिकांश लोग इस बात से सहमत होंगे कि यात्रा नए सांस्कृतिक वातावरण में खुद को डुबोने और अपने क्षितिज को व्यापक बनाने का एक शानदार तरीका है। हालाँकि, यदि आप किसी से पूछते हैं कि क्या उन्हें एयरलाइन टिकट खोजना पसंद है, तो मुझे यकीन है कि उत्तर इतना सकारात्मक नहीं होगा। वास्तव में, पायथन यहां हमारी सहायता के लिए आता है।

हवाई टिकटों पर जानकारी खोजने के लिए एक प्रणाली बनाने के रास्ते पर हमें जो पहला काम हल करना होगा, वह एक उपयुक्त मंच का चयन करना होगा जहां से हम जानकारी लेंगे। इस समस्या को हल करना मेरे लिए आसान नहीं था, लेकिन अंत में मैंने कयाक सेवा को चुना। मैंने मोमोन्डो, स्काईस्कैनर, एक्सपीडिया और कुछ अन्य की सेवाओं की कोशिश की, लेकिन इन संसाधनों पर रोबोट सुरक्षा तंत्र अभेद्य थे। कई प्रयासों के बाद, जिसके दौरान मुझे ट्रैफिक लाइट, पैदल यात्री क्रॉसिंग और साइकिल से निपटना पड़ा, सिस्टम को यह समझाने की कोशिश की कि मैं इंसान हूं, मैंने फैसला किया कि कयाक मेरे लिए सबसे उपयुक्त है, इस तथ्य के बावजूद कि भले ही बहुत सारे पृष्ठ लोड किए गए हों कुछ ही देर में जांच भी शुरू हो जाती है. मैं बॉट को 4 से 6 घंटे के अंतराल पर साइट पर अनुरोध भेजने में कामयाब रहा, और सब कुछ ठीक रहा। समय-समय पर, कयाक के साथ काम करते समय कठिनाइयाँ आती हैं, लेकिन यदि वे आपको चेक से परेशान करना शुरू कर देते हैं, तो आपको या तो उनसे मैन्युअल रूप से निपटना होगा और फिर बॉट लॉन्च करना होगा, या कुछ घंटों तक प्रतीक्षा करनी होगी और चेक बंद हो जाना चाहिए। यदि आवश्यक हो, तो आप आसानी से किसी अन्य प्लेटफ़ॉर्म के लिए कोड को अनुकूलित कर सकते हैं, और यदि आप ऐसा करते हैं, तो आप टिप्पणियों में इसकी रिपोर्ट कर सकते हैं।

यदि आप अभी वेब स्क्रैपिंग के साथ शुरुआत कर रहे हैं और नहीं जानते कि कुछ वेबसाइटें इसमें क्यों संघर्ष करती हैं, तो इस क्षेत्र में अपना पहला प्रोजेक्ट शुरू करने से पहले, अपने आप पर एक एहसान करें और "वेब स्क्रैपिंग शिष्टाचार" शब्दों पर Google खोज करें। . यदि आप नासमझी से वेब स्क्रैपिंग करते हैं तो आपके प्रयोग आपकी सोच से जल्दी समाप्त हो सकते हैं।

प्रारंभ करना

हमारे वेब स्क्रैपर कोड में क्या होगा इसका एक सामान्य अवलोकन यहां दिया गया है:

  • आवश्यक पुस्तकालय आयात करें.
  • Google Chrome टैब खोलना.
  • एक फ़ंक्शन को कॉल करें जो बॉट शुरू करता है, इसे उन शहरों और तारीखों को पास करता है जिनका उपयोग टिकट खोजते समय किया जाएगा।
  • यह फ़ंक्शन पहले खोज परिणामों को लेता है, सर्वोत्तम के आधार पर क्रमबद्ध करता है, और अधिक परिणाम लोड करने के लिए एक बटन पर क्लिक करता है।
  • एक अन्य फ़ंक्शन पूरे पृष्ठ से डेटा एकत्र करता है और एक डेटा फ़्रेम लौटाता है।
  • पिछले दो चरणों को टिकट की कीमत (सस्ते) और उड़ान की गति (सबसे तेज़) के अनुसार क्रमबद्ध प्रकारों का उपयोग करके निष्पादित किया जाता है।
  • स्क्रिप्ट के उपयोगकर्ता को एक ईमेल भेजा जाता है जिसमें टिकट की कीमतों (सबसे सस्ते टिकट और औसत मूल्य) का सारांश होता है, और उपरोक्त तीन संकेतकों द्वारा क्रमबद्ध जानकारी वाला एक डेटा फ्रेम एक्सेल फ़ाइल के रूप में सहेजा जाता है।
  • उपरोक्त सभी क्रियाएं एक निश्चित समय के बाद एक चक्र में की जाती हैं।

यह ध्यान दिया जाना चाहिए कि प्रत्येक सेलेनियम प्रोजेक्ट एक वेब ड्राइवर से शुरू होता है। मैं उपयोग करता हूं क्रोमड्राइवर, मैं Google Chrome के साथ काम करता हूं, लेकिन अन्य विकल्प भी हैं। फैंटमजेएस और फायरफॉक्स भी लोकप्रिय हैं। ड्राइवर को डाउनलोड करने के बाद, आपको इसे उपयुक्त फ़ोल्डर में रखना होगा, और यह इसके उपयोग की तैयारी पूरी करता है। हमारी स्क्रिप्ट की पहली पंक्तियाँ एक नया Chrome टैब खोलती हैं।

ध्यान रखें कि अपनी कहानी में मैं हवाई टिकटों पर बढ़िया सौदे खोजने के लिए नए क्षितिज खोलने की कोशिश नहीं कर रहा हूँ। ऐसे ऑफ़र खोजने के बहुत अधिक उन्नत तरीके मौजूद हैं। मैं इस सामग्री के पाठकों को इस समस्या को हल करने का एक सरल लेकिन व्यावहारिक तरीका प्रदान करना चाहता हूं।

यहां वह कोड है जिसके बारे में हमने ऊपर बात की थी।

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 वेब ड्राइवर. खोज बटन पर क्लिक करने के बाद, परिणाम पृष्ठ पर दिखाई देने चाहिए।

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
जब मैंने कमांड का उपयोग किया get कुछ ही मिनटों के भीतर दो या तीन से अधिक बार, मुझे रीकैप्चा का उपयोग करके सत्यापन पूरा करने के लिए कहा गया। आप इस चेक को मैन्युअल रूप से पास कर सकते हैं और तब तक प्रयोग जारी रख सकते हैं जब तक सिस्टम एक नया चेक चलाने का निर्णय नहीं ले लेता। जब मैंने स्क्रिप्ट का परीक्षण किया, तो ऐसा लगा कि पहला खोज सत्र हमेशा सुचारू रूप से चला, इसलिए यदि आप कोड के साथ प्रयोग करना चाहते हैं, तो आपको केवल समय-समय पर मैन्युअल रूप से जांच करनी होगी और खोज सत्रों के बीच लंबे अंतराल का उपयोग करके कोड को चलने देना होगा। और, यदि आप इसके बारे में सोचते हैं, तो किसी व्यक्ति को खोज अभियानों के बीच 10 मिनट के अंतराल पर प्राप्त टिकट की कीमतों के बारे में जानकारी की आवश्यकता होने की संभावना नहीं है।

XPath का उपयोग करके एक पेज के साथ कार्य करना

इसलिए, हमने एक विंडो खोली और साइट लोड की। मूल्य निर्धारण और अन्य जानकारी प्राप्त करने के लिए, हमें XPath तकनीक या CSS चयनकर्ताओं का उपयोग करने की आवश्यकता है। मैंने XPath के साथ बने रहने का निर्णय लिया और CSS चयनकर्ताओं का उपयोग करने की आवश्यकता महसूस नहीं की, लेकिन इस तरह से काम करना काफी संभव है। XPath का उपयोग करके किसी पृष्ठ पर नेविगेट करना मुश्किल हो सकता है, और भले ही आप मेरे द्वारा वर्णित तकनीकों का उपयोग करें यह लेख, जिसमें पेज कोड से संबंधित पहचानकर्ताओं की प्रतिलिपि बनाना शामिल था, मुझे एहसास हुआ कि यह वास्तव में, आवश्यक तत्वों तक पहुंचने का इष्टतम तरीका नहीं है। वैसे, में यह पुस्तक XPath और CSS चयनकर्ताओं का उपयोग करके पृष्ठों के साथ काम करने की बुनियादी बातों का उत्कृष्ट विवरण प्रदान करती है। संबंधित वेब ड्राइवर विधि इस तरह दिखती है।

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
तो चलिए बॉट पर काम करना जारी रखें। आइए सबसे सस्ते टिकट चुनने के लिए कार्यक्रम की क्षमताओं का उपयोग करें। निम्नलिखित छवि में, XPath चयनकर्ता कोड को लाल रंग में हाइलाइट किया गया है। कोड देखने के लिए, आपको उस पृष्ठ तत्व पर राइट-क्लिक करना होगा जिसमें आप रुचि रखते हैं और दिखाई देने वाले मेनू से निरीक्षण कमांड का चयन करें। इस कमांड को विभिन्न पेज तत्वों के लिए कॉल किया जा सकता है, जिसका कोड कोड व्यूअर में प्रदर्शित और हाइलाइट किया जाएगा।

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
पेज कोड देखें

कोड से चयनकर्ताओं की प्रतिलिपि बनाने के नुकसान के बारे में मेरे तर्क की पुष्टि पाने के लिए, निम्नलिखित विशेषताओं पर ध्यान दें।

जब आप कोड कॉपी करते हैं तो आपको यह मिलता है:

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

इस तरह की किसी चीज़ को कॉपी करने के लिए, आपको उस कोड के अनुभाग पर राइट-क्लिक करना होगा जिसमें आप रुचि रखते हैं और दिखाई देने वाले मेनू से कॉपी> कॉपी XPath कमांड का चयन करें।

यहां बताया गया है कि मैंने सबसे सस्ते बटन को परिभाषित करने के लिए क्या उपयोग किया है:

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

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
कमांड कॉपी करें > XPath कॉपी करें

यह बिल्कुल स्पष्ट है कि दूसरा विकल्प अधिक सरल दिखता है। जब इसका उपयोग किया जाता है, तो यह एक ऐसे तत्व की खोज करता है जिसमें विशेषता हो 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).

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
पहली तीन पंक्तियाँ प्रदर्शित होती हैं और हम अपनी ज़रूरत की सभी चीज़ें स्पष्ट रूप से देख सकते हैं। हालाँकि, हमारे पास जानकारी प्राप्त करने के और भी दिलचस्प तरीके हैं। हमें प्रत्येक तत्व से अलग से डेटा लेने की आवश्यकता है।

काम करने के लिए मिलता है!

किसी फ़ंक्शन को लिखने का सबसे आसान तरीका अतिरिक्त परिणाम लोड करना है, इसलिए हम यहीं से शुरुआत करेंगे। मैं उन उड़ानों की संख्या को अधिकतम करना चाहूंगा जिनके बारे में कार्यक्रम को जानकारी प्राप्त होती है, सेवा में संदेह पैदा किए बिना जो निरीक्षण की ओर ले जाती है, इसलिए मैं पृष्ठ प्रदर्शित होने पर हर बार एक बार अधिक परिणाम लोड करें बटन पर क्लिक करता हूं। इस कोड में आपको ब्लॉक पर ध्यान देना चाहिए 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.....')

स्क्रिप्ट का परीक्षण रन इस तरह दिखता है।
पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं
स्क्रिप्ट का टेस्ट रन

परिणाम

यदि आप यहां तक ​​पहुंच गए हैं, तो बधाई हो! अब आपके पास एक कार्यशील वेब स्क्रैपर है, हालाँकि मैं इसे सुधारने के कई तरीके पहले से ही देख सकता हूँ। उदाहरण के लिए, इसे ट्विलियो के साथ एकीकृत किया जा सकता है ताकि यह ईमेल के बजाय टेक्स्ट संदेश भेज सके। आप एक साथ कई सर्वरों से परिणाम प्राप्त करने के लिए वीपीएन या किसी अन्य चीज़ का उपयोग कर सकते हैं। साइट उपयोगकर्ता की यह जांच करने में भी समय-समय पर समस्या आती है कि वह कोई व्यक्ति है या नहीं, लेकिन इस समस्या को भी हल किया जा सकता है। किसी भी स्थिति में, अब आपके पास एक आधार है जिसे आप चाहें तो बढ़ा सकते हैं। उदाहरण के लिए, सुनिश्चित करें कि एक एक्सेल फ़ाइल उपयोगकर्ता को ईमेल के अनुलग्नक के रूप में भेजी गई है।

पाइथॉन उन लोगों के लिए सस्ते हवाई टिकट ढूंढने में सहायक है जो यात्रा करना पसंद करते हैं

केवल पंजीकृत उपयोगकर्ता ही सर्वेक्षण में भाग ले सकते हैं। साइन इन करेंकृपया।

क्या आप वेब स्क्रैपिंग तकनीकों का उपयोग करते हैं?

  • Да

  • नहीं

8 उपयोगकर्ताओं ने मतदान किया. 1 उपयोगकर्ता अनुपस्थित रहा.

स्रोत: www.habr.com

एक टिप्पणी जोड़ें