我的问题确实是与上一个问题相同的方法,但是在Scrapy 0.14中。
使用一个Scrapyspider访问多个网站
基本上,我有一个GUI,它接受域,关键字,标签名称等参数,并且我想创建一个通用的爬虫来为那些标签中的关键字搜寻这些域。通过覆盖spider管理器类或动态创建spider,我已经使用较旧的scrapy版本阅读了冲突的内容。首选哪种方法?如何实现和调用正确的解决方案?提前致谢。
这是我想使通用的代码。它还使用BeautifulSoup。我将其配对,因此希望不会删除对理解它至关重要的任何内容。
class MySpider(CrawlSpider): name = 'MySpider' allowed_domains = ['somedomain.com', 'sub.somedomain.com'] start_urls = ['http://www.somedomain.com'] rules = ( Rule(SgmlLinkExtractor(allow=('/pages/', ), deny=('', ))), Rule(SgmlLinkExtractor(allow=('/2012/03/')), callback='parse_item'), ) def parse_item(self, response): contentTags = [] soup = BeautifulSoup(response.body) contentTags = soup.findAll('p', itemprop="myProp") for contentTag in contentTags: matchedResult = re.search('Keyword1|Keyword2', contentTag.text) if matchedResult: print('URL Found: ' + response.url) pass
我使用Scrapy Extensions方法将Spider类扩展到一个名为Masterspider 的类,该类包括一个通用解析器。
下面是我的通用扩展解析器的非常“简短”的版本。请注意,一旦开始使用AJAX处理页面,就需要使用Javascript引擎(例如Selenium或BeautifulSoup)实现渲染器。还有许多其他代码来管理站点之间的差异(基于列标题的报废,处理相对URL和长URL,管理不同类型的数据容器等)。
使用Scrapy扩展方法的麻烦之处在于,如果某些不适合但我从未必须使用的方法,您仍然可以覆盖通用解析器方法。Masterspider类检查是否在特定于站点的spider类下创建了某些方法(例如parser_start,next_url_parser …),以允许进行特殊性管理:发送表单,根据页面中的元素构造next_url请求等。
由于我要抓取截然不同的网站,因此始终需要进行管理。这就是为什么我更愿意为每个抓取的站点保留一个类,以便我可以编写一些特定的方法来处理它(预处理/后处理,除了PipeLines,Request generators …)。
masterspider / sitespider / settings.py
EXTENSIONS = { 'masterspider.masterspider.MasterSpider': 500 }
masterspider / masterspdier / masterspider.py
# -*- coding: utf8 -*- from scrapy.spider import Spider from scrapy.selector import Selector from scrapy.http import Request from sitespider.items import genspiderItem class MasterSpider(Spider): def start_requests(self): if hasattr(self,'parse_start'): # First page requiring a specific parser fcallback = self.parse_start else: fcallback = self.parse return [ Request(self.spd['start_url'], callback=fcallback, meta={'itemfields': {}}) ] def parse(self, response): sel = Selector(response) lines = sel.xpath(self.spd['xlines']) # ... for line in lines: item = genspiderItem(response.meta['itemfields']) # ... # Get request_url of detailed page and scrap basic item info # ... yield Request(request_url, callback=self.parse_item, meta={'item':item, 'itemfields':response.meta['itemfields']}) for next_url in sel.xpath(self.spd['xnext_url']).extract(): if hasattr(self,'next_url_parser'): # Need to process the next page URL before? yield self.next_url_parser(next_url, response) else: yield Request( request_url, callback=self.parse, meta=response.meta) def parse_item(self, response): sel = Selector(response) item = response.meta['item'] for itemname, xitemname in self.spd['x_ondetailpage'].iteritems(): item[itemname] = "\n".join(sel.xpath(xitemname).extract()) return item
masterspider / sitespider / spiders / somesite_spider.py
# -*- coding: utf8 -*- from scrapy.spider import Spider from scrapy.selector import Selector from scrapy.http import Request from sitespider.items import genspiderItem from masterspider.masterspider import MasterSpider class targetsiteSpider(MasterSpider): name = "targetsite" allowed_domains = ["www.targetsite.com"] spd = { 'start_url' : "http://www.targetsite.com/startpage", # Start page 'xlines' : "//td[something...]", 'xnext_url' : "//a[contains(@href,'something?page=')]/@href", # Next pages 'x_ondetailpage' : { "itemprop123" : u"id('someid')//text()" } } # def next_url_parser(self, next_url, response): # OPTIONAL next_url regexp pre-processor # ...