Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay

Ang may-akda ng artikulo, ang pagsasalin na aming inilalathala ngayon, ay nagsabi na ang layunin nito ay pag-usapan ang tungkol sa pagbuo ng isang web scraper sa Python gamit ang Selenium, na naghahanap ng mga presyo ng tiket sa eroplano. Kapag naghahanap ng mga tiket, ginagamit ang mga flexible na petsa (+- 3 araw na nauugnay sa mga tinukoy na petsa). Ang scraper ay nagse-save ng mga resulta ng paghahanap sa isang Excel file at nagpapadala sa taong nagpatakbo ng paghahanap ng isang email na may buod ng kung ano ang kanilang nahanap. Ang layunin ng proyektong ito ay tulungan ang mga manlalakbay na mahanap ang pinakamahusay na deal.

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay

Kung, habang nauunawaan ang materyal, sa tingin mo ay nawawala, tingnan mo ito artikulo.

Ano ang hahanapin natin?

Malaya kang gamitin ang system na inilarawan dito ayon sa gusto mo. Halimbawa, ginamit ko ito upang maghanap ng mga paglilibot sa katapusan ng linggo at mga tiket sa aking bayan. Kung seryoso ka sa paghahanap ng mga kumikitang tiket, maaari mong patakbuhin ang script sa server (simple server, para sa 130 rubles sa isang buwan, ay angkop para dito) at siguraduhin na ito ay tumatakbo nang isang beses o dalawang beses sa isang araw. Ang mga resulta ng paghahanap ay ipapadala sa iyo sa pamamagitan ng email. Bilang karagdagan, inirerekumenda ko ang pag-set up ng lahat upang mai-save ng script ang isang Excel file na may mga resulta ng paghahanap sa isang folder ng Dropbox, na magbibigay-daan sa iyo upang tingnan ang mga naturang file mula sa kahit saan at anumang oras.

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Hindi pa ako nakakahanap ng mga taripa na may mga error, ngunit sa tingin ko posible ito

Kapag naghahanap, tulad ng nabanggit na, isang "nababagong petsa" ang ginagamit; ang script ay nakakahanap ng mga alok na nasa loob ng tatlong araw mula sa mga ibinigay na petsa. Bagama't kapag pinapatakbo ang script, naghahanap ito ng mga alok sa isang direksyon lamang, madali itong baguhin upang makakolekta ito ng data sa ilang direksyon ng paglipad. Sa tulong nito, maaari ka ring maghanap ng mga maling taripa; ang mga naturang paghahanap ay maaaring maging lubhang kawili-wili.

Bakit kailangan mo ng isa pang web scraper?

Noong una kong sinimulan ang web scraping, sa totoo lang ay hindi ako partikular na interesado dito. Gusto kong gumawa ng higit pang mga proyekto sa larangan ng predictive modeling, financial analysis, at, posibleng, sa larangan ng pagsusuri sa emosyonal na pangkulay ng mga teksto. Ngunit ito ay naging napaka-interesante na malaman kung paano lumikha ng isang programa na nangongolekta ng data mula sa mga website. Sa pag-aaral ko sa paksang ito, napagtanto ko na ang web scraping ay ang "engine" ng Internet.

Maaari mong isipin na ito ay masyadong matapang na pahayag. Ngunit isaalang-alang na nagsimula ang Google sa isang web scraper na nilikha ni Larry Page gamit ang Java at Python. Ang mga robot ng Google ay naggalugad sa Internet, sinusubukang ibigay sa mga user nito ang pinakamahusay na mga sagot sa kanilang mga tanong. Ang pag-scrape sa web ay walang katapusang gamit, at kahit na interesado ka sa ibang bagay sa Data Science, kakailanganin mo ng ilang mga kasanayan sa pag-scrape upang makuha ang data na kailangan mong suriin.

Natagpuan ko ang ilan sa mga pamamaraan na ginamit dito sa isang kahanga-hanga ang libro tungkol sa web scraping, na nakuha ko kamakailan. Naglalaman ito ng maraming simpleng halimbawa at ideya para sa praktikal na aplikasyon ng iyong natutuhan. Bilang karagdagan, mayroong isang napaka-kagiliw-giliw na kabanata sa pag-bypass ng mga pagsusuri sa reCaptcha. Dumating ito bilang balita sa akin, dahil hindi ko alam na may mga espesyal na tool at kahit buong serbisyo para sa paglutas ng mga naturang problema.

Mahilig ka bang magtravel?!

Sa simple at medyo hindi nakakapinsalang tanong na ibinibigay sa pamagat ng seksyong ito, madalas mong maririnig ang isang positibong sagot, na sinamahan ng ilang mga kuwento mula sa mga paglalakbay ng taong tinanong ito. Karamihan sa atin ay sasang-ayon na ang paglalakbay ay isang mahusay na paraan upang isawsaw ang iyong sarili sa mga bagong kultural na kapaligiran at palawakin ang iyong pananaw. Gayunpaman, kung tatanungin mo ang isang tao kung gusto nilang maghanap ng mga tiket sa eroplano, sigurado ako na ang sagot ay hindi magiging positibo. Sa katunayan, tinutulungan tayo ng Python dito.

Ang unang gawain na kailangan naming lutasin sa paraan sa paglikha ng isang sistema para sa paghahanap ng impormasyon sa mga tiket sa eroplano ay ang pagpili ng angkop na platform kung saan kami kukuha ng impormasyon. Ang paglutas ng problemang ito ay hindi madali para sa akin, ngunit sa huli ay pinili ko ang serbisyo ng Kayak. Sinubukan ko ang mga serbisyo ng Momondo, Skyscanner, Expedia, at ilang iba pa, ngunit ang mga mekanismo ng proteksyon ng robot sa mga mapagkukunang ito ay hindi malalampasan. Pagkatapos ng ilang mga pagtatangka, kung saan kailangan kong harapin ang mga ilaw ng trapiko, mga tawiran ng pedestrian at mga bisikleta, sinusubukang kumbinsihin ang mga sistema na ako ay tao, napagpasyahan ko na ang Kayak ay pinakaangkop para sa akin, sa kabila ng katotohanan na kahit na Masyadong maraming mga pahina ang na-load sa maikling panahon, at magsisimula na rin ang mga pagsusuri. Nagawa kong gawin ang bot na magpadala ng mga kahilingan sa site sa pagitan ng 4 hanggang 6 na oras, at lahat ay gumana nang maayos. Paminsan-minsan, lumilitaw ang mga paghihirap kapag nagtatrabaho sa Kayak, ngunit kung sinimulan ka nilang guluhin ng mga tseke, kailangan mong harapin ang mga ito nang manu-mano at pagkatapos ay ilunsad ang bot, o maghintay ng ilang oras at dapat huminto ang mga tseke. Kung kinakailangan, madali mong maiangkop ang code para sa isa pang platform, at kung gagawin mo ito, maaari mong iulat ito sa mga komento.

Kung nagsisimula ka pa lang sa web scraping at hindi mo alam kung bakit nahihirapan ang ilang website dito, bago mo simulan ang iyong unang proyekto sa lugar na ito, gawin ang iyong sarili ng pabor at maghanap sa Google sa mga salitang "web scraping etiquette" . Ang iyong mga eksperimento ay maaaring magwakas nang mas maaga kaysa sa iyong inaakala kung gagawin mo ang web scraping nang hindi matalino.

Pagsisimula

Narito ang pangkalahatang pangkalahatang-ideya ng kung ano ang mangyayari sa aming web scraper code:

  • I-import ang mga kinakailangang aklatan.
  • Pagbubukas ng tab ng Google Chrome.
  • Tumawag sa isang function na magsisimula sa bot, na ipapasa dito ang mga lungsod at petsa na gagamitin kapag naghahanap ng mga tiket.
  • Kinukuha ng function na ito ang mga unang resulta ng paghahanap, pinagsunod-sunod ayon sa pinakamahusay, at nag-click sa isang button upang mag-load ng higit pang mga resulta.
  • Ang isa pang function ay nangongolekta ng data mula sa buong page at nagbabalik ng data frame.
  • Ang dalawang naunang hakbang ay isinasagawa gamit ang mga uri ng pag-uuri ayon sa presyo ng tiket (mura) at sa bilis ng paglipad (pinakamabilis).
  • Ang gumagamit ng script ay pinadalhan ng isang email na naglalaman ng isang buod ng mga presyo ng tiket (pinakamurang mga tiket at average na presyo), at isang data frame na may impormasyon na pinagsunod-sunod ayon sa tatlong nabanggit na mga tagapagpahiwatig ay nai-save bilang isang Excel file.
  • Ang lahat ng mga aksyon sa itaas ay ginagawa sa isang cycle pagkatapos ng isang tinukoy na tagal ng panahon.

Dapat tandaan na ang bawat proyekto ng Selenium ay nagsisimula sa isang web driver. gumagamit ako Chromedriver, Gumagana ako sa Google Chrome, ngunit may iba pang mga opsyon. Sikat din ang PhantomJS at Firefox. Pagkatapos i-download ang driver, kailangan mong ilagay ito sa naaangkop na folder, at nakumpleto nito ang paghahanda para sa paggamit nito. Ang mga unang linya ng aming script ay nagbubukas ng bagong tab ng Chrome.

Tandaan na sa aking kuwento hindi ko sinusubukan na magbukas ng mga bagong abot-tanaw para sa paghahanap ng magagandang deal sa mga air ticket. Mayroong higit pang mga advanced na paraan ng paghahanap para sa mga naturang alok. Gusto ko lang mag-alok sa mga mambabasa ng materyal na ito ng isang simple ngunit praktikal na paraan upang malutas ang problemang ito.

Narito ang code na pinag-usapan natin sa itaas.

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)

Sa simula ng code makikita mo ang mga package import command na ginagamit sa kabuuan ng aming proyekto. Kaya, randint ginamit upang gawin ang bot na "makatulog" para sa isang random na bilang ng mga segundo bago simulan ang isang bagong operasyon sa paghahanap. Karaniwan, hindi magagawa ng isang bot kung wala ito. Kung patakbuhin mo ang code sa itaas, magbubukas ang isang window ng Chrome, na gagamitin ng bot upang gumana sa mga site.

Gumawa tayo ng kaunting eksperimento at buksan ang website ng kayak.com sa isang hiwalay na window. Pipiliin natin ang lungsod kung saan tayo lilipad, at ang lungsod na gusto nating puntahan, pati na rin ang mga petsa ng paglipad. Kapag pumipili ng mga petsa, tiyaking ginagamit ang saklaw na +-3 araw. Isinulat ko ang code na isinasaalang-alang kung ano ang ginagawa ng site bilang tugon sa mga naturang kahilingan. Kung, halimbawa, kailangan mong maghanap ng mga tiket para lamang sa mga tinukoy na petsa, pagkatapos ay may mataas na posibilidad na kailangan mong baguhin ang bot code. Kapag pinag-uusapan ko ang code, nagbibigay ako ng naaangkop na mga paliwanag, ngunit kung nalilito ka, ipaalam sa akin.

Ngayon mag-click sa pindutan ng paghahanap at tingnan ang link sa address bar. Ito ay dapat na katulad ng link na ginagamit ko sa halimbawa sa ibaba kung saan ang variable ay ipinahayag kayak, na nag-iimbak ng URL, at ginagamit ang paraan get driver ng web. Pagkatapos i-click ang pindutan ng paghahanap, dapat na lumitaw ang mga resulta sa pahina.

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Kapag ginamit ko ang utos get higit sa dalawa o tatlong beses sa loob ng ilang minuto, hiniling sa akin na kumpletuhin ang pag-verify gamit ang reCaptcha. Maaari mong ipasa ang tseke na ito nang manu-mano at magpatuloy sa pag-eeksperimento hanggang sa magpasya ang system na magpatakbo ng bagong pagsusuri. Noong sinubukan ko ang script, tila laging maayos ang takbo ng unang sesyon ng paghahanap, kaya kung gusto mong mag-eksperimento sa code, kailangan mo lang manu-manong suriin at hayaang tumakbo ang code, gamit ang mahabang pagitan sa pagitan ng mga session ng paghahanap. At, kung iisipin mo ito, ang isang tao ay malamang na hindi nangangailangan ng impormasyon tungkol sa mga presyo ng tiket na natanggap sa 10 minutong pagitan sa pagitan ng mga operasyon sa paghahanap.

Paggawa gamit ang isang pahina gamit ang XPath

Kaya, binuksan namin ang isang window at ni-load ang site. Upang makakuha ng pagpepresyo at iba pang impormasyon, kailangan naming gumamit ng XPath na teknolohiya o mga tagapili ng CSS. Nagpasya akong manatili sa XPath at hindi ko naramdaman ang pangangailangang gumamit ng mga tagapili ng CSS, ngunit medyo posible na gumana sa ganoong paraan. Ang pag-navigate sa paligid ng isang page gamit ang XPath ay maaaring nakakalito, at kahit na gamitin mo ang mga diskarteng inilarawan ko ito artikulo, na may kinalaman sa pagkopya ng mga kaukulang identifier mula sa page code, napagtanto ko na ito ay, sa katunayan, hindi ang pinakamainam na paraan upang ma-access ang mga kinakailangang elemento. Sa pamamagitan ng paraan, sa ito Ang aklat ay nagbibigay ng mahusay na paglalarawan ng mga pangunahing kaalaman sa pagtatrabaho sa mga pahina gamit ang XPath at CSS selector. Ito ang hitsura ng kaukulang pamamaraan ng web driver.

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Kaya, magpatuloy tayo sa pagtatrabaho sa bot. Gamitin natin ang mga kakayahan ng programa para piliin ang pinakamurang ticket. Sa sumusunod na larawan, ang XPath selector code ay naka-highlight sa pula. Upang matingnan ang code, kailangan mong mag-right-click sa elemento ng pahina na interesado ka at piliin ang Inspect command mula sa menu na lilitaw. Ang utos na ito ay maaaring tawagan para sa iba't ibang mga elemento ng pahina, ang code na kung saan ay ipapakita at iha-highlight sa viewer ng code.

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Tingnan ang code ng pahina

Upang makahanap ng kumpirmasyon ng aking pangangatwiran tungkol sa mga disadvantages ng pagkopya ng mga tagapili mula sa code, bigyang pansin ang mga sumusunod na tampok.

Ito ang makukuha mo kapag kinopya mo ang code:

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

Upang makopya ang isang bagay na tulad nito, kailangan mong mag-right click sa seksyon ng code na interesado ka at piliin ang Copy > Copy XPath command mula sa menu na lilitaw.

Narito ang ginamit ko upang tukuyin ang pinakamurang button:

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

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Kopyahin ang Utos > Kopyahin ang XPath

Medyo halata na ang pangalawang pagpipilian ay mukhang mas simple. Kapag ginamit, maghahanap ito ng elemento a na may katangian data-code, katumbas price. Kapag ginagamit ang unang opsyon, hinahanap ang elemento id na katumbas ng wtKI-price_aTab, at ang XPath path sa elemento ay kamukha /div[1]/div/div/div[1]/div/span/span. Ang isang XPath query na tulad nito sa isang page ay gagawa ng trick, ngunit isang beses lang. Masasabi ko ngayon na id ay magbabago sa susunod na oras na ma-load ang pahina. Pagkakasunod-sunod ng karakter wtKI dynamic na nagbabago sa tuwing na-load ang pahina, kaya ang code na gumagamit nito ay magiging walang silbi pagkatapos ng susunod na pag-reload ng pahina. Kaya maglaan ng ilang oras upang maunawaan ang XPath. Ang kaalamang ito ay magsisilbing mabuti sa iyo.

Gayunpaman, dapat tandaan na ang pagkopya sa mga tagapili ng XPath ay maaaring maging kapaki-pakinabang kapag nagtatrabaho sa medyo simpleng mga site, at kung komportable ka dito, walang mali dito.

Ngayon, isipin natin kung ano ang gagawin kung kailangan mong makuha ang lahat ng resulta ng paghahanap sa ilang linya, sa loob ng isang listahan. Napakasimple. Ang bawat resulta ay nasa loob ng isang bagay na may klase resultWrapper. Ang paglo-load ng lahat ng mga resulta ay maaaring gawin sa isang loop na katulad ng ipinapakita sa ibaba.

Dapat tandaan na kung naiintindihan mo ang nasa itaas, dapat mong madaling maunawaan ang karamihan sa code na aming susuriin. Habang tumatakbo ang code na ito, ina-access namin ang kailangan namin (sa katunayan, ang elemento kung saan nakabalot ang resulta) gamit ang ilang uri ng mekanismo na tumutukoy sa landas (XPath). Ginagawa ito upang makuha ang teksto ng elemento at ilagay ito sa isang bagay kung saan mababasa ang data (unang ginamit flight_containers, pagkatapos - flights_list).

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Ang unang tatlong linya ay ipinapakita at malinaw na nakikita namin ang lahat ng kailangan namin. Gayunpaman, mayroon kaming mas kawili-wiling mga paraan ng pagkuha ng impormasyon. Kailangan nating kumuha ng data mula sa bawat elemento nang hiwalay.

Magtrabaho!

Ang pinakamadaling paraan upang magsulat ng isang function ay ang pag-load ng mga karagdagang resulta, kaya doon tayo magsisimula. Gusto kong i-maximize ang bilang ng mga flight kung saan natatanggap ng programa ang impormasyon tungkol sa, nang hindi nagtataas ng mga hinala sa serbisyo na humahantong sa isang inspeksyon, kaya i-click ko ang button na Mag-load ng higit pang mga resulta sa bawat oras na ipinapakita ang pahina. Sa code na ito, dapat mong bigyang pansin ang block try, na idinagdag ko dahil minsan ang pindutan ay hindi naglo-load ng maayos. Kung nakatagpo ka rin nito, magkomento ng mga tawag sa function na ito sa function code start_kayak, na titingnan natin sa ibaba.

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

Ngayon, pagkatapos ng mahabang pagsusuri sa function na ito (kung minsan ay madadala ako), handa na kaming magdeklara ng function na mag-scrape sa page.

Nakolekta ko na ang karamihan sa kailangan sa sumusunod na function na tinatawag page_scrape. Minsan ang ibinalik na data ng landas ay pinagsama, kaya gumagamit ako ng isang simpleng paraan upang paghiwalayin ito. Halimbawa, kapag gumamit ako ng mga variable sa unang pagkakataon section_a_list и section_b_list. Ang aming function ay nagbabalik ng data frame flights_df, nagbibigay-daan ito sa amin na paghiwalayin ang mga resultang nakuha mula sa iba't ibang paraan ng pag-uuri ng data at pagsamahin ang mga ito sa ibang pagkakataon.

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

Sinubukan kong pangalanan ang mga variable upang maunawaan ang code. Tandaan na ang mga variable na nagsisimula sa a nabibilang sa unang yugto ng landas, at b - sa pangalawa. Lumipat tayo sa susunod na function.

Mga mekanismo ng suporta

Mayroon na kaming function na nagbibigay-daan sa amin na mag-load ng mga karagdagang resulta ng paghahanap at isang function upang iproseso ang mga resultang iyon. Maaaring dito na natapos ang artikulong ito, dahil ang dalawang function na ito ay nagbibigay ng lahat ng kailangan mo para mag-scrape ng mga page na maaari mong buksan sa iyong sarili. Ngunit hindi pa namin isinasaalang-alang ang ilan sa mga pantulong na mekanismo na tinalakay sa itaas. Halimbawa, ito ang code para sa pagpapadala ng mga email at ilang iba pang bagay. Ang lahat ng ito ay matatagpuan sa function start_kayak, na isasaalang-alang natin ngayon.

Para gumana ang function na ito, kailangan mo ng impormasyon tungkol sa mga lungsod at petsa. Gamit ang impormasyong ito, bumubuo ito ng isang link sa isang variable kayak, na ginagamit upang dalhin ka sa isang pahina na naglalaman ng mga resulta ng paghahanap na pinagsunod-sunod ayon sa kanilang pinakamahusay na tugma sa query. Pagkatapos ng unang sesyon ng pag-scrape, gagawin namin ang mga presyo sa talahanayan sa tuktok ng pahina. Ibig sabihin, mahahanap namin ang pinakamababang presyo ng tiket at ang average na presyo. Ang lahat ng ito, kasama ang hula na ibinigay ng site, ay ipapadala sa pamamagitan ng email. Sa pahina, ang kaukulang talahanayan ay dapat nasa itaas na kaliwang sulok. Ang pagtatrabaho sa talahanayang ito, sa pamamagitan ng paraan, ay maaaring maging sanhi ng isang error kapag naghahanap gamit ang eksaktong mga petsa, dahil sa kasong ito ang talahanayan ay hindi ipinapakita sa pahina.

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

Sinubukan ko ang script na ito gamit ang isang Outlook account (hotmail.com). Hindi ko pa nasubukan ito upang gumana nang tama sa isang Gmail account, ang email system na ito ay medyo sikat, ngunit maraming posibleng mga pagpipilian. Kung gumagamit ka ng isang Hotmail account, pagkatapos ay upang gumana ang lahat, kailangan mo lamang ipasok ang iyong data sa code.

Kung gusto mong maunawaan kung ano ang eksaktong ginagawa sa mga partikular na seksyon ng code para sa function na ito, maaari mong kopyahin ang mga ito at mag-eksperimento sa kanila. Ang pag-eksperimento sa code ay ang tanging paraan upang tunay na maunawaan ito.

Ready system

Ngayon na nagawa na namin ang lahat ng aming napag-usapan, maaari kaming lumikha ng isang simpleng loop na tumatawag sa aming mga function. Ang script ay humihiling ng data mula sa user tungkol sa mga lungsod at petsa. Kapag sumusubok sa patuloy na pag-restart ng script, malamang na hindi mo gustong ipasok ang data na ito nang manu-mano sa bawat oras, kaya ang mga kaukulang linya, para sa tagal ng pagsubok, ay maaaring magkomento sa pamamagitan ng pag-uncomment sa mga nasa ibaba nito, kung saan ang data na kailangan ng ang script ay hardcoded.

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

Ito ang hitsura ng isang pagsubok na run ng script.
Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay
Test run ng script

Mga resulta ng

Kung naabot mo na ito, congratulations! Mayroon ka na ngayong gumaganang web scraper, bagama't nakakakita na ako ng maraming paraan para mapabuti ito. Halimbawa, maaari itong isama sa Twilio upang magpadala ito ng mga text message sa halip na mga email. Maaari kang gumamit ng VPN o iba pa upang sabay-sabay na makatanggap ng mga resulta mula sa ilang mga server. Mayroon ding pana-panahong lumalabas na problema sa pagsuri sa gumagamit ng site upang makita kung siya ay isang tao, ngunit ang problemang ito ay maaari ding malutas. Sa anumang kaso, mayroon kang isang base na maaari mong palawakin kung nais mo. Halimbawa, siguraduhin na ang isang Excel file ay ipinadala sa user bilang isang attachment sa isang email.

Python - isang katulong sa paghahanap ng murang air ticket para sa mga mahilig maglakbay

Ang mga rehistradong user lamang ang maaaring lumahok sa survey. Mag-sign in, pakiusap

Gumagamit ka ba ng mga teknolohiya sa web scraping?

  • Oo

  • Hindi

8 na user ang bumoto. 1 user ang umiwas.

Pinagmulan: www.habr.com

Magdagdag ng komento