我需要使用Scrapy(http://example.com/itemview)从网站中删除每个项目的数据。我有一个itemID列表,我需要在example.com中的表单中传递它。 每个项目都没有网址更改。因此对于我的蜘蛛中的每个请求,url将始终是相同的。但内容会有所不同。
我不会想要处理每个请求的for循环。所以我按照下面提到的步骤。
此后它会自动调用spider_closed信号。但我希望继续上述步骤,直到完成总项目ID。
class ExampleSpider(scrapy.Spider):
name = "example"
allowed_domains = ["example.com"]
itemIDs = [11111,22222,33333]
current_item_num = 0
def __init__(self, itemids=None, *args, **kwargs):
super(ExampleSpider, self).__init__(*args, **kwargs)
dispatcher.connect(self.item_scraped, signals.item_scraped)
dispatcher.connect(self.spider_closed, signals.spider_closed)
def spider_closed(self, spider):
self.driver.quit()
def start_requests(self):
request = self.make_requests_from_url('http://example.com/itemview')
yield request
def parse(self,response):
self.driver = webdriver.PhantomJS()
self.driver.get(response.url)
first_data = self.driver.find_element_by_xpath('//div[@id="itemview"]').text.strip()
yield Request(response.url,meta={'first_data':first_data},callback=self.processDetails,dont_filter=True)
def processDetails(self,response):
itemID = self.itemIDs[self.current_item_num]
..form submission with the current itemID goes here...
...the content of the page is updated with the given itemID...
yield Request(response.url,meta={'first_data':response.meta['first_data']},callback=self.processData,dont_filter=True)
def processData(self,response):
...some more scraping goes here...
item = ExamplecrawlerItem()
item['first_data'] = response.meta['first_data']
yield item
def item_scraped(self,item,response,spider):
self.current_item_num += 1
#i need to call the processDetails function here for the next itemID
#and the process needs to contine till the itemID finishes
self.parse(response)
我的piepline:
class ExampleDBPipeline(object):
def process_item(self, item, spider):
MYCOLLECTION.insert(dict(item))
return
答案 0 :(得分:0)
我希望我有一个优雅的解决方案。但相反,它是一种调用底层类的hackish方式。
self.crawler.engine.slot.scheduler.enqueue_request(scrapy.Request(url,self.yourCallBack))
但是,您可以在生成项目并将其回调到self.processDetails后生成请求。只需将其添加到您的processData函数:
yield item
self.counter += 1
yield scrapy.Request(response.url,callback=self.processDetails,dont_filter=True, meta = {"your":"Dictionary"}
此外,PhantomJS可以很好用,让你的生活轻松,但它比常规连接慢。如果可能的话,找到json数据的请求,或者在没有JS的情况下使页面不可解析的任何内容。为此,打开chrome,右键单击,单击inspect,转到网络选项卡,然后在表单中输入ID,然后查看XHR或JS选项卡,查找包含所需数据或下一个URL的JSON。大多数情况下,通过添加ID会有一些url,如果你能找到它,你可以连接你的url并直接调用它而不需要JS渲染的成本。有时它是随机的,或者没有,但我已经取得了相当大的成功。然后,您也可以使用它同时产生许多请求,而不必担心phantomJS会一次尝试做两件事或者必须初始化它的许多实例。你可以使用标签,但这很痛苦。
另外,我会使用您的ID队列来确保线程安全。否则,你可以让processDetails在同一个ID上调用两次,但是在程序的逻辑中,一切似乎都是线性的,这意味着你没有使用Scrapy的并发功能,你的程序会变得更慢。要使用队列添加:
import Queue
#go inside class definition and add
itemIDQueue = Queue.Queue()
#within __init__ add
[self.itemIDQueue.put(ID) for ID in self.itemID]
#within processDetails replace itemID = self.itemIDs[self.current_item_num] with
itemID = self.itemIDQueue.get()
然后没有必要增加计数器,你的程序是线程安全的。