Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi

Tarjimasi bugun biz e'lon qilayotgan maqola muallifining aytishicha, uning maqsadi Pythonda Selenium yordamida aviachiptalar narxini qidiradigan veb-skreperni ishlab chiqish haqida gapirishdir. Chiptalarni qidirishda moslashuvchan sanalar qo'llaniladi (belgilangan sanalarga nisbatan +-3 kun). Skreper qidiruv natijalarini Excel faylida saqlaydi va qidiruvni amalga oshirgan odamga topilgan narsalarning qisqacha mazmuni bilan elektron pochta xabarini yuboradi. Ushbu loyihaning maqsadi sayohatchilarga eng yaxshi takliflarni topishga yordam berishdir.

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi

Agar materialni tushunganingizda, o'zingizni yo'qolgandek his qilsangiz, bir ko'z tashlang bu maqola.

Biz nimani qidiramiz?

Siz bu yerda tasvirlangan tizimdan xohlaganingizcha foydalanishingiz mumkin. Masalan, men undan hafta oxiri sayohatlari va ona shahrimga chiptalarni qidirishda foydalanardim. Agar siz foydali chiptalarni topishga jiddiy yondashsangiz, skriptni serverda ishga tushirishingiz mumkin (oddiy server, oyiga 130 rubl uchun, bunga juda mos keladi) va kuniga bir yoki ikki marta ishlashiga ishonch hosil qiling. Qidiruv natijalari sizga elektron pochta orqali yuboriladi. Bundan tashqari, men hamma narsani skript Dropbox papkasida qidiruv natijalari bilan Excel faylini saqlashi uchun sozlashni tavsiya qilaman, bu sizga bunday fayllarni istalgan joydan va istalgan vaqtda ko'rish imkonini beradi.

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Men hali xatoli tariflarni topmadim, lekin menimcha, bu mumkin

Qidirayotganda, yuqorida aytib o'tilganidek, "moslashuvchan sana" ishlatiladi; skript berilgan sanadan keyin uch kun ichida bo'lgan takliflarni topadi. Skriptni ishga tushirishda u faqat bitta yo'nalishda takliflarni qidirsa ham, uni bir nechta parvoz yo'nalishlari bo'yicha ma'lumotlarni to'plashi uchun o'zgartirish oson. Uning yordami bilan siz hatto noto'g'ri tariflarni qidirishingiz mumkin, bunday topilmalar juda qiziqarli bo'lishi mumkin.

Nega sizga boshqa veb-skreper kerak?

Men birinchi marta veb-qirqishni boshlaganimda, rostini aytsam, men bunga unchalik qiziqmasdim. Men bashoratli modellashtirish, moliyaviy tahlil va, ehtimol, matnlarning hissiy ranglarini tahlil qilish sohasida ko'proq loyihalarni amalga oshirishni xohlardim. Ammo ma'lum bo'lishicha, veb-saytlardan ma'lumotlarni to'playdigan dasturni qanday yaratishni aniqlash juda qiziq edi. Men ushbu mavzuni o'rganib chiqqach, men veb-qirqish Internetning "motori" ekanligini angladim.

Bu juda dadil bayonot deb o'ylashingiz mumkin. Ammo Google Larri Peyj Java va Python yordamida yaratilgan veb-skreper bilan boshlanganini hisobga oling. Google robotlari Internetni o'rganib, o'z foydalanuvchilarini savollariga eng yaxshi javoblar bilan ta'minlashga harakat qilmoqda. Veb-qirqish cheksiz maqsadlarga ega va agar siz Data Science-da boshqa narsaga qiziqsangiz ham, tahlil qilishingiz kerak bo'lgan ma'lumotlarni olish uchun sizga ba'zi bir qirqish ko'nikmalari kerak bo'ladi.

Men bu erda qo'llaniladigan ba'zi texnikalarni ajoyib tarzda topdim kitob men yaqinda sotib olgan veb-qirqish haqida. Unda siz o'rgangan narsalarni amaliy qo'llash uchun ko'plab oddiy misollar va g'oyalar mavjud. Bundan tashqari, reCaptcha tekshiruvlarini chetlab o'tish bo'yicha juda qiziqarli bob mavjud. Bu men uchun yangilik bo'ldi, chunki men bunday muammolarni hal qilish uchun maxsus vositalar va hatto butun xizmatlar mavjudligini ham bilmasdim.

Sayohat qilishni yoqtirasizmi?!

Ushbu bo'limning sarlavhasida berilgan oddiy va juda zararsiz savolga siz ko'pincha ijobiy javobni eshitishingiz mumkin, u so'ralgan odamning sayohatlaridan bir nechta hikoyalar bilan birga keladi. Ko'pchiligimiz sayohat qilish yangi madaniy muhitlarga sho'ng'ish va dunyoqarashingizni kengaytirishning ajoyib usuli ekanligiga rozi bo'lamiz. Ammo, agar siz kimdandir aviachiptalarni qidirishni yoqtirasizmi, deb so'rasangiz, javob u qadar ijobiy bo'lmasligiga aminman. Aslida, Python bu erda bizga yordam beradi.

Aviachiptalar bo'yicha ma'lumotlarni qidirish tizimini yaratish yo'lida hal qilishimiz kerak bo'lgan birinchi vazifa - biz ma'lumot oladigan mos platformani tanlash. Bu muammoni hal qilish men uchun oson bo'lmadi, lekin oxirida men Kayak xizmatini tanladim. Men Momondo, Skyscanner, Expedia va boshqa bir qancha xizmatlarni sinab ko'rdim, ammo bu resurslardagi robotlarni himoya qilish mexanizmlari o'tib bo'lmas edi. Men svetoforlar, piyodalar o'tish joylari va velosipedlar bilan shug'ullanishim kerak bo'lgan bir necha urinishlardan so'ng, tizimlarni o'zimning odam ekanligimga ishontirishga harakat qilgandan so'ng, juda ko'p sahifalar yuklangan bo'lsa ham, kayak menga eng mos keladi, deb qaror qildim. qisqa vaqt ichida va tekshiruvlar ham boshlanadi. Men botni 4 dan 6 soatgacha bo'lgan vaqt oralig'ida saytga so'rovlar yuborishga muvaffaq bo'ldim va hammasi yaxshi ishladi. Vaqti-vaqti bilan Kayak bilan ishlashda qiyinchiliklar paydo bo'ladi, lekin agar ular sizni cheklar bilan bezovta qila boshlasa, siz ularni qo'lda hal qilishingiz va keyin botni ishga tushirishingiz yoki bir necha soat kutishingiz kerak va tekshiruvlar to'xtashi kerak. Agar kerak bo'lsa, kodni boshqa platformaga osongina moslashingiz mumkin va agar shunday qilsangiz, sharhlarda xabar berishingiz mumkin.

Agar siz endigina veb-qirqish bilan shug'ullanayotgan bo'lsangiz va ba'zi veb-saytlar nima uchun bu bilan kurashayotganini bilmasangiz, unda bu sohadagi birinchi loyihangizni boshlashdan oldin o'zingizga yaxshilik qiling va "veb qirqish odob-axloqi" so'zlari bo'yicha Google qidiruvini bajaring. . Tajribalaringiz siz o'ylaganingizdan tezroq tugashi mumkin, agar siz veb-saytlarni noto'g'ri qirib tashlasangiz.

Ishga kirishish

Bizning veb-kazıyıcı kodimizda nima sodir bo'lishi haqida umumiy ma'lumot:

  • Kerakli kutubxonalarni import qiling.
  • Google Chrome yorlig'ini ochish.
  • Chiptalarni qidirishda foydalaniladigan shaharlar va sanalarni uzatib, botni ishga tushiradigan funksiyani chaqiring.
  • Bu funksiya eng yaxshilari boʻyicha saralangan birinchi qidiruv natijalarini oladi va koʻproq natijalarni yuklash uchun tugmani bosadi.
  • Boshqa funktsiya butun sahifadan ma'lumotlarni to'playdi va ma'lumotlar ramkasini qaytaradi.
  • Oldingi ikki bosqich chipta narxi (arzon) va parvoz tezligi (eng tez) bo'yicha saralash turlari yordamida amalga oshiriladi.
  • Skript foydalanuvchisiga chiptalar narxlari (eng arzon chiptalar va o'rtacha narx) haqida qisqacha ma'lumotni o'z ichiga olgan elektron pochta xabari yuboriladi va yuqorida qayd etilgan uchta ko'rsatkich bo'yicha saralangan ma'lumotlar ramkasi Excel fayli sifatida saqlanadi.
  • Yuqoridagi barcha harakatlar belgilangan vaqtdan keyin tsiklda amalga oshiriladi.

Shuni ta'kidlash kerakki, har bir Selenium loyihasi veb-drayverdan boshlanadi. Men foydalanaman Chromedriver, Men Google Chrome bilan ishlayman, lekin boshqa variantlar ham bor. PhantomJS va Firefox ham mashhur. Drayvni yuklab olgandan so'ng, uni tegishli papkaga joylashtirishingiz kerak va bu uni ishlatishga tayyorgarlikni yakunlaydi. Skriptimizning birinchi satrlari yangi Chrome yorlig'ini ochadi.

Yodda tutingki, men o'z hikoyamda aviachiptalarda katta chegirmalarni topish uchun yangi ufqlarni ochishga harakat qilmayman. Bunday takliflarni qidirishning ancha ilg'or usullari mavjud. Men ushbu materialning o'quvchilariga ushbu muammoni hal qilishning oddiy, ammo amaliy usulini taklif qilmoqchiman.

Mana biz yuqorida gaplashgan kod.

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)

Kodning boshida siz butun loyihamizda ishlatiladigan paketlarni import qilish buyruqlarini ko'rishingiz mumkin. Shunday qilib, randint yangi qidiruv operatsiyasini boshlashdan oldin botni tasodifiy soniyalar davomida "uxlab qoldirish" uchun ishlatiladi. Odatda, birorta ham bot busiz qila olmaydi. Yuqoridagi kodni ishga tushirsangiz, bot saytlar bilan ishlashda foydalanadigan Chrome oynasi ochiladi.

Keling, kichik tajriba o'tkazamiz va kayak.com veb-saytini alohida oynada ochamiz. Biz uchadigan shaharni va bormoqchi bo'lgan shaharni, shuningdek parvoz sanalarini tanlaymiz. Sanalarni tanlashda +-3 kun oralig'idan foydalanilganligiga ishonch hosil qiling. Men sayt bunday so'rovlarga javoban nima ishlab chiqarishini hisobga olgan holda kodni yozdim. Agar, masalan, siz chiptalarni faqat belgilangan sanalar uchun qidirishingiz kerak bo'lsa, unda siz bot kodini o'zgartirishingiz kerak bo'lishi ehtimoli yuqori. Kod haqida gapirganda, men tegishli tushuntirishlar beraman, lekin agar siz chalkashib ketsangiz, menga xabar bering.

Endi qidiruv tugmasini bosing va manzil satridagi havolaga qarang. Bu o'zgaruvchi e'lon qilingan quyidagi misolda men foydalanadigan havolaga o'xshash bo'lishi kerak kayakURL manzilini saqlaydigan , va usul ishlatiladi get veb haydovchi. Qidiruv tugmasini bosgandan so'ng natijalar sahifada paydo bo'lishi kerak.

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Men buyruqni ishlatganimda get bir necha daqiqa ichida ikki yoki uch martadan ko'proq, reCaptcha yordamida tekshirishni yakunlashimni so'rashdi. Siz ushbu tekshiruvni qo'lda topshirishingiz va tizim yangi tekshirishni o'tkazishga qaror qilmaguncha tajribani davom ettirishingiz mumkin. Skriptni sinab ko'rganimda, birinchi qidiruv seansi har doim muammosiz o'tgandek tuyuldi, shuning uchun agar siz kod bilan tajriba o'tkazmoqchi bo'lsangiz, vaqti-vaqti bilan qo'lda tekshirishingiz va qidiruv seanslari orasidagi uzoq vaqt oralig'idan foydalanib kodni ishga tushirishga ruxsat berishingiz kerak bo'ladi. Va agar siz bu haqda o'ylab ko'rsangiz, qidiruv operatsiyalari o'rtasida 10 daqiqalik oraliqda olingan chiptalar narxi to'g'risida ma'lumotga muhtoj bo'lishi dargumon.

XPath yordamida sahifa bilan ishlash

Shunday qilib, biz oyna ochdik va saytni yukladik. Narxlar va boshqa ma'lumotlarni olish uchun XPath texnologiyasi yoki CSS selektorlaridan foydalanishimiz kerak. Men XPath-dan foydalanishga qaror qildim va CSS selektorlaridan foydalanishga ehtiyoj sezmadim, lekin bu tarzda ishlash juda mumkin. XPath yordamida sahifa bo'ylab navigatsiya qilish qiyin bo'lishi mumkin va hatto men tavsiflagan usullardan foydalansangiz ham bu sahifa kodidan tegishli identifikatorlarni nusxalashni o'z ichiga olgan maqola, men bu, aslida, kerakli elementlarga kirishning maqbul usuli emasligini angladim. Aytgancha, ichida bu Kitobda XPath va CSS selektorlari yordamida sahifalar bilan ishlash asoslarining ajoyib tavsifi berilgan. Tegishli veb-drayveri usuli shunday ko'rinadi.

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Shunday qilib, keling, bot ustida ishlashni davom ettiramiz. Eng arzon chiptalarni tanlash uchun dasturning imkoniyatlaridan foydalanamiz. Quyidagi rasmda XPath selektor kodi qizil rang bilan ta'kidlangan. Kodni ko'rish uchun siz qiziqqan sahifa elementini sichqonchaning o'ng tugmasi bilan bosishingiz va paydo bo'lgan menyudan Tekshirish buyrug'ini tanlashingiz kerak. Ushbu buyruq turli xil sahifa elementlari uchun chaqirilishi mumkin, ularning kodi kodni ko'rish vositasida ko'rsatiladi va ta'kidlanadi.

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Sahifa kodini ko'rish

Koddan selektorlarni nusxalashning kamchiliklari haqidagi mulohazalarimni tasdiqlash uchun quyidagi xususiyatlarga e'tibor bering.

Kodni nusxalashda siz quyidagilarni olasiz:

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

Shunga o'xshash narsalarni nusxalash uchun siz qiziqqan kod bo'limiga sichqonchaning o'ng tugmachasini bosishingiz va paydo bo'lgan menyudan Nusxalash > XPathni nusxalash buyrug'ini tanlashingiz kerak.

Men eng arzon tugmani belgilash uchun foydalanardim:

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

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Buyruqni nusxalash > XPath-ni nusxalash

Ikkinchi variant ancha sodda ko'rinishi aniq. Foydalanilganda, u atributga ega bo'lgan elementni qidiradi data-codega teng price. Birinchi variantdan foydalanganda element qidiriladi id ga teng wtKI-price_aTab, va elementga XPath yo'li o'xshaydi /div[1]/div/div/div[1]/div/span/span. Sahifaga bunday XPath so'rovi yordam beradi, lekin faqat bir marta. Men buni hozir aytishim mumkin id keyingi safar sahifa yuklanganda o'zgaradi. Belgilar ketma-ketligi wtKI sahifa har safar yuklanganda dinamik ravishda o'zgaradi, shuning uchun uni ishlatadigan kod keyingi sahifani qayta yuklagandan keyin foydasiz bo'ladi. Shunday qilib, XPathni tushunish uchun biroz vaqt ajrating. Bu bilim sizga yaxshi xizmat qiladi.

Shunga qaramay, shuni ta'kidlash kerakki, XPath selektorlarini nusxalash juda oddiy saytlar bilan ishlashda foydali bo'lishi mumkin va agar sizga bu qulay bo'lsa, unda hech qanday yomon narsa yo'q.

Keling, barcha qidiruv natijalarini ro'yxat ichida bir necha qatorda olishingiz kerak bo'lsa, nima qilish kerakligini o'ylab ko'raylik. Juda oddiy. Har bir natija sinfga ega ob'ekt ichida bo'ladi resultWrapper. Barcha natijalarni yuklash quyida ko'rsatilganga o'xshash tsiklda amalga oshirilishi mumkin.

Shuni ta'kidlash kerakki, agar siz yuqoridagilarni tushunsangiz, biz tahlil qiladigan kodning ko'p qismini osongina tushunishingiz kerak. Ushbu kod ishlayotganda, biz qandaydir yo'lni belgilash mexanizmidan (XPath) foydalanib, bizga kerak bo'lgan narsaga (aslida, natija o'ralgan elementga) kiramiz. Bu element matnini olish va uni ma'lumotlarni o'qish mumkin bo'lgan ob'ektga joylashtirish uchun amalga oshiriladi (birinchi marta foydalanilgan). flight_containers, keyin - flights_list).

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Birinchi uchta satr ko'rsatiladi va biz kerak bo'lgan hamma narsani aniq ko'rishimiz mumkin. Biroq, bizda ma'lumot olishning qiziqarli usullari mavjud. Har bir elementdan ma'lumotlarni alohida olishimiz kerak.

Ishga bor!

Funktsiyani yozishning eng oson yo'li qo'shimcha natijalarni yuklashdir, shuning uchun biz shu erdan boshlaymiz. Tekshirishga olib keladigan xizmatda shubha tug'dirmasdan, dastur ma'lumot oladigan parvozlar sonini maksimal darajada oshirishni xohlayman, shuning uchun sahifa har ko'rsatilganda "Ko'proq natijalarni yuklash" tugmasini bir marta bosaman. Ushbu kodda siz blokga e'tibor berishingiz kerak try, men qo'shdim, chunki ba'zida tugma to'g'ri yuklanmaydi. Agar siz ham bunga duch kelsangiz, funktsiya kodida ushbu funktsiyaga qo'ng'iroqlarni izohlang start_kayak, biz quyida ko'rib chiqamiz.

# Загрузка большего количества результатов для того, чтобы максимизировать объём собираемых данных
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

Endi, ushbu funktsiyani uzoq vaqt tahlil qilgandan so'ng (ba'zan men o'zimni o'zimdan tortib olishim mumkin), biz sahifani qirib tashlaydigan funktsiyani e'lon qilishga tayyormiz.

Men allaqachon chaqirilgan quyidagi funktsiyada zarur bo'lgan ko'p narsalarni to'pladim page_scrape. Ba'zan qaytarilgan yo'l ma'lumotlari birlashtiriladi, shuning uchun uni ajratish uchun oddiy usuldan foydalanaman. Misol uchun, o'zgaruvchilarni birinchi marta ishlatganimda section_a_list и section_b_list. Funktsiyamiz ma'lumotlar ramkasini qaytaradi flights_df, bu turli xil ma'lumotlarni saralash usullaridan olingan natijalarni ajratish va keyinchalik ularni birlashtirish imkonini beradi.

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

Kod tushunarli bo'lishi uchun o'zgaruvchilarni nomlashga harakat qildim. O'zgaruvchilar bilan boshlanishini unutmang a yo'lning birinchi bosqichiga tegishli va b - ikkinchisiga. Keling, keyingi funktsiyaga o'tamiz.

Qo'llab-quvvatlash mexanizmlari

Endi bizda qo‘shimcha qidiruv natijalarini yuklash imkonini beruvchi funksiya va shu natijalarni qayta ishlash funksiyasi mavjud. Ushbu maqola shu erda tugashi mumkin edi, chunki bu ikki funktsiya o'zingiz ochishingiz mumkin bo'lgan sahifalarni qirib tashlash uchun kerak bo'lgan hamma narsani ta'minlaydi. Ammo biz yuqorida muhokama qilingan ba'zi yordamchi mexanizmlarni hali ko'rib chiqmadik. Masalan, bu elektron pochta va boshqa narsalarni yuborish uchun kod. Bularning barchasini funksiyada topish mumkin start_kayak, biz hozir ko'rib chiqamiz.

Bu funksiya shaharlar va sanalar haqida maʼlumot talab qiladi. Ushbu ma'lumotlardan foydalanib, u o'zgaruvchida havola hosil qiladi kayak, bu sizni so'rovga eng yaxshi mosligi bo'yicha saralangan qidiruv natijalarini o'z ichiga olgan sahifaga olib borish uchun ishlatiladi. Birinchi qirib tashlash seansidan so'ng biz sahifaning yuqori qismidagi jadvaldagi narxlar bilan ishlaymiz. Ya'ni, biz minimal chipta narxini va o'rtacha narxni topamiz. Bularning barchasi, sayt tomonidan chiqarilgan bashorat bilan birga, elektron pochta orqali yuboriladi. Sahifada tegishli jadval yuqori chap burchakda bo'lishi kerak. Aytgancha, ushbu jadval bilan ishlash aniq sanalar yordamida qidirishda xatolikka olib kelishi mumkin, chunki bu holda jadval sahifada ko'rsatilmaydi.

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.....')

Men ushbu skriptni Outlook hisob qaydnomasi (hotmail.com) yordamida sinab ko'rdim. Men uni Gmail hisob qaydnomasi bilan to'g'ri ishlashi uchun sinab ko'rmadim, bu elektron pochta tizimi juda mashhur, ammo ko'plab mumkin bo'lgan variantlar mavjud. Agar siz Hotmail hisob qaydnomasidan foydalansangiz, hamma narsa ishlashi uchun kodga ma'lumotlaringizni kiritish kifoya.

Agar siz ushbu funktsiya uchun kodning muayyan bo'limlarida aniq nima qilinayotganini tushunmoqchi bo'lsangiz, ularni nusxalashingiz va ular bilan tajriba o'tkazishingiz mumkin. Kod bilan tajriba qilish - uni chinakam tushunishning yagona yo'li.

Tayyor tizim

Endi biz gaplashgan hamma narsani bajarganimizdan so'ng, biz funktsiyalarimizni chaqiradigan oddiy tsiklni yaratishimiz mumkin. Skript foydalanuvchidan shaharlar va sanalar haqidagi ma'lumotlarni so'raydi. Skriptni doimiy ravishda qayta ishga tushirish bilan sinovdan o'tayotganda, siz ushbu ma'lumotlarni har safar qo'lda kiritishni xohlamasligingiz dargumon, shuning uchun test davomida tegishli qatorlarni ularning ostidagilarni izohlash orqali izohlash mumkin, bunda ma'lumotlar kerak bo'ladi. skript qattiq kodlangan.

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.....')

Skriptni sinovdan o'tkazish shunday ko'rinadi.
Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi
Skriptni sinovdan o'tkazish

natijalar

Agar shu paytgacha erishgan bo'lsangiz, tabriklaymiz! Endi sizda ishlaydigan veb-skreper bor, garchi men uni yaxshilashning ko'plab usullarini ko'rsam ham. Masalan, u Twilio bilan birlashtirilishi mumkin, shunda u elektron pochta o'rniga matnli xabarlarni yuboradi. Bir vaqtning o'zida bir nechta serverlardan natijalarni olish uchun VPN yoki boshqa narsadan foydalanishingiz mumkin. Shuningdek, vaqti-vaqti bilan sayt foydalanuvchisini shaxs yoki yo'qligini tekshirish bilan bog'liq muammolar mavjud, ammo bu muammoni ham hal qilish mumkin. Har qanday holatda, endi sizda, agar xohlasangiz, kengaytirishingiz mumkin bo'lgan baza bor. Misol uchun, Excel fayli foydalanuvchiga elektron pochtaga ilova sifatida yuborilganligiga ishonch hosil qiling.

Python - sayohat qilishni yaxshi ko'radiganlar uchun arzon aviachiptalarni topishda yordamchi

So'rovda faqat ro'yxatdan o'tgan foydalanuvchilar ishtirok etishlari mumkin. tizimga kirishiltimos.

Veb-qirqish texnologiyalaridan foydalanasizmi?

  • ekan

  • yo'q

8 ta foydalanuvchi ovoz berdi. 1 foydalanuvchi betaraf qoldi.

Manba: www.habr.com

a Izoh qo'shish