Ausgabe
Ich versuche, einige Daten von der Flugsuchseite zu kratzen.
Diese Seite funktioniert so:
Sie füllen ein Formular aus und klicken dann auf die Schaltfläche Suchen – das ist ok. Wenn Sie auf die Schaltfläche klicken, werden Sie auf die Seite mit den Ergebnissen weitergeleitet, und hier ist das Problem. Diese Seite fügt kontinuierlich Ergebnisse hinzu, beispielsweise für eine Minute, was keine große Sache ist – das Problem besteht darin, alle diese Ergebnisse zu erhalten. Wenn Sie sich im echten Browser befinden, müssen Sie die Seite nach unten scrollen und diese Ergebnisse werden angezeigt. Also habe ich versucht, mit Selenium nach unten zu scrollen. Es scrollt am Ende der Seite wahrscheinlich so schnell nach unten oder es ist ein Sprung anstatt zu scrollen, dass die Seite keine neuen Ergebnisse lädt.
Wenn Sie langsam nach unten scrollen, werden die Ergebnisse neu geladen, aber wenn Sie es sehr schnell tun, stoppt das Laden.
Ich bin mir nicht sicher, ob mein Code hilft, das zu verstehen, also hänge ich ihn an.
SEARCH_STRING = """URL"""
class spider():
def __init__(self):
self.driver = webdriver.Firefox()
@staticmethod
def prepare_get(dep_airport,arr_airport,dep_date,arr_date):
string = SEARCH_STRING%(dep_airport,arr_airport,arr_airport,dep_airport,dep_date,arr_date)
return string
def find_flights_html(self,dep_airport, arr_airport, dep_date, arr_date):
if isinstance(dep_airport, list):
airports_string = str(r'%20').join(dep_airport)
dep_airport = airports_string
wait = WebDriverWait(self.driver, 60) # wait for results
self.driver.get(spider.prepare_get(dep_airport, arr_airport, dep_date, arr_date))
wait.until(EC.invisibility_of_element_located((By.XPATH, '//img[contains(@src, "loading")]')))
wait.until(EC.invisibility_of_element_located((By.XPATH, u'//div[. = "Poprosíme o trpezlivosť, hľadáme pre Vás ešte viac letov"]/preceding-sibling::img')))
self.driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
self.driver.find_element_by_xpath('//body').send_keys(Keys.CONTROL+Keys.END)
return self.driver.page_source
@staticmethod
def get_info_from_borderbox(div):
arrival = div.find('div',class_='departure').text
price = div.find('div',class_='pricebox').find('div',class_=re.compile('price'))
departure = div.find_all('div',class_='departure')[1].contents
date_departure = departure[1].text
airport_departure = departure[5].text
arrival = div.find_all('div', class_= 'arrival')[0].contents
date_arrival = arrival[1].text
airport_arrival = arrival[3].text[1:]
print 'DEPARTURE: '
print date_departure,airport_departure
print 'ARRIVAL: '
print date_arrival,airport_arrival
@staticmethod
def get_flights_from_result_page(html):
def match_tag(tag, classes):
return (tag.name == 'div'
and 'class' in tag.attrs
and all([c in tag['class'] for c in classes]))
soup = mLib.getSoup_html(html)
divs = soup.find_all(lambda t: match_tag(t, ['borderbox', 'flightbox', 'p2']))
for div in divs:
spider.get_info_from_borderbox(div)
print len(divs)
spider_inst = spider()
print spider.get_flights_from_result_page(spider_inst.find_flights_html(['BTS','BRU','PAR'], 'MAD', '2015-07-15', '2015-08-15'))
Das Hauptproblem ist also meiner Meinung nach, dass es zu schnell scrollt, um ein erneutes Laden der Ergebnisse auszulösen.
Hast du eine Idee, wie man es zum Laufen bringt?
Lösung
Hier ist ein anderer Ansatz, der für mich funktioniert hat, indem ich in die Ansicht des letzten Suchergebnisses scrolle und darauf warte, dass zusätzliche Elemente geladen werden, bevor ich erneut scrolle:
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import StaleElementReferenceException
from selenium.webdriver.support import expected_conditions as EC
class wait_for_more_than_n_elements(object):
def __init__(self, locator, count):
self.locator = locator
self.count = count
def __call__(self, driver):
try:
count = len(EC._find_elements(driver, self.locator))
return count >= self.count
except StaleElementReferenceException:
return False
driver = webdriver.Firefox()
dep_airport = ['BTS', 'BRU', 'PAR']
arr_airport = 'MAD'
dep_date = '2015-07-15'
arr_date = '2015-08-15'
airports_string = str(r'%20').join(dep_airport)
dep_airport = airports_string
url = "https://www.pelikan.sk/sk/flights/list?dfc=C%s&dtc=C%s&rfc=C%s&rtc=C%s&dd=%s&rd=%s&px=1000&ns=0&prc=&rng=1&rbd=0&ct=0" % (dep_airport, arr_airport, arr_airport, dep_airport, dep_date, arr_date)
driver.maximize_window()
driver.get(url)
wait = WebDriverWait(driver, 60)
wait.until(EC.invisibility_of_element_located((By.XPATH, '//img[contains(@src, "loading")]')))
wait.until(EC.invisibility_of_element_located((By.XPATH,
u'//div[. = "Poprosíme o trpezlivosť, hľadáme pre Vás ešte viac letov"]/preceding-sibling::img')))
while True: # TODO: make the endless loop end
results = driver.find_elements_by_css_selector("div.flightbox")
print "Results count: %d" % len(results)
# scroll to the last element
driver.execute_script("arguments[0].scrollIntoView();", results[-1])
# wait for more results to load
wait.until(wait_for_more_than_n_elements((By.CSS_SELECTOR, 'div.flightbox'), len(results)))
Anmerkungen:
- Sie müssten herausfinden, wann die Schleife beendet werden soll – zum Beispiel bei einem bestimmten
len(results)
Wert wait_for_more_than_n_elements
ist eine benutzerdefinierte erwartete Bedingung , die hilft zu erkennen, wann der nächste Teil geladen wird und wir erneut scrollen können
Beantwortet von – alecxe
Antwort geprüft von – Jay B. (FixError Admin)