Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar

O autor do artigo, cuja tradução publicamos hoje, diz que seu objetivo é falar sobre o desenvolvimento de um web scraper em Python usando Selenium, que busca preços de passagens aéreas. Na procura de bilhetes são utilizadas datas flexíveis (+- 3 dias relativamente às datas indicadas). O raspador salva os resultados da pesquisa em um arquivo Excel e envia à pessoa que executou a pesquisa um e-mail com um resumo do que encontrou. O objetivo deste projeto é ajudar os viajantes a encontrar as melhores ofertas.

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar

Se, ao compreender o material, você se sentir perdido, dê uma olhada este artigo.

O que você está procurando?

Você é livre para usar o sistema descrito aqui como desejar. Por exemplo, usei-o para pesquisar passeios de fim de semana e ingressos para minha cidade natal. Se você realmente quer encontrar ingressos lucrativos, pode executar o script no servidor (simples servidor, por 130 rublos por mês, é bastante adequado para isso) e certifique-se de que funcione uma ou duas vezes por dia. Os resultados da pesquisa serão enviados a você por e-mail. Além disso, recomendo configurar tudo para que o script salve um arquivo Excel com os resultados da pesquisa em uma pasta Dropbox, o que permitirá visualizar esses arquivos de qualquer lugar e a qualquer hora.

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
Ainda não encontrei tarifas com erros, mas acho que é possível

Na busca, como já mencionado, é utilizada uma “data flexível”, o script encontra ofertas que estão dentro de três dias das datas indicadas. Embora ao executar o script ele busque ofertas em apenas uma direção, é fácil modificá-lo para que possa coletar dados em diversas direções de voo. Com sua ajuda, você pode até procurar tarifas erradas; tais descobertas podem ser muito interessantes.

Por que você precisa de outro web scraper?

Quando comecei a fazer web scraping, honestamente não estava particularmente interessado nisso. Eu queria fazer mais projetos na área de modelagem preditiva, análise financeira e, possivelmente, na área de análise da coloração emocional de textos. Mas descobriu-se que foi muito interessante descobrir como criar um programa que coleta dados de sites. Ao me aprofundar neste tópico, percebi que web scraping é o “motor” da Internet.

Você pode pensar que esta é uma afirmação muito ousada. Mas considere que o Google começou com um web scraper que Larry Page criou usando Java e Python. Os robôs do Google têm explorado a Internet, tentando fornecer aos seus usuários as melhores respostas às suas perguntas. Web scraping tem usos infinitos e, mesmo se você estiver interessado em outra coisa em ciência de dados, precisará de algumas habilidades de scraping para obter os dados que precisa analisar.

Encontrei algumas das técnicas usadas aqui de uma forma maravilhosa um livro sobre web scraping, que adquiri recentemente. Ele contém muitos exemplos simples e ideias para aplicação prática do que você aprendeu. Além disso, há um capítulo muito interessante sobre como contornar as verificações do reCaptcha. Isso foi uma novidade para mim, pois eu nem sabia que existiam ferramentas especiais e até serviços inteiros para solucionar esses problemas.

Você gosta de viajar?!

À pergunta simples e bastante inofensiva colocada no título desta seção, muitas vezes você pode ouvir uma resposta positiva, acompanhada por algumas histórias das viagens da pessoa a quem foi feita a pergunta. A maioria de nós concordaria que viajar é uma ótima maneira de mergulhar em novos ambientes culturais e ampliar seus horizontes. Porém, se você perguntar a alguém se ele gosta de pesquisar passagens aéreas, tenho certeza que a resposta não será tão positiva. Na verdade, o Python vem em nosso auxílio aqui.

A primeira tarefa que precisamos resolver no caminho para a criação de um sistema de busca de informações sobre passagens aéreas será a seleção de uma plataforma adequada da qual retiraremos as informações. Resolver este problema não foi fácil para mim, mas no final optei pelo serviço Kayak. Experimentei os serviços da Momondo, Skyscanner, Expedia e alguns outros, mas os mecanismos de proteção dos robôs nesses recursos eram impenetráveis. Depois de várias tentativas, durante as quais tive que lidar com semáforos, faixas de pedestres e bicicletas, tentando convencer os sistemas de que era humano, decidi que o Kayak era o mais adequado para mim, apesar do fato de que mesmo que muitas páginas estejam carregadas em pouco tempo, e as verificações também começam. Consegui fazer com que o bot enviasse solicitações ao site em intervalos de 4 a 6 horas e tudo funcionou bem. De vez em quando surgem dificuldades ao trabalhar com o Kayak, mas se eles começarem a incomodar você com verificações, você precisará lidar com elas manualmente e depois iniciar o bot, ou esperar algumas horas e as verificações devem parar. Se necessário, você pode facilmente adaptar o código para outra plataforma e, se fizer isso, pode reportar nos comentários.

Se você está apenas começando com web scraping e não sabe por que alguns sites têm dificuldades com isso, antes de iniciar seu primeiro projeto nesta área, faça um favor a si mesmo e faça uma pesquisa no Google pelas palavras "etiqueta de web scraping" . Seus experimentos podem terminar mais cedo do que você pensa se você fizer web scraping de maneira imprudente.

Introdução

Aqui está uma visão geral do que acontecerá em nosso código do web scraper:

  • Importe as bibliotecas necessárias.
  • Abrindo uma guia do Google Chrome.
  • Chama uma função que inicia o bot, passando para ele as cidades e datas que serão utilizadas na busca pelos ingressos.
  • Esta função pega os primeiros resultados da pesquisa, classificados pelos melhores, e clica em um botão para carregar mais resultados.
  • Outra função coleta dados de toda a página e retorna um quadro de dados.
  • As duas etapas anteriores são realizadas utilizando tipos de ordenação por preço da passagem (mais barato) e por velocidade do voo (mais rápido).
  • O usuário do script recebe um e-mail contendo um resumo dos preços dos ingressos (ingressos mais baratos e preço médio), e um data frame com informações ordenadas pelos três indicadores mencionados acima é salvo em arquivo Excel.
  • Todas as ações acima são executadas em um ciclo após um período de tempo especificado.

Deve-se observar que todo projeto Selenium começa com um driver web. eu uso Chromedriver, trabalho com o Google Chrome, mas existem outras opções. PhantomJS e Firefox também são populares. Após baixar o driver, é necessário colocá-lo na pasta apropriada, e isso completa a preparação para seu uso. As primeiras linhas do nosso script abrem uma nova guia do Chrome.

Tenha em mente que na minha história não estou tentando abrir novos horizontes para encontrar ótimas ofertas em passagens aéreas. Existem métodos muito mais avançados de pesquisa dessas ofertas. Quero apenas oferecer aos leitores deste material uma maneira simples, mas prática, de resolver esse problema.

Aqui está o código sobre o qual falamos acima.

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)

No início do código você pode ver os comandos de importação de pacotes que são usados ​​em todo o nosso projeto. Então, randint usado para fazer o bot “adormecer” por um número aleatório de segundos antes de iniciar uma nova operação de pesquisa. Normalmente, nenhum bot pode viver sem isso. Se você executar o código acima, uma janela do Chrome será aberta, que o bot usará para trabalhar com sites.

Vamos fazer uma pequena experiência e abrir o site kayak.com em uma janela separada. Selecionaremos a cidade de onde voaremos, a cidade para onde queremos chegar, bem como as datas dos voos. Ao escolher as datas, certifique-se de usar o intervalo de +-3 dias. Escrevi o código levando em consideração o que o site produz em resposta a tais solicitações. Se, por exemplo, você precisar procurar ingressos apenas para datas específicas, há uma grande probabilidade de que você tenha que modificar o código do bot. Quando falo sobre o código, forneço explicações adequadas, mas se você se sentir confuso, me avise.

Agora clique no botão de pesquisa e veja o link na barra de endereço. Deve ser semelhante ao link que uso no exemplo abaixo onde a variável é declarada kayak, que armazena o URL, e o método é usado get motorista web. Após clicar no botão de pesquisa, os resultados deverão aparecer na página.

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
Quando usei o comando get mais de duas ou três vezes em poucos minutos, fui solicitado a concluir a verificação usando o reCaptcha. Você pode passar nessa verificação manualmente e continuar experimentando até que o sistema decida executar uma nova verificação. Quando testei o script, parecia que a primeira sessão de pesquisa sempre corria bem, então se você quisesse experimentar o código, você só teria que verificar manualmente periodicamente e deixar o código rodar, usando longos intervalos entre as sessões de pesquisa. E, se você pensar bem, é improvável que uma pessoa precise de informações sobre os preços dos ingressos recebidos em intervalos de 10 minutos entre as operações de pesquisa.

Trabalhando com uma página usando XPath

Então, abrimos uma janela e carregamos o site. Para obter preços e outras informações, precisamos usar a tecnologia XPath ou seletores CSS. Decidi ficar com o XPath e não senti necessidade de usar seletores CSS, mas é bem possível trabalhar dessa forma. Navegar por uma página usando XPath pode ser complicado, e mesmo se você usar as técnicas descritas em este artigo, que envolvia copiar os identificadores correspondentes do código da página, percebi que esta não é, de fato, a maneira ideal de acessar os elementos necessários. Aliás, em este O livro fornece uma excelente descrição dos fundamentos do trabalho com páginas usando seletores XPath e CSS. Esta é a aparência do método do driver da web correspondente.

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
Então, vamos continuar trabalhando no bot. Vamos usar os recursos do programa para selecionar os ingressos mais baratos. Na imagem a seguir, o código do seletor XPath está destacado em vermelho. Para visualizar o código, você precisa clicar com o botão direito no elemento da página de seu interesse e selecionar o comando Inspecionar no menu que aparece. Este comando pode ser chamado para diferentes elementos da página, cujo código será exibido e destacado no visualizador de código.

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
Ver código da página

Para encontrar a confirmação do meu raciocínio sobre as desvantagens de copiar seletores do código, preste atenção aos seguintes recursos.

Isto é o que você obtém quando copia o código:

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

Para copiar algo assim, você precisa clicar com o botão direito na seção do código de seu interesse e selecionar o comando Copiar> Copiar XPath no menu que aparece.

Aqui está o que usei para definir o botão Mais barato:

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

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
Comando Copiar > Copiar XPath

É bastante óbvio que a segunda opção parece muito mais simples. Quando utilizado, procura um elemento a que possua o atributo data-codeigual a price. Ao usar a primeira opção, o elemento é pesquisado id que é igual a wtKI-price_aTab, e o caminho XPath para o elemento se parece com /div[1]/div/div/div[1]/div/span/span. Uma consulta XPath como essa para uma página resolverá o problema, mas apenas uma vez. Posso dizer agora que id mudará na próxima vez que a página for carregada. Sequência de caracteres wtKI muda dinamicamente toda vez que a página é carregada, portanto o código que a utiliza será inútil após o próximo recarregamento da página. Portanto, reserve algum tempo para entender o XPath. Esse conhecimento será útil para você.

No entanto, deve-se observar que copiar seletores XPath pode ser útil ao trabalhar com sites bastante simples e, se você se sentir confortável com isso, não há nada de errado com isso.

Agora vamos pensar no que fazer se você precisar obter todos os resultados da pesquisa em várias linhas, dentro de uma lista. Muito simples. Cada resultado está dentro de um objeto com uma classe resultWrapper. O carregamento de todos os resultados pode ser feito em um loop semelhante ao mostrado abaixo.

Deve-se observar que, se você entender o que foi dito acima, deverá compreender facilmente a maior parte do código que analisaremos. À medida que esse código é executado, acessamos o que precisamos (na verdade, o elemento no qual o resultado está encapsulado) usando algum tipo de mecanismo de especificação de caminho (XPath). Isto é feito para obter o texto do elemento e colocá-lo em um objeto a partir do qual os dados possam ser lidos (usado pela primeira vez flight_containers, então - flights_list).

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
As três primeiras linhas são exibidas e podemos ver claramente tudo o que precisamos. Porém, temos formas mais interessantes de obter informações. Precisamos obter dados de cada elemento separadamente.

Ir trabalhar!

A maneira mais fácil de escrever uma função é carregar resultados adicionais, e é por aí que começaremos. Gostaria de maximizar o número de voos sobre os quais o programa recebe informações, sem levantar suspeitas no serviço que leva à fiscalização, por isso clico no botão Carregar mais resultados uma vez cada vez que a página é exibida. Neste código, você deve prestar atenção ao bloco try, que adicionei porque às vezes o botão não carrega corretamente. Se você também encontrar isso, comente as chamadas para esta função no código da função start_kayak, que veremos a seguir.

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

Agora, depois de uma longa análise desta função (às vezes posso me deixar levar), estamos prontos para declarar uma função que irá raspar a página.

Já coletei a maior parte do que é necessário na seguinte função chamada page_scrape. Às vezes, os dados do caminho retornado são combinados, então uso um método simples para separá-los. Por exemplo, quando uso variáveis ​​pela primeira vez section_a_list и section_b_list. Nossa função retorna um quadro de dados flights_df, isso nos permite separar os resultados obtidos de diferentes métodos de classificação de dados e posteriormente combiná-los.

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

Tentei nomear as variáveis ​​para que o código ficasse compreensível. Lembre-se de que variáveis ​​começando com a pertencem à primeira etapa do caminho, e b - para o segundo. Vamos passar para a próxima função.

Mecanismos de apoio

Agora temos uma função que nos permite carregar resultados de pesquisa adicionais e uma função para processar esses resultados. Este artigo poderia ter terminado aqui, pois essas duas funções fornecem tudo que você precisa para raspar páginas que você mesmo pode abrir. Mas ainda não consideramos alguns dos mecanismos auxiliares discutidos acima. Por exemplo, este é o código para enviar e-mails e algumas outras coisas. Tudo isso pode ser encontrado na função start_kayak, que consideraremos agora.

Para que esta função funcione, você precisa de informações sobre cidades e datas. Usando essas informações, ele forma um link em uma variável kayak, que é usado para levá-lo a uma página que conterá os resultados da pesquisa classificados pela melhor correspondência com a consulta. Após a primeira sessão de scraping, trabalharemos com os preços da tabela no topo da página. Ou seja, encontraremos o preço mínimo do ingresso e o preço médio. Tudo isso, junto com a previsão divulgada pelo site, será enviado por email. Na página, a tabela correspondente deverá estar no canto superior esquerdo. Trabalhar com esta tabela, aliás, pode causar erro na busca por datas exatas, pois neste caso a tabela não é exibida na página.

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

Testei esse script usando uma conta do Outlook (hotmail.com). Não testei para funcionar corretamente com uma conta do Gmail, este sistema de e-mail é bastante popular, mas existem muitas opções possíveis. Se você usa uma conta do Hotmail, para que tudo funcione basta inserir seus dados no código.

Se quiser entender o que exatamente está sendo feito em seções específicas do código para esta função, você pode copiá-las e experimentá-las. Experimentar o código é a única maneira de realmente entendê-lo.

Sistema pronto

Agora que fizemos tudo o que falamos, podemos criar um loop simples que chama nossas funções. O script solicita dados do usuário sobre cidades e datas. Ao testar com reinicialização constante do script, é improvável que você queira inserir esses dados manualmente todas as vezes, portanto, as linhas correspondentes, para o momento do teste, podem ser comentadas descomentando as que estão abaixo delas, nas quais os dados necessários para o o script é codificado.

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

Esta é a aparência de um teste do script.
Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar
Execução de teste do script

Resultados de

Se você chegou até aqui, parabéns! Agora você tem um web scraper funcional, embora eu já possa ver muitas maneiras de melhorá-lo. Por exemplo, pode ser integrado ao Twilio para enviar mensagens de texto em vez de e-mails. Você pode usar uma VPN ou outra coisa para receber resultados simultaneamente de vários servidores. Também surge periodicamente um problema ao verificar o usuário do site para ver se ele é uma pessoa, mas esse problema também pode ser resolvido. De qualquer forma, agora você tem uma base que pode expandir se desejar. Por exemplo, certifique-se de que um arquivo Excel seja enviado ao usuário como anexo de um email.

Python - um assistente na busca de passagens aéreas baratas para quem gosta de viajar

Apenas usuários registrados podem participar da pesquisa. Entrarpor favor

Você usa tecnologias de web scraping?

  • Sim

  • Não

8 usuários votaram. 1 usuário se absteve.

Fonte: habr.com

Adicionar um comentário