Python 如果不发送请求,则无法在方法之间传递参数
我已经用python创建了一个脚本,使用scrapy与selenium结合,从主页解析不同餐厅的链接,然后从它们的内部页面解析每个餐厅的名称 当我将scrapy与selenium结合使用时,回调(或在方法之间传递参数)如何在不发送请求的情况下工作? 以下脚本使用我无法摆脱的Python 如果不发送请求,则无法在方法之间传递参数,python,python-3.x,selenium,web-scraping,scrapy,Python,Python 3.x,Selenium,Web Scraping,Scrapy,我已经用python创建了一个脚本,使用scrapy与selenium结合,从主页解析不同餐厅的链接,然后从它们的内部页面解析每个餐厅的名称 当我将scrapy与selenium结合使用时,回调(或在方法之间传递参数)如何在不发送请求的情况下工作? 以下脚本使用我无法摆脱的self.driver.get(response.url)覆盖回调: import scrapy from selenium import webdriver from scrapy.crawler import Crawle
self.driver.get(response.url)
覆盖回调:
import scrapy
from selenium import webdriver
from scrapy.crawler import CrawlerProcess
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support import expected_conditions as EC
class YPageSpider(scrapy.Spider):
name = "yellowpages"
link = 'https://www.yellowpages.com/search?search_terms=Pizza+Hut&geo_location_terms=San+Francisco%2C+CA'
def start_requests(self):
self.driver = webdriver.Chrome()
self.wait = WebDriverWait(self.driver, 10)
yield scrapy.Request(self.link,callback=self.parse)
def parse(self,response):
self.driver.get(response.url)
for elem in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".v-card .info a.business-name"))):
yield scrapy.Request(elem.get_attribute("href"),callback=self.parse_info)
def parse_info(self,response):
self.driver.get(response.url)
elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".sales-info > h1"))).text
yield {"title":elem}
if __name__ == '__main__':
c = CrawlerProcess()
c.crawl(YPageSpider)
c.start()
你的意思是在函数之间传递变量吗?为什么不为此使用
meta
?不管有没有硒,它都能起作用。我使用与您相同的代码,只是两个小更新:
def parse(self,response):
self.driver.get(response.url)
for elem in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".v-card .info a.business-name"))):
yield scrapy.Request(elem.get_attribute("href"),
callback=self.parse_info,
meta={'test': 'test'}) # <- pass anything here
def parse_info(self,response):
self.driver.get(response.url)
elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".sales-info > h1"))).text
yield {"title": elem, 'data': response.meta['test']} # <- getting it here
def解析(self,response):
self.driver.get(response.url)
对于self中的元素。等待。直到(所有元素的存在位置((By.CSS\u选择器,“.v-card.info a.business-name”)):
生成scrapy.Request(elem.get_属性(“href”),
callback=self.parse_info,
meta={'test':'test'})#你的意思是在函数之间传递变量吗?为什么不为此使用meta
?不管有没有硒,它都能起作用。我使用与您相同的代码,只是两个小更新:
def parse(self,response):
self.driver.get(response.url)
for elem in self.wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".v-card .info a.business-name"))):
yield scrapy.Request(elem.get_attribute("href"),
callback=self.parse_info,
meta={'test': 'test'}) # <- pass anything here
def parse_info(self,response):
self.driver.get(response.url)
elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".sales-info > h1"))).text
yield {"title": elem, 'data': response.meta['test']} # <- getting it here
def解析(self,response):
self.driver.get(response.url)
对于self中的元素。等待。直到(所有元素的存在位置((By.CSS\u选择器,“.v-card.info a.business-name”)):
生成scrapy.Request(elem.get_属性(“href”),
callback=self.parse_info,
meta={'test':'test'})#@vezunchik已经指出的链接答案几乎能让你达到目的。唯一的问题是,当您使用完全相同的代码时,您将有多个chromedriver实例。要多次重复使用同一个驱动程序,可以尝试如下操作
在scrapy项目middleware.py中创建一个文件,并粘贴以下代码:
from scrapy.http import HtmlResponse
from selenium import webdriver
class SeleniumMiddleware(object):
def __init__(self):
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--headless")
self.driver = webdriver.Chrome(options=chromeOptions)
def process_request(self, request, spider):
self.driver.get(request.url)
body = self.driver.page_source
return HtmlResponse(self.driver.current_url, body=body, encoding='utf-8', request=request)
我想提出一个更新,以防你们想看看chmoedriver在可见模式下是如何遍历的。若要让浏览器可见漫游,请尝试以下操作:
from scrapy import signals
from selenium import webdriver
from scrapy.http import HtmlResponse
from scrapy.xlib.pydispatch import dispatcher
class SeleniumMiddleware(object):
def __init__(self):
self.driver = webdriver.Chrome()
dispatcher.connect(self.spider_closed, signals.spider_closed)
def process_request(self, request, spider):
self.driver.get(request.url)
body = self.driver.page_source
return HtmlResponse(self.driver.current_url, body=body, encoding='utf-8', request=request)
def spider_closed(self):
self.driver.quit()
使用以下脚本获取所需的内容。通过中间件使用selenium,每个url只会有一个请求(导航)。现在,您可以在spider中使用Selector()
来获取数据,如下所示
import sys
# The hardcoded address leads to your project location which ensures that
# you can add middleware reference within crawlerprocess
sys.path.append(r'C:\Users\WCS\Desktop\yourproject')
import scrapy
from scrapy import Selector
from scrapy.crawler import CrawlerProcess
class YPageSpider(scrapy.Spider):
name = "yellowpages"
start_urls = ['https://www.yellowpages.com/search?search_terms=Pizza+Hut&geo_location_terms=San+Francisco%2C+CA']
def parse(self,response):
items = Selector(response)
for elem in items.css(".v-card .info a.business-name::attr(href)").getall():
yield scrapy.Request(url=response.urljoin(elem),callback=self.parse_info)
def parse_info(self,response):
items = Selector(response)
title = items.css(".sales-info > h1::text").get()
yield {"title":title}
if __name__ == '__main__':
c = CrawlerProcess({
'DOWNLOADER_MIDDLEWARES':{'yourspider.middleware.SeleniumMiddleware': 200},
})
c.crawl(YPageSpider)
c.start()
@vezunchik已经指出的链接答案几乎可以让你达到目的。唯一的问题是,当您使用完全相同的代码时,您将有多个chromedriver实例。要多次重复使用同一个驱动程序,可以尝试如下操作
在scrapy项目middleware.py中创建一个文件,并粘贴以下代码:
from scrapy.http import HtmlResponse
from selenium import webdriver
class SeleniumMiddleware(object):
def __init__(self):
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("--headless")
self.driver = webdriver.Chrome(options=chromeOptions)
def process_request(self, request, spider):
self.driver.get(request.url)
body = self.driver.page_source
return HtmlResponse(self.driver.current_url, body=body, encoding='utf-8', request=request)
我想提出一个更新,以防你们想看看chmoedriver在可见模式下是如何遍历的。若要让浏览器可见漫游,请尝试以下操作:
from scrapy import signals
from selenium import webdriver
from scrapy.http import HtmlResponse
from scrapy.xlib.pydispatch import dispatcher
class SeleniumMiddleware(object):
def __init__(self):
self.driver = webdriver.Chrome()
dispatcher.connect(self.spider_closed, signals.spider_closed)
def process_request(self, request, spider):
self.driver.get(request.url)
body = self.driver.page_source
return HtmlResponse(self.driver.current_url, body=body, encoding='utf-8', request=request)
def spider_closed(self):
self.driver.quit()
使用以下脚本获取所需的内容。通过中间件使用selenium,每个url只会有一个请求(导航)。现在,您可以在spider中使用Selector()
来获取数据,如下所示
import sys
# The hardcoded address leads to your project location which ensures that
# you can add middleware reference within crawlerprocess
sys.path.append(r'C:\Users\WCS\Desktop\yourproject')
import scrapy
from scrapy import Selector
from scrapy.crawler import CrawlerProcess
class YPageSpider(scrapy.Spider):
name = "yellowpages"
start_urls = ['https://www.yellowpages.com/search?search_terms=Pizza+Hut&geo_location_terms=San+Francisco%2C+CA']
def parse(self,response):
items = Selector(response)
for elem in items.css(".v-card .info a.business-name::attr(href)").getall():
yield scrapy.Request(url=response.urljoin(elem),callback=self.parse_info)
def parse_info(self,response):
items = Selector(response)
title = items.css(".sales-info > h1::text").get()
yield {"title":title}
if __name__ == '__main__':
c = CrawlerProcess({
'DOWNLOADER_MIDDLEWARES':{'yourspider.middleware.SeleniumMiddleware': 200},
})
c.crawl(YPageSpider)
c.start()
我不太确定你的问题是什么。你想传递什么论点在哪里?错误是什么?将链接从parse()
传递到parse_info()
@NoSplitSherlock。我仍然不知道您遇到了什么错误。我没有收到任何错误。脚本已经在运行。然而,逻辑是错误的,这就是为什么我问这个问题?你根本没有解释错误的逻辑。你的剧本怎么了?你需要重写某些东西的事实?那你为什么要这么做?我这里没有信息。我不确定你的问题是什么。你想传递什么论点在哪里?错误是什么?将链接从parse()
传递到parse_info()
@NoSplitSherlock。我仍然不知道您遇到了什么错误。我没有收到任何错误。脚本已经在运行。然而,逻辑是错误的,这就是为什么我问这个问题?你根本没有解释错误的逻辑。你的剧本怎么了?你需要重写某些东西的事实?那你为什么要这么做?我这里没有信息。对了,你是@vezunchik,我可以像这样在方法之间传递变量。但是,问题是我的脚本使用yield scrapy.Request()
发送请求,然后再次使用self.driver.get(response.url)
导航。为了一个目的做两件不同的事情。没有任何方法可以让我的脚本将链接从一个方法传递到另一个方法,然后导航,因为你知道脚本使用这个yield scrapy.Request()
无效地发送请求,因为它没有任何效果。啊,明白了!非常有趣。关于你的问题,我已经找到了这个很有希望的线索,但我会稍后再尝试。也许这会对你有帮助。这里有一个有趣的解决两个请求问题的方法,比@venunchik的链接开销更大,但值得一读:没错,你是@vezunchik,我可以像这样在方法之间传递变量。但是,问题是我的脚本使用yield scrapy.Request()
发送请求,然后再次使用self.driver.get(response.url)
导航。为了一个目的做两件不同的事情。没有任何方法可以让我的脚本将链接从一个方法传递到另一个方法,然后导航,因为你知道脚本使用这个yield scrapy.Request()
无效地发送请求,因为它没有任何效果。啊,明白了!非常有趣。关于你的问题,我已经找到了这个很有希望的线索,但我会稍后再尝试。也许这会对你有帮助。这里有一个有趣的解决两个请求问题的方法,比@venunchik的链接开销更大,但值得一读: