如何在Scrapy CrawlSpider中找到当前的start_url?

时间:2018-09-10 12:34:46

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

当使用自己的脚本运行Scrapy时,该脚本从数据库加载URL并遵循这些网站上的所有内部链接,因此遇到了麻烦。我需要知道当前使用哪个start_url,因为我必须保持与数据库(SQL DB)的一致性。但是:当Scrapy使用名为“ start_urls”的内置列表来接收要遵循的链接列表并且这些网站具有立即重定向时,就会出现问题。例如,当Scrapy启动并且正在搜寻start_urls并且搜寻器遵循在那里找到的所有内部链接时,我以后只能确定当前访问的URL,而不能确定Scrapy起始的start_url。

网络上的其他答案是错误的,因为其他用例已被弃用,因为去年Scrapy的代码似乎有所更改。

MWE:

from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.crawler import CrawlerProcess

class CustomerSpider(CrawlSpider):
    name = "my_crawler"
    rules = [Rule(LinkExtractor(unique=True), callback="parse_obj", ), ]

    def parse_obj(self, response):
        print(response.url)  # find current start_url and do something

a = CustomerSpider
a.start_urls = ["https://upb.de", "https://spiegel.de"]  # I want to re-identify upb.de in the crawling process in process.crawl(a), but it is redirected immediately  # I have to hand over the start_urls this way, as I use the class CustomerSpider in another class
a.allowed_domains = ["upb.de", "spiegel.de"]

process = CrawlerProcess()

process.crawl(a)
process.start()

在这里,我提供了一个MWE,Scrapy(我的搜寻器)会在其中接收URL列表,就像我必须这样做一样。重定向网址示例为https://upb.de,它重定向到https://uni-paderborn.de

我正在寻找一种优雅的方式来处理此问题,因为我想利用Scrapy的众多功能(例如并行爬网等)。因此,我不想再使用诸如请求库之类的东西。我想找到当前在内部使用的Scrapy start_url(在Scrapy库中)。 感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

理想情况下,您将在原始请求上设置meta属性,然后在回调中引用它。不幸的是,CrawlSpider不支持通过meta传递Rule(请参阅#929)。

您最好构建自己的蜘蛛,而不是子类CrawlSpider。首先将您的start_urls作为参数传递给process.crawl,以使其可作为实例上的属性使用。在start_requests方法中,为每个URL产生一个新的Request,包括数据库密钥作为meta值。

parse收到加载URL的响应时,在其上运行LinkExtractor,并提出一个要求,分别将其刮取。在这里,您可以再次传递meta,将原始数据库密钥沿链传播。

代码如下:

from scrapy.spiders import Spider
from scrapy import Request
from scrapy.linkextractors import LinkExtractor
from scrapy.crawler import CrawlerProcess


class CustomerSpider(Spider):
    name = 'my_crawler'

    def start_requests(self):
        for url in self.root_urls:
            yield Request(url, meta={'root_url': url})

    def parse(self, response):
        links = LinkExtractor(unique=True).extract_links(response)

        for link in links:
            yield Request(
                link.url, callback=self.process_link, meta=response.meta)

    def process_link(self, response):
        print {
            'root_url': response.meta['root_url'],
            'resolved_url': response.url
        }


a = CustomerSpider
a.allowed_domains = ['upb.de', 'spiegel.de']

process = CrawlerProcess()

process.crawl(a, root_urls=['https://upb.de', 'https://spiegel.de'])
process.start()

# {'root_url': 'https://spiegel.de', 'resolved_url': 'http://www.spiegel.de/video/'}
# {'root_url': 'https://spiegel.de', 'resolved_url': 'http://www.spiegel.de/netzwelt/netzpolitik/'}
# {'root_url': 'https://spiegel.de', 'resolved_url': 'http://www.spiegel.de/thema/buchrezensionen/'}