我使用 scrapy
结合 selenium
编写了一个脚本,用于从网页解析不同公司 CEO
的姓名。您可以在登陆页面找到不同公司的名称。但是,一旦您点击公司名称链接,您就可以获得 CEO
的姓名。
以下脚本可以解析不同公司的链接,并使用这些链接来抓取除第二家公司之外的 CEO
的姓名。 当脚本尝试使用第二家公司的链接解析 CEO
的姓名时,遇到陈旧元素引用错误
。即使脚本在途中遇到该错误,它也会以正确的方式获取其余结果。再一次 - 它仅在使用第二个公司链接解析信息时抛出错误。多么奇怪!!
这是我迄今为止尝试过的:
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------------
How can I fix the error that my script encounters while dealing with the second company link?
PS 我可以使用他们的 api 来获取所有信息,但我很好奇为什么上面的脚本会面临这个奇怪的问题。
最佳答案
稍微修改一下的方法应该可以让您从该网站获得所有所需的内容,而不会出现任何问题。您需要做的就是将所有目标链接存储为 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)
关于python - 使用多个链接之间的特定链接时,脚本会引发错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58051328/