При чтении веб-ссылки из фрейма данных возникает ошибка «устаревшая ссылка на элемент: элемент не прикреплен к документу страницы».

#python #python-3.x #selenium #selenium-webdriver #selenium-chromedriver

Вопрос:

У меня есть фрейм данных, содержащий ссылки на отзывы Google о двух ресторанах. Я хотел загрузить все отзывы о двух ресторанах (один за другим) в браузер, а затем сохранить их в новом фрейме данных. Я написал скрипт, который считывает и загружает все отзывы в браузер следующим образом:

 from selenium import webdriver import pandas as pd from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.action_chains import ActionChains import time  link_df = Link 0 https://www.google.com/search?q=restaurant in christchurchamp;biw=1280amp;bih=614amp;hotel_occupancy=2amp;tbm=lclamp;sxsrf=AOaemvI4qlEAr3btedb6PCx9U53RtXkI2Q:1635630947742amp;ei=Y799YaHfLOKZ4-EPoeqjmA4amp;oq=restaurant in christchurchamp;gs_l=psy-ab.3...0.0.0.614264.0.0.0.0.0.0.0.0..0.0....0...1c..64.psy-ab..0.0.0....0.7jAOI05vCjI#lrd=0x6d318a3aa3041455:0x5f83f4fae76d8656,1,,,amp;rlfi=hd:;si:6882614014013965910,l,ChpyZXN0YXVyYW50IGluIGNocmlzdGNodXJjaEiglZKhm6qAgAhaKBAAGAAYAiIacmVzdGF1cmFudCBpbiBjaHJpc3RjaHVyY2gqBAgDEACSARJidXJtZXNlX3Jlc3RhdXJhbnSqAQwQASoIIgRmb29kKAA,y,UB2auy7TMYs;mv:[[-43.4870861,172.6509735],[-43.5490232,172.5976049]] 1 https://www.google.com/search?q=restaurant in christchurchamp;biw=1280amp;bih=614amp;hotel_occupancy=2amp;tbm=lclamp;sxsrf=AOaemvI4qlEAr3btedb6PCx9U53RtXkI2Q:1635630947742amp;ei=Y799YaHfLOKZ4-EPoeqjmA4amp;oq=restaurant in christchurchamp;gs_l=psy-ab.3...0.0.0.614264.0.0.0.0.0.0.0.0..0.0....0...1c..64.psy-ab..0.0.0....0.7jAOI05vCjI#lrd=0x6d318bf82139caaf:0xf115cd7fe794cbcc,1,,,amp;rlfi=hd:;si:17372017086881385420,l,ChpyZXN0YXVyYW50IGluIGNocmlzdGNodXJjaEjh9auu-q6AgAhaKBAAGAAYAiIacmVzdGF1cmFudCBpbiBjaHJpc3RjaHVyY2gqBAgDEACSAQpyZXN0YXVyYW50qgEMEAEqCCIEZm9vZCgA,y,ZeJbBWd7wDg;mv:[[-43.4870861,172.6509735],[-43.5490232,172.5976049]]  i = 0 driver = webdriver.Chrome() for index, i in link_df.iterrows():  base_url = i['Link'] #link_df['Link'][i]    driver.get(base_url)  WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//div[./span[text()='Newest']]"))).click()  print('Restaurant number is ',index)    title = driver.find_element_by_xpath("//div[@class='P5Bobd']").text  address = driver.find_element_by_xpath("//div[@class='T6pBCe']").text  overall_rating = driver.find_element_by_xpath("//div[@class='review-score-container']//span[@class='Aq14fc']").text    total_reviews_text =driver.find_element_by_xpath("//div[@class='review-score-container']//div//div//span//span[@class='z5jxId']").text  num_reviews = int (total_reviews_text.split()[0])  all_reviews = WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div.gws-localreviews__google-review')))  time.sleep(2)  total_reviews = len(all_reviews)    while total_reviews lt; num_reviews:  driver.execute_script('arguments[0].scrollIntoView(true);', all_reviews[-1])  WebDriverWait(driver, 5, 0.25).until_not(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[class$="activityIndicator"]')))  time.sleep(5)  all_reviews = WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div.gws-localreviews__google-review')))  print(total_reviews)  total_reviews  =1  reviews_info = driver.find_elements_by_xpath("//div[@class='jxjCjc']")  review_information = pd.DataFrame(columns=["Restaurant title","Restaurant rating","Total reviews","Reviewer Name","Rating", "Review"])  name= ''  rating = ''  text = ''      for index,review_info in enumerate(reviews_info):  name = review_info.find_element_by_xpath("./div/div/a").text  rating = review_info.find_element_by_xpath(".//div[@class='PuaHbe']//g-review-stars//span").get_attribute('aria-label')  text = review_info.find_element_by_xpath(".//div[@class='Jtu6Td']//span").text  review_information.at[len(review_information)] = [title,overall_rating,num_reviews,name,rating,text]    filename = 'Google_reviews'   ' '  pd.to_datetime("now").strftime("%Y_%m_%d") '.csv'  files_present = glob.glob(filename)  if files_present:  review_information.to_csv(filename,index=False,mode='a',header=False)  else:  review_information.to_csv(filename,index=False)    driver.get('https:ww.google.com')  time.sleep(3)  

Проблема в том, что скрипт выдает ошибку, когда он достигает следующей строки.

 driver.execute_script('arguments[0].scrollIntoView(true);', all_reviews[-1])  

Это приводит к следующей ошибке:

 StaleElementReferenceException: Message: stale element reference: element is not attached to the page document  (Session info: chrome=95.0.4638.69)  

Когда я попробовал ту же программу без сохранения ссылок Google во фрейме данных (т. Е. Без цикла , и вместо base_url = i['Link'] этого я написал base_url = ссылка на обзор google), она работает нормально.

Я не уверен, где я совершаю ошибку. Любое предложение или помощь по устранению проблемы будут высоко оценены?

Комментарии:

1. Почему вы не можете поймать исключение и повторно вызвать функцию, которая вам нужна?

2. Попробовал ваш код и, посетив URL-адреса, даже установив английский язык, не смог увидеть «Новейший» диапазон, который вы ищете. Кроме того, вы ссылаетесь на несколько имен классов, которые, я думаю, генерируются автоматически и могут измениться в будущем. Знать.

3. @NandanA, извини, я не понял. Что вы подразумеваете под функцией повторного вызова?

4. @MattiaGalati, я вижу «Самый новостной» диапазон в html-коде страницы

5. проблема в первом цикле или во втором цикле?

Ответ №1:

Редактировать

  1. вы помещаете создание драйвера за пределы цикла for
  2. вы не можете запустить новый URL-адрес с данными gps, когда первое всплывающее окно всегда впереди, если вы его запустите, оно останется в бэкдоре, проще всего запустить новый URL-адрес без данных gps — gt; https:ww.google.com и подождите 3 декабря, прежде чем следовать своему циклу:
  3. ваш счет не очень хорош, я изменил ваш селектор, изменил общее количество и установил несколько строк в комментарии

 from selenium import webdriver import pandas as pd from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.firefox.options import Options import time  link_df = ["https://www.google.com/search?q=restaurant in christchurchamp;biw=1280amp;bih=614amp;hotel_occupancy=2amp;tbm=lclamp;sxsrf=AOaemvI4qlEAr3btedb6PCx9U53RtXkI2Q:1635630947742amp;ei=Y799YaHfLOKZ4-EPoeqjmA4amp;oq=restaurant in christchurchamp;gs_l=psy-ab.3...0.0.0.614264.0.0.0.0.0.0.0.0..0.0....0...1c..64.psy-ab..0.0.0....0.7jAOI05vCjI#lrd=0x6d318a3aa3041455:0x5f83f4fae76d8656,1,,,amp;rlfi=hd:;si:6882614014013965910,l,ChpyZXN0YXVyYW50IGluIGNocmlzdGNodXJjaEiglZKhm6qAgAhaKBAAGAAYAiIacmVzdGF1cmFudCBpbiBjaHJpc3RjaHVyY2gqBAgDEACSARJidXJtZXNlX3Jlc3RhdXJhbnSqAQwQASoIIgRmb29kKAA,y,UB2auy7TMYs;mv:[[-43.4870861,172.6509735],[-43.5490232,172.5976049]]",  "https://www.google.com/search?q=restaurant in christchurchamp;biw=1280amp;bih=614amp;hotel_occupancy=2amp;tbm=lclamp;sxsrf=AOaemvI4qlEAr3btedb6PCx9U53RtXkI2Q:1635630947742amp;ei=Y799YaHfLOKZ4-EPoeqjmA4amp;oq=restaurant in christchurchamp;gs_l=psy-ab.3...0.0.0.614264.0.0.0.0.0.0.0.0..0.0....0...1c..64.psy-ab..0.0.0....0.7jAOI05vCjI#lrd=0x6d318bf82139caaf:0xf115cd7fe794cbcc,1,,,amp;rlfi=hd:;si:17372017086881385420,l,ChpyZXN0YXVyYW50IGluIGNocmlzdGNodXJjaEjh9auu-q6AgAhaKBAAGAAYAiIacmVzdGF1cmFudCBpbiBjaHJpc3RjaHVyY2gqBAgDEACSAQpyZXN0YXVyYW50qgEMEAEqCCIEZm9vZCgA,y,ZeJbBWd7wDg;mv:[[-43.4870861,172.6509735],[-43.5490232,172.5976049]]"  ] i = 0 binary = r'C:Program Files (x86)Mozilla Firefoxfirefox.exe' cap = DesiredCapabilities().FIREFOX cap["marionette"] = True options = Options() options.binary = binary driver = webdriver.Firefox(options=options, capabilities=cap, executable_path="E:\Téléchargement\geckodriver.exe")  # i have to launch one time to accept the cookies manually  #by setting a breakpoint after, but you dont have that i think #driver.get(link_df[0])   print ("Headless Firefox Initialized")   print(link_df) for url in link_df:  base_url = url # i['Link'] # link_df['Link'][i]  print(base_url)  driver.get(base_url)  WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[./span[text()='Avis les plus récents']]"))).click()   title = driver.find_element_by_xpath("//div[@class='P5Bobd']").text  address = driver.find_element_by_xpath("//div[@class='T6pBCe']").text  overall_rating = driver.find_element_by_xpath("//div[@class='review-score-container']//span[@class='Aq14fc']").text   total_reviews_text = driver.find_element_by_xpath(  "//div[@class='review-score-container']//div//div//span//span[@class='z5jxId']").text  num_reviews = int(total_reviews_text.split()[0])  all_reviews = WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#reviewSort .gws-localreviews__google-review')))  # time.sleep(2)  total_reviews = 0   while total_reviews lt; num_reviews:  driver.execute_script('arguments[0].scrollIntoView(true);', all_reviews[-1])  WebDriverWait(driver, 5, 0.25).until_not(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[class$="activityIndicator"]')))    all_reviews = WebDriverWait(driver, 5).until(  EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#reviewSort .gws-localreviews__google-review')))  total_reviews = len(all_reviews)  print(total_reviews, len(all_reviews))   driver.get('https:ww.google.com') # or driver.close() if no bugs  time.sleep(3)  driver.close() driver.quit()  

похоже, решение для chrome нуждается в некоторых исправлениях:

org.openqa.селен.Исключение StaleElementReferenceException: устаревший элемент ссылка: элемент не прикреплен к документу страницы

Буквальное значение примерно таково: элемент , на который ссылается ссылка , устарел, больше не прикреплен к текущей странице . Обычно это происходит из-за того , что страница была обновлена или пропущена , решение заключается в повторном использовании метода findElement или findElements для поиска элемента .

так что, похоже, для chrome существует проблема обновления, поэтому я предлагаю загрузить количество записей перед прокруткой, чтобы получить свежую копию элементов DOM, и мне нужно добавить 1 сек в конце цикла while

 from selenium import webdriver import pandas as pd from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.action_chains import ActionChains #from selenium.webdriver.firefox.options import Options from selenium.webdriver.chrome.options import Options import time  link_df = [  "https://www.google.com/search?q=restaurant in christchurchamp;biw=1280amp;bih=614amp;hotel_occupancy=2amp;tbm=lclamp;sxsrf=AOaemvI4qlEAr3btedb6PCx9U53RtXkI2Q:1635630947742amp;ei=Y799YaHfLOKZ4-EPoeqjmA4amp;oq=restaurant in christchurchamp;gs_l=psy-ab.3...0.0.0.614264.0.0.0.0.0.0.0.0..0.0....0...1c..64.psy-ab..0.0.0....0.7jAOI05vCjI#lrd=0x6d318a3aa3041455:0x5f83f4fae76d8656,1,,,amp;rlfi=hd:;si:6882614014013965910,l,ChpyZXN0YXVyYW50IGluIGNocmlzdGNodXJjaEiglZKhm6qAgAhaKBAAGAAYAiIacmVzdGF1cmFudCBpbiBjaHJpc3RjaHVyY2gqBAgDEACSARJidXJtZXNlX3Jlc3RhdXJhbnSqAQwQASoIIgRmb29kKAA,y,UB2auy7TMYs;mv:[[-43.4870861,172.6509735],[-43.5490232,172.5976049]]",  "https://www.google.com/search?q=restaurant in christchurchamp;biw=1280amp;bih=614amp;hotel_occupancy=2amp;tbm=lclamp;sxsrf=AOaemvI4qlEAr3btedb6PCx9U53RtXkI2Q:1635630947742amp;ei=Y799YaHfLOKZ4-EPoeqjmA4amp;oq=restaurant in christchurchamp;gs_l=psy-ab.3...0.0.0.614264.0.0.0.0.0.0.0.0..0.0....0...1c..64.psy-ab..0.0.0....0.7jAOI05vCjI#lrd=0x6d318bf82139caaf:0xf115cd7fe794cbcc,1,,,amp;rlfi=hd:;si:17372017086881385420,l,ChpyZXN0YXVyYW50IGluIGNocmlzdGNodXJjaEjh9auu-q6AgAhaKBAAGAAYAiIacmVzdGF1cmFudCBpbiBjaHJpc3RjaHVyY2gqBAgDEACSAQpyZXN0YXVyYW50qgEMEAEqCCIEZm9vZCgA,y,ZeJbBWd7wDg;mv:[[-43.4870861,172.6509735],[-43.5490232,172.5976049]]" ]  i = 0 binaryfirefox = r'C:Program Files (x86)Mozilla Firefoxfirefox.exe' binarychrome = r'C:Program Files (x86)GoogleChromeApplicationchrome.exe'   options = Options()  #cap = DesiredCapabilities().CHROME #cap["marionette"] = True #cap = DesiredCapabilities().FIREFOX #options.binary = binaryfirefox #driver = webdriver.Firefox(options=options, capabilities=cap, executable_path="E:\Téléchargement\geckodriver.exe")  options.binary_location = binarychrome driver = webdriver.Chrome(options=options, executable_path="E:\Téléchargement\chromedriver.exe" )  # same reason tha Firefox i have to load one time # an url to accept manually the cookies #driver.get(link_df[0])     print(link_df) for url in link_df:  base_url = url # i['Link'] # link_df['Link'][i]  print(base_url)  driver.get(base_url)  WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[./span[text()='Newest']]"))).click()   title = driver.find_element_by_xpath("//div[@class='P5Bobd']").text  address = driver.find_element_by_xpath("//div[@class='T6pBCe']").text  overall_rating = driver.find_element_by_xpath("//div[@class='review-score-container']//span[@class='Aq14fc']").text   total_reviews_text = driver.find_element_by_xpath(  "//div[@class='review-score-container']//div//div//span//span[@class='z5jxId']").text  num_reviews = int(total_reviews_text.split()[0])  all_reviews = WebDriverWait(driver, 20).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#reviewSort .gws-localreviews__google-review')))  # time.sleep(2)  total_reviews = 0   while total_reviews lt; num_reviews:  #reload to avoid exception, or trap scroll with try/except but more expznsive  all_reviews = WebDriverWait(driver, 20).until(  EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#reviewSort .gws-localreviews__google-review')))   driver.execute_script('arguments[0].scrollIntoView(true);', all_reviews[-1])   total_reviews = len(all_reviews)  print(total_reviews, len(all_reviews))  time.sleep(1)   driver.get('https:ww.google.com') # or driver.close() if no bugs  time.sleep(3)  driver.close() driver.quit()  

Комментарии:

1. спасибо за решение. Я попробовал ваше второе предлагаемое решение. Я все еще получаю ту же ошибку. ошибка возникает в первом операторе внутри цикла while

2. Я также попробовал первое решение, но в итоге получил тот же результат. Я включил полный измененный код своей программы в исходный пост.

3. только один вопрос, зачем вы делаете просмотр прокрутки? не могли бы вы объяснить?

4. Я просто хотел перейти к концу последнего загруженного обзора страницы, чтобы она позволяла загружать больше повторений. Вот почему я использовал scrollview. Есть ли какой-нибудь лучший способ?

5. нет, я использую firefox, и у меня нет проблем, я вижу прокрутку для обоих URL-адресов. Вы провели тест, изменив порядок вашего URL-адреса?