#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:
Редактировать
- вы помещаете создание драйвера за пределы цикла for
- вы не можете запустить новый URL-адрес с данными gps, когда первое всплывающее окно всегда впереди, если вы его запустите, оно останется в бэкдоре, проще всего запустить новый URL-адрес без данных gps — gt; https:ww.google.com и подождите 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-адреса?