Скрипт выдает ошибку при использовании определенной ссылки среди нескольких - PullRequest
2 голосов
/ 22 сентября 2019

Я написал скрипт, использующий scrapy в сочетании с selenium для анализа названия CEO различных компаний с веб-страницы.Вы можете найти названия различных компаний на целевой странице.Тем не менее, вы можете получить имя CEO, щелкнув по названию ссылки на компанию.

Следующий скрипт может анализировать ссылки разных компаний и использовать эти ссылки для очистки имен CEO 'S, за исключением второй компании. Когда скрипт пытается проанализировать имя CEO по ссылке второй компании, он встречает stale element reference error.Сценарий правильно выбирает остальные результаты, даже когда встречает эту ошибку по пути. Еще раз - он выдает только ошибку при разборе информации, используя вторую ссылку компании.Как странно !!

Ссылка на веб-страницу

Это то, что я пробовал до сих пор:

import scrapy
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class FortuneSpider(scrapy.Spider):

    name = 'fortune'
    url = 'http://fortune.com/fortune500/list/'

    def start_requests(self):
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver,10)
        yield scrapy.Request(self.url,callback=self.get_links)

    def get_links(self,response):
        self.driver.get(response.url)
        for item in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '[class*="searchResults__title--"]'))):
            company_link = item.find_element_by_css_selector('a[class*="searchResults__cellWrapper--"]').get_attribute("href")
            yield scrapy.Request(company_link,callback=self.get_inner_content)

    def get_inner_content(self,response):
        self.driver.get(response.url)
        chief_executive = self.wait.until(EC.presence_of_element_located((By.XPATH, '//tr[td[.="CEO"]]//td[contains(@class,"dataTable__value--")]/div'))).text
        yield {'CEO': chief_executive}

Это типРезультаты, которые я получаю:

Jeffrey P. Bezos

raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
  (Session info: chrome=76.0.3809.132)

Darren W. Woods
Timothy D. Cook
Warren E. Buffett
Brian S. Tyler
C. Douglas McMillon
David S. Wichmann
Randall L. Stephenson
Steven H. Collis
and so on------------

Как исправить ошибку, с которой сталкивается мой скрипт при работе со второй ссылкой компании?

PS Я могу использовать их API, чтобы получить всю информацию, но мне любопытно узнать, с чем связана эта странная проблема с вышеуказанным сценарием.

Ответы [ 4 ]

1 голос
/ 25 сентября 2019

Немного измененный подход должен получить вам весь желаемый контент с этого сайта без каких-либо проблем.Все, что вам нужно сделать, это сохранить все целевые ссылки в виде списка в методе get_links() и использовать return или yield при обратном вызове метода get_inner_content().Вы также можете отключить изображения, чтобы сделать скрипт немного быстрее.

Следующая попытка должна получить все результаты:

import scrapy
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from scrapy.crawler import CrawlerProcess

class FortuneSpider(scrapy.Spider):

    name = 'fortune'
    url = 'http://fortune.com/fortune500/list/'

    def start_requests(self):
        option = webdriver.ChromeOptions()
        chrome_prefs = {}
        option.experimental_options["prefs"] = chrome_prefs
        chrome_prefs["profile.default_content_settings"] = {"images": 2}
        chrome_prefs["profile.managed_default_content_settings"] = {"images": 2}

        self.driver = webdriver.Chrome(options=option)
        self.wait = WebDriverWait(self.driver,10)
        yield scrapy.Request(self.url,callback=self.get_links)

    def get_links(self,response):
        self.driver.get(response.url)
        item_links = [item.get_attribute("href") for item in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '[class*="searchResults__title--"] a[class*="searchResults__cellWrapper--"]')))]
        return [scrapy.Request(link,callback=self.get_inner_content) for link in item_links]

    def get_inner_content(self,response):
        self.driver.get(response.url)
        chief_executive = self.wait.until(EC.presence_of_element_located((By.XPATH, '//tr[td[.="CEO"]]//td[contains(@class,"dataTable__value--")]/div'))).text
        yield {'CEO': chief_executive}

if __name__ == "__main__":
    process = CrawlerProcess()
    process.crawl(FortuneSpider)
    process.start()

Или использование yield:

def get_links(self,response):
    self.driver.get(response.url)
    item_links = [item.get_attribute("href") for item in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '[class*="searchResults__title--"] a[class*="searchResults__cellWrapper--"]')))]
    for link in item_links:
        yield scrapy.Request(link,callback=self.get_inner_content) 
0 голосов
/ 28 сентября 2019

Вот как вы можете получить информацию о компании, не используя Selenium намного быстрее и легче.
Посмотрите, как я получаю company_name и change_the_world для извлечения других деталей.

import requests
from bs4 import BeautifulSoup
import re
import html

with requests.Session() as session:
    response = session.get("https://content.fortune.com/wp-json/irving/v1/data/franchise-search-results?list_id=2611932")
    items = response.json()[1]["items"]
    for item in items:
        company_name = html.unescape(list(filter(lambda x: x['key'] == 'name', item["fields"]))[0]["value"])
        change_the_world = list(filter(lambda x: x['key'] == 'change-the-world-y-n', item["fields"]))[0]["value"]

        response = session.get(item["permalink"])
        preload_data = BeautifulSoup(response.text, "html.parser").select_one("#preload").text
        ceo = re.search('"ceo","value":"(.*?)"', preload_data).groups()[0]

        print(f"Company: {company_name}, CEO: {ceo}, Change The World: {change_the_world}")

Результат:

Компания: Карвана, Генеральный директор: Эрнест С. Гарсия, Измени мир: нет
Компания: ManTech International, Генеральный директор: Кевин М. Филлипс, Измени мир: нет
Компания: NuStarEnergy, генеральный директор: Брэдли С. Баррон, Change The World: нет
Компания: Shutterfly, генеральный директор: Райан О'Хара, Change The World: нет
Компания: Spire, генеральный директор: Сюзанна Сизервуд, Change The World: нет
Компания: Align Technology, генеральный директор: Джозеф М. Хоган, Change The World: нет
Компания: Herc Holdings, генеральный директор: Лоуренс Х. Силбер, Change The World: нет
...

0 голосов
/ 25 сентября 2019

Чтобы проанализировать имена генеральных директоров различных компаний со страницы https://fortune.com/fortune500/search/ Selenium , достаточно одного и вам потребуется:

  • Scroll до последнего элемента на веб-странице.
  • Соберите атрибуты href и сохраните в списке.
  • Откройте hrefs во вкладке смежных
  • Переключите фокус на вновь открытую вкладку и вызовите WebDriverWait для visibility_of_element_located(), и вы можете использовать следующие Стратегии локатора :

    • Кодовый блок:

      # -*- coding: UTF-8 -*-
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      
      options = webdriver.ChromeOptions()
      options.add_argument("start-maximized")
      options.add_experimental_option("excludeSwitches", ["enable-automation"])
      options.add_experimental_option('useAutomationExtension', False)
      driver = webdriver.Chrome(options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe')
      driver.get("https://fortune.com/fortune500/search/")
      driver.execute_script("arguments[0].scrollIntoView(true);", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//span[text()='Explore Lists from Other Years']"))))
      my_hrefs = [my_elem.get_attribute("href") for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//a[starts-with(@class, 'searchResults__cellWrapper--') and contains(@href, 'fortune500')][.//span/div]")))]
      windows_before  = driver.current_window_handle
      for my_href in my_hrefs:
          driver.execute_script("window.open('" + my_href +"');")
          WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
          windows_after = driver.window_handles
          new_window = [x for x in windows_after if x != windows_before][0]
          driver.switch_to_window(new_window)
          print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//table/tbody/tr//td[starts-with(@class, 'dataTable__value')]/div"))).text)
          driver.close() # close the window
          driver.switch_to.window(windows_before) # switch_to the parent_window_handle
      driver.quit()
      
    • Выход на консоль:

      C. Douglas McMillon
      Darren W. Woods
      Timothy D. Cook
      Warren E. Buffett
      Jeffrey P. Bezos
      David S. Wichmann
      Brian S. Tyler
      Larry J. Merlo
      Randall L. Stephenson
      Steven H. Collis
      Michael K. Wirth
      James P. Hackett
      Mary T. Barra
      W. Craig Jelinek
      Larry Page
      Michael C. Kaufmann
      Stefano Pessina
      James Dimon
      Hans E. Vestberg
      W. Rodney McMullen
      H. Lawrence Culp Jr.
      Hugh R. Frater
      Greg C. Garland
      Joseph W. Gorder
      Brian T. Moynihan
      Satya Nadella
      Craig A. Menear
      Dennis A. Muilenburg
      C. Allen Parker
      Michael L. Corbat
      Gary R. Heminger
      Brian L. Roberts
      Gail K. Boudreaux
      Michael S. Dell
      Marc Doyle
      Michael L. Tipsord
      Alex Gorsky
      Virginia M. Rometty
      Brian C. Cornell
      Donald H. Layton
      David P. Abney
      Marvin R. Ellison
      Robert H. Swan
      Michel A. Khalaf
      David S. Taylor
      Gregory J. Hayes
      Frederick W. Smith
      Ramon L. Laguarta
      Juan R. Luciano
      .
      .
      .
      
0 голосов
/ 25 сентября 2019

Вы получаете Stale Element Exception, потому что в строке 24 вы переходите от исходной страницы.

    def get_inner_content(self,response):
        self.driver.get(response.url)
        ...

Поскольку вы просматриваете ссылки в строке 19 ...

 for item in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '[class*="searchResults__title--"]'))):

Любой последующий доступ к item будет предоставлен как Stale Element Exception, если вы попытаетесь выполнить доступ к нему, поскольку страница была удалена в контексте driver.

ВашСкрипт будет работать для "Walmart", так как это первый item.Вы получаете эту ошибку на Exxon Mobil, поскольку страница была перемещена из строки 24.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...