Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian

Penulis artikel, terjemahan yang kami terbitkan hari ini, mengatakan bahwa tujuannya adalah untuk membicarakan tentang pengembangan web scraper dengan Python menggunakan Selenium, yang mencari harga tiket pesawat. Saat mencari tiket, tanggal fleksibel digunakan (+- 3 hari dibandingkan tanggal yang ditentukan). Scraper menyimpan hasil pencarian dalam file Excel dan mengirimkan email kepada orang yang melakukan pencarian dengan ringkasan dari apa yang mereka temukan. Tujuan dari proyek ini adalah membantu wisatawan menemukan penawaran terbaik.

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian

Jika saat memahami materi Anda merasa tersesat, simaklah ini artikel.

Apa yang kita cari?

Anda bebas menggunakan sistem yang dijelaskan di sini sesuai keinginan Anda. Misalnya, saya menggunakannya untuk mencari tur akhir pekan dan tiket ke kampung halaman. Jika Anda serius ingin menemukan tiket yang menguntungkan, Anda dapat menjalankan skrip di server (sederhana server, untuk 130 rubel sebulan, cukup cocok untuk ini) dan pastikan itu berjalan sekali atau dua kali sehari. Hasil pencarian akan dikirimkan kepada Anda melalui email. Selain itu, saya sarankan untuk mengatur semuanya sehingga skrip menyimpan file Excel dengan hasil pencarian di folder Dropbox, yang memungkinkan Anda melihat file tersebut dari mana saja dan kapan saja.

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Saya belum menemukan tarif yang error, tapi menurut saya itu mungkin saja

Saat mencari, seperti yang telah disebutkan, "tanggal fleksibel" digunakan; skrip menemukan penawaran dalam waktu tiga hari dari tanggal yang ditentukan. Meskipun saat menjalankan skrip, ia mencari penawaran hanya dalam satu arah, namun mudah untuk memodifikasinya sehingga dapat mengumpulkan data pada beberapa arah penerbangan. Dengan bantuannya, Anda bahkan dapat mencari tarif yang salah, temuan seperti itu bisa sangat menarik.

Mengapa Anda memerlukan web scraper lain?

Ketika saya pertama kali memulai web scraping, sejujurnya saya tidak terlalu tertarik dengannya. Saya ingin melakukan lebih banyak proyek di bidang pemodelan prediktif, analisis keuangan, dan, mungkin, di bidang analisis pewarnaan emosional teks. Namun ternyata sangat menarik untuk mengetahui cara membuat program yang mengumpulkan data dari website. Saat saya mendalami topik ini, saya menyadari bahwa web scraping adalah “mesin” Internet.

Anda mungkin berpikir pernyataan ini terlalu berani. Namun pertimbangkan bahwa Google memulai dengan web scraper yang dibuat Larry Page menggunakan Java dan Python. Robot Google telah menjelajahi Internet, mencoba memberikan jawaban terbaik atas pertanyaan mereka kepada penggunanya. Pengikisan web memiliki kegunaan yang tidak ada habisnya, dan meskipun Anda tertarik pada hal lain dalam Ilmu Data, Anda memerlukan beberapa keterampilan pengikisan untuk mendapatkan data yang perlu dianalisis.

Saya menemukan beberapa teknik yang digunakan di sini dengan luar biasa buku itu tentang web scraping, yang baru saja saya peroleh. Ini berisi banyak contoh dan ide sederhana untuk penerapan praktis dari apa yang telah Anda pelajari. Selain itu, ada bab yang sangat menarik tentang cara melewati pemeriksaan reCaptcha. Ini menjadi berita baru bagi saya, karena saya bahkan tidak tahu bahwa ada alat khusus dan bahkan layanan lengkap untuk memecahkan masalah seperti itu.

Apakah kamu suka jalan jalan?!

Terhadap pertanyaan sederhana dan tidak berbahaya yang diajukan dalam judul bagian ini, Anda sering kali mendengar jawaban positif, disertai dengan beberapa cerita dari perjalanan orang yang ditanyai. Sebagian besar dari kita setuju bahwa bepergian adalah cara terbaik untuk membenamkan diri dalam lingkungan budaya baru dan memperluas wawasan Anda. Namun, jika Anda bertanya kepada seseorang apakah mereka suka mencari tiket pesawat, saya yakin jawabannya tidak akan terlalu positif. Faktanya, Python membantu kami di sini.

Tugas pertama yang perlu kita selesaikan dalam menciptakan sistem untuk mencari informasi tentang tiket pesawat adalah memilih platform yang sesuai dari mana kita akan mengambil informasi. Mengatasi masalah ini memang tidak mudah bagi saya, namun pada akhirnya saya memilih layanan Kayak. Saya mencoba layanan Momondo, Skyscanner, Expedia, dan beberapa lainnya, namun mekanisme perlindungan robot pada sumber daya ini tidak dapat ditembus. Setelah beberapa kali mencoba, di mana saya harus berurusan dengan lampu lalu lintas, penyeberangan pejalan kaki, dan sepeda, mencoba meyakinkan sistem bahwa saya adalah manusia, saya memutuskan bahwa Kayak adalah yang terbaik untuk saya, meskipun faktanya meskipun Terlalu banyak halaman yang dimuat dalam waktu singkat, dan pemeriksaan juga dimulai. Saya berhasil membuat bot mengirimkan permintaan ke situs dengan interval 4 hingga 6 jam, dan semuanya berfungsi dengan baik. Dari waktu ke waktu, kesulitan muncul saat bekerja dengan Kayak, tetapi jika mereka mulai mengganggu Anda dengan cek, maka Anda harus menanganinya secara manual dan kemudian meluncurkan bot, atau menunggu beberapa jam dan pemeriksaan akan berhenti. Jika perlu, Anda dapat dengan mudah mengadaptasi kode untuk platform lain, dan jika Anda melakukannya, Anda dapat melaporkannya di komentar.

Jika Anda baru memulai dengan web scraping dan tidak tahu mengapa beberapa situs web kesulitan melakukannya, maka sebelum Anda memulai proyek pertama Anda di bidang ini, bantulah diri Anda sendiri dan lakukan penelusuran Google untuk kata-kata "etiket web scraping" . Eksperimen Anda mungkin berakhir lebih cepat dari yang Anda kira jika Anda melakukan web scraping dengan tidak bijaksana.

Memulai

Berikut gambaran umum tentang apa yang akan terjadi pada kode scraper web kami:

  • Impor perpustakaan yang diperlukan.
  • Membuka tab Google Chrome.
  • Panggil fungsi yang memulai bot, meneruskan kota dan tanggal yang akan digunakan saat mencari tiket.
  • Fungsi ini mengambil hasil pencarian pertama, diurutkan berdasarkan yang terbaik, dan mengklik tombol untuk memuat hasil lainnya.
  • Fungsi lain mengumpulkan data dari seluruh halaman dan mengembalikan bingkai data.
  • Dua langkah sebelumnya dilakukan dengan mengurutkan jenis berdasarkan harga tiket (termurah) dan kecepatan penerbangan (tercepat).
  • Pengguna skrip dikirimi email berisi ringkasan harga tiket (tiket termurah dan harga rata-rata), dan bingkai data dengan informasi yang diurutkan berdasarkan tiga indikator yang disebutkan di atas disimpan sebagai file Excel.
  • Semua tindakan di atas dilakukan dalam satu siklus setelah jangka waktu tertentu.

Perlu dicatat bahwa setiap proyek Selenium dimulai dengan driver web. saya menggunakan driver Chrome, Saya bekerja dengan Google Chrome, tetapi ada opsi lain. PhantomJS dan Firefox juga populer. Setelah mengunduh driver, Anda perlu meletakkannya di folder yang sesuai, dan ini menyelesaikan persiapan penggunaannya. Baris pertama skrip kami membuka tab Chrome baru.

Ingatlah bahwa dalam cerita saya, saya tidak mencoba membuka cakrawala baru untuk menemukan penawaran menarik untuk tiket pesawat. Ada metode yang lebih canggih untuk mencari penawaran semacam itu. Saya hanya ingin menawarkan kepada pembaca materi ini cara sederhana namun praktis untuk mengatasi masalah ini.

Ini adalah kode yang kita bicarakan di atas.

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)

Di awal kode Anda dapat melihat perintah impor paket yang digunakan di seluruh proyek kami. Jadi, randint digunakan untuk membuat bot “tertidur” selama beberapa detik secara acak sebelum memulai operasi pencarian baru. Biasanya, tidak ada satu bot pun yang dapat melakukannya tanpa ini. Jika Anda menjalankan kode di atas, jendela Chrome akan terbuka, yang akan digunakan bot untuk bekerja dengan situs.

Mari lakukan sedikit eksperimen dan buka situs kayak.com di jendela terpisah. Kami akan memilih kota asal kami akan terbang, dan kota yang ingin kami tuju, serta tanggal penerbangan. Saat memilih tanggal, pastikan rentang +-3 hari yang digunakan. Saya menulis kode dengan mempertimbangkan apa yang dihasilkan situs sebagai tanggapan atas permintaan tersebut. Jika, misalnya, Anda perlu mencari tiket hanya untuk tanggal tertentu, kemungkinan besar Anda harus mengubah kode bot. Ketika saya berbicara tentang kode, saya memberikan penjelasan yang sesuai, tetapi jika Anda merasa bingung, beri tahu saya.

Sekarang klik tombol pencarian dan lihat tautan di bilah alamat. Ini harus serupa dengan tautan yang saya gunakan pada contoh di bawah ini di mana variabel dideklarasikan kayak, yang menyimpan URL, dan metode yang digunakan get pengemudi web. Setelah mengklik tombol pencarian, hasilnya akan muncul di halaman.

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Ketika saya menggunakan perintah get lebih dari dua atau tiga kali dalam beberapa menit, saya diminta menyelesaikan verifikasi menggunakan reCaptcha. Anda dapat meneruskan pemeriksaan ini secara manual dan terus bereksperimen hingga sistem memutuskan untuk menjalankan pemeriksaan baru. Saat saya menguji skripnya, sepertinya sesi pencarian pertama selalu berjalan lancar, jadi jika Anda ingin bereksperimen dengan kode tersebut, Anda hanya perlu memeriksa secara manual secara berkala dan membiarkan kode berjalan, menggunakan interval yang panjang antar sesi pencarian. Dan, jika dipikir-pikir, kemungkinan besar seseorang tidak memerlukan informasi tentang harga tiket yang diterima dengan interval 10 menit antara operasi pencarian.

Bekerja dengan halaman menggunakan XPath

Jadi, kami membuka jendela dan memuat situs tersebut. Untuk mendapatkan harga dan informasi lainnya, kita perlu menggunakan teknologi XPath atau pemilih CSS. Saya memutuskan untuk tetap menggunakan XPath dan tidak merasa perlu menggunakan pemilih CSS, tetapi cara itu sangat mungkin dilakukan. Menavigasi halaman menggunakan XPath bisa jadi rumit, dan bahkan jika Anda menggunakan teknik yang saya jelaskan ini artikel, yang melibatkan penyalinan pengidentifikasi yang sesuai dari kode halaman, saya menyadari bahwa ini sebenarnya bukan cara optimal untuk mengakses elemen yang diperlukan. Ngomong-ngomong, di ini Buku ini memberikan penjelasan yang sangat bagus tentang dasar-dasar bekerja dengan halaman menggunakan pemilih XPath dan CSS. Seperti inilah tampilan metode driver web yang sesuai.

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Jadi, mari terus mengerjakan botnya. Mari gunakan kemampuan program untuk memilih tiket termurah. Pada gambar berikut, kode pemilih XPath disorot dengan warna merah. Untuk melihat kodenya, Anda perlu mengklik kanan pada elemen halaman yang Anda minati dan memilih perintah Inspect dari menu yang muncul. Perintah ini dapat dipanggil untuk elemen halaman berbeda, yang kodenya akan ditampilkan dan disorot di penampil kode.

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Lihat kode halaman

Untuk mendapatkan konfirmasi atas alasan saya tentang kerugian menyalin penyeleksi dari kode, perhatikan fitur-fitur berikut.

Inilah yang Anda dapatkan saat menyalin kode:

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

Untuk menyalin sesuatu seperti ini, Anda perlu mengklik kanan pada bagian kode yang Anda minati dan memilih perintah Copy > Copy XPath dari menu yang muncul.

Inilah yang saya gunakan untuk mendefinisikan tombol Termurah:

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

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Salin Perintah> Salin XPath

Jelas sekali bahwa opsi kedua terlihat jauh lebih sederhana. Saat digunakan, ia mencari elemen a yang memiliki atribut data-code, setara price. Saat menggunakan opsi pertama, elemen dicari id yang sama dengan wtKI-price_aTab, dan tampilan jalur XPath ke elemen tersebut /div[1]/div/div/div[1]/div/span/span. Permintaan XPath seperti ini ke halaman akan berhasil, tetapi hanya sekali. Saya dapat mengatakannya sekarang id akan berubah saat halaman dimuat lagi. Urutan karakter wtKI berubah secara dinamis setiap kali halaman dimuat, sehingga kode yang menggunakannya tidak akan berguna setelah halaman berikutnya dimuat ulang. Jadi luangkan waktu untuk memahami XPath. Pengetahuan ini akan membantu Anda dengan baik.

Namun, perlu dicatat bahwa menyalin pemilih XPath dapat berguna saat bekerja dengan situs yang cukup sederhana, dan jika Anda merasa nyaman dengan hal ini, tidak ada yang salah dengan itu.

Sekarang mari kita pikirkan apa yang harus dilakukan jika Anda perlu mendapatkan semua hasil pencarian dalam beberapa baris, di dalam daftar. Sangat sederhana. Setiap hasil ada di dalam objek dengan kelas resultWrapper. Memuat semua hasil dapat dilakukan dalam satu lingkaran seperti yang ditunjukkan di bawah ini.

Perlu dicatat bahwa jika Anda memahami hal di atas, maka Anda akan dengan mudah memahami sebagian besar kode yang akan kami analisis. Saat kode ini berjalan, kita mengakses apa yang kita perlukan (sebenarnya, elemen yang membungkus hasilnya) menggunakan semacam mekanisme penentu jalur (XPath). Hal ini dilakukan untuk mendapatkan teks elemen dan menempatkannya pada objek tempat data dapat dibaca (pertama kali digunakan flight_containers, Kemudian - flights_list).

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Tiga baris pertama ditampilkan dan kita dapat dengan jelas melihat semua yang kita butuhkan. Namun, kami memiliki cara yang lebih menarik untuk memperoleh informasi. Kita perlu mengambil data dari setiap elemen secara terpisah.

Mulai bekerja!

Cara termudah untuk menulis suatu fungsi adalah dengan memuat hasil tambahan, jadi dari situlah kita akan memulai. Saya ingin memaksimalkan jumlah penerbangan yang informasinya diterima oleh program, tanpa menimbulkan kecurigaan pada layanan yang mengarah ke inspeksi, jadi saya mengklik tombol Muat lebih banyak hasil satu kali setiap kali halaman ditampilkan. Dalam kode ini, Anda harus memperhatikan bloknya try, yang saya tambahkan karena terkadang tombol tidak dimuat dengan benar. Jika Anda juga mengalami hal ini, beri komentar pada panggilan ke fungsi ini dalam kode fungsi start_kayak, yang akan kita lihat di bawah.

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

Sekarang, setelah analisis panjang terhadap fungsi ini (terkadang saya terbawa suasana), kami siap mendeklarasikan fungsi yang akan mengikis halaman.

Saya telah mengumpulkan sebagian besar dari apa yang dibutuhkan dalam fungsi yang dipanggil berikut page_scrape. Terkadang data jalur yang dikembalikan digabungkan, jadi saya menggunakan metode sederhana untuk memisahkannya. Misalnya saat saya menggunakan variabel untuk pertama kalinya section_a_list и section_b_list. Fungsi kami mengembalikan bingkai data flights_df, ini memungkinkan kita untuk memisahkan hasil yang diperoleh dari metode penyortiran data yang berbeda dan kemudian menggabungkannya.

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

Saya mencoba memberi nama variabel agar kodenya dapat dimengerti. Ingatlah bahwa variabel dimulai dengan a termasuk dalam tahap pertama dari jalan tersebut, dan b - ke yang kedua. Mari beralih ke fungsi berikutnya.

Mekanisme pendukung

Kami sekarang memiliki fungsi yang memungkinkan kami memuat hasil pencarian tambahan dan fungsi untuk memproses hasil tersebut. Artikel ini bisa saja berakhir di sini, karena kedua fungsi ini menyediakan semua yang Anda perlukan untuk mengikis halaman yang dapat Anda buka sendiri. Namun kami belum mempertimbangkan beberapa mekanisme tambahan yang dibahas di atas. Misalnya saja ini kode untuk mengirim email dan beberapa hal lainnya. Semua ini dapat ditemukan di fungsinya start_kayak, yang sekarang akan kita pertimbangkan.

Agar fungsi ini berfungsi, Anda memerlukan informasi tentang kota dan tanggal. Dengan menggunakan informasi ini, ia membentuk tautan dalam sebuah variabel kayak, yang digunakan untuk membawa Anda ke halaman yang berisi hasil pencarian yang diurutkan berdasarkan kecocokan terbaiknya dengan kueri. Setelah sesi scraping pertama, kami akan mengerjakan harga pada tabel di bagian atas halaman. Yaitu kita akan mencari harga tiket minimum dan harga rata-rata. Semua ini beserta prediksi yang dikeluarkan oleh situs tersebut akan dikirimkan melalui email. Di halaman tersebut, tabel terkait harus berada di sudut kiri atas. Omong-omong, bekerja dengan tabel ini dapat menyebabkan kesalahan saat mencari menggunakan tanggal pasti, karena dalam kasus ini tabel tidak ditampilkan di halaman.

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

Saya menguji skrip ini menggunakan akun Outlook (hotmail.com). Saya belum mengujinya agar berfungsi dengan benar dengan akun Gmail, sistem email ini cukup populer, tetapi ada banyak opsi yang memungkinkan. Jika Anda menggunakan akun Hotmail, maka agar semuanya berfungsi, Anda hanya perlu memasukkan data Anda ke dalam kode.

Jika Anda ingin memahami apa sebenarnya yang dilakukan di bagian tertentu dari kode untuk fungsi ini, Anda dapat menyalinnya dan bereksperimen dengannya. Bereksperimen dengan kode adalah satu-satunya cara untuk benar-benar memahaminya.

Sistem siap

Sekarang setelah kita melakukan semua yang kita bicarakan, kita dapat membuat loop sederhana yang memanggil fungsi kita. Script meminta data dari pengguna tentang kota dan tanggal. Saat menguji dengan skrip yang terus-menerus dihidupkan ulang, kemungkinan besar Anda tidak ingin memasukkan data ini secara manual setiap saat, jadi baris yang sesuai, untuk saat pengujian, dapat dikomentari dengan menghapus komentar di bawahnya, yang berisi data yang dibutuhkan oleh skrip. skrip di-hardcode.

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

Seperti inilah tampilan uji coba skripnya.
Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian
Uji coba skrip

Hasil

Jika Anda sudah berhasil sejauh ini, selamat! Anda sekarang memiliki web scraper yang berfungsi, meskipun saya sudah melihat banyak cara untuk memperbaikinya. Misalnya saja bisa diintegrasikan dengan Twilio sehingga bisa mengirim pesan teks, bukan email. Anda dapat menggunakan VPN atau yang lainnya untuk menerima hasil secara bersamaan dari beberapa server. Ada juga masalah yang muncul secara berkala saat memeriksa pengguna situs untuk melihat apakah dia seseorang, namun masalah ini juga dapat diselesaikan. Bagaimanapun, sekarang Anda memiliki basis yang dapat Anda kembangkan jika Anda mau. Misalnya, pastikan file Excel dikirimkan ke pengguna sebagai lampiran ke email.

Python - asisten dalam mencari tiket pesawat murah bagi mereka yang suka bepergian

Hanya pengguna terdaftar yang dapat berpartisipasi dalam survei. Masuk, silakan.

Apakah Anda menggunakan teknologi web scraping?

  • Ya

  • Tidak

8 pengguna memilih. 1 pengguna abstain.

Sumber: www.habr.com

Tambah komentar