Scrapy

时间:2018-02-27 21:55:32

标签: python python-3.x scrapy scrapy-spider

使用Scrapy,我试图从维基百科中搜索所有语言的链接网络。每个维基百科页面都应包含指向维基数据项目的链接,该项目可以唯一标识所有语言的页面主题。我试图实现的过程如下:

  1. 首先,从每个页面(“源”链接)中提取维基数据链接。
  2. 浏览页面上的其余链接。
  3. 对于每个链接,使用新的回调函数向相应的页面(“目标”链接)发送请求。
  4. 从相应的目标网页中提取维基数据链接。
  5. 遍历目标网页上的所有链接,并回拨原始的parse功能。
  6. 基本上,我想跳过给定源页面上的中间链接,而是抓住相应的维基数据链接。

    这是我到目前为止的(半工作)代码:

    from urllib.parse import urljoin, urlparse
    from scrapy import Spider    
    from wiki_network.items import WikiNetworkItem
    
    WD = \
        "//a/@href[contains(., 'wikidata.org/wiki/Special:EntityPage') \
        and not(contains(., '#'))][1]"
    
    TARGETS = \
        "//a/@href[contains(., '/wiki/') \
        and not(contains(., 'wikidata')) \
        and not(contains(., 'wikimedia'))]"
    
    class WikiNetworkSpider(Spider):
        name = "wiki_network"
        allowed_domains = ["wikipedia.org"]    
        start_urls = ["https://gl.wikipedia.org/wiki/Jacques_Derrida"]
        filter = re.compile(r"^.*(?!.*:[^_]).*wiki.*")               
    
        def parse(self, response):        
    
            # Extract the Wikidata link from the "source" page
            source = response.xpath(WD).extract_first()       
    
            # Extract the set of links from the "source" page                         
            targets = response.xpath(TARGETS).extract()                
            if source:                
                source_title = response.xpath("//h1/text()").extract_first()                                      
                for target in targets:   
                    if self.filter.match(str(target)) is not None:
                        item = WikiNetworkItem()        
                        item["source"] = source
                        item["source_domain"] = urlparse(response.url).netloc
                        item["refer"] = response.url
                        item["source_title"] = source_title  
    
                        # Yield a request to the target page
                        yield Request(url=urljoin(response.url, str(target)), \
                                      callback=self.parse_wikidata, \
                                      meta={"item": item})
    
        def parse_wikidata(self, response):
            item = WikiNetworkItem(response.meta["item"])
            wikidata_target = response.xpath(WD).extract_first()
            if wikidata_target:      
    
                # Return current item
                yield self.item_helper(item, wikidata_target, response)
    
                # Harvest next set of links            
                for s in response.xpath(TARGETS).extract():
                    if self.filter.match(str(s)) is not None:
                        yield Request(url=urljoin(response.url, str(s)), \
                                      callback=self.parse, meta={"item": item})
    
        def item_helper(self, item, wikidata, response):
            print()
            print("Target: ", wikidata)        
            print()
            if item["source"] != wikidata:                
                target_title = response.xpath("//h1/text()").extract_first()                            
                item["target"] = wikidata
                item["target_title"] = target_title
                item["target_domain"] = urlparse(response.url).netloc
                item["target_wiki"] = response.url                                    
                print()
                print("Target: ", target_title)            
                print()
                return item 
    

    蜘蛛运行并刮擦链接一段时间(刮取的项目数通常达到620左右),但最终它会建立一个庞大的队列,完全停止刮擦,然后继续爬行。我是否应该期待它在某个时候再次开始刮擦?

    似乎应该有一种简单的方法在Scrapy中进行这种二级抓取,但到目前为止我读过的其他问题似乎主要是关于如何在Scrapy中处理分页,而不是如何处理以这种方式“折叠”一个链接。

1 个答案:

答案 0 :(得分:1)

只要蜘蛛没有问题,你真正想要的就是当你运行

make install

它应该yield Request(url=urljoin(response.url, str(target)), \ callback=self.parse_wikidata, \ meta={"item": item}) 早于下面类型的排队请求

yield

如果查看文档

https://doc.scrapy.org/en/latest/topics/request-response.html

  

priority(int) - 此请求的优先级(默认为0)。调度程序使用优先级来定义用于处理请求的顺序。具有更高优先级值的请求将更早执行。允许使用负值以指示相对较低的优先级。

所以你将使用

yield Request(url=urljoin(response.url, str(s)), \
                                  callback=self.parse, meta={"item": item})

yield Request(url=urljoin(response.url, str(target)), \
                                  callback=self.parse_wikidata, \
                                  meta={"item": item}, priority=1)

这将确保刮刀优​​先考虑将导致数据首先被删除的链接