scrapy 中的解析函数内联请求

Inline requests inside parse function in scrapy

本例中我想获取link.url的文本。因此 links 包含一组 url,并且在每次迭代中,附加来自 link.url 的文本。为此,scrapy 需要访问 link.url。我通过发送请求来做到这一点,然后回调函数应该提取文本。但是在输出文件中,我看到 text 字段包含 links.url 而不是 links.url 中的文本。 简而言之,我想要来自 scrapy shell 的 fetch 函数,其中 returns response 对象中的所有内容,但在 python 中。这就是我在下面的代码中尝试做的事情:

class TravelSpider(CrawlSpider):
    name = "travel"
    allowed_domains = allowed_domains
    start_urls = urls

    custom_settings = {
        'DOWNLOAD_DELAY': 5,
        'DEPTH_LIMIT': 1,
        #  'CLOSESPIDER_PAGECOUNT': 5
    }

    rules = [Rule(LinkExtractor(unique=True), callback='parse', follow=True, process_links=process_links)]

    def parse(self, response):
        items = []
        links = LinkExtractor(canonicalize=True, unique=True).extract_links(response)

        for link in links:
            is_allowed = False
            for allowed_domain in self.allowed_domains:
                if allowed_domain in link.url:
                    is_allowed = True

            if is_allowed:
                item = ScraperItem()
                item['url_from'] = response.url
                item['url_to'] = link.url
                request = scrapy.Request(link.url, callback=self.parse_single, meta={'item': item}, dont_filter=True)
                #  items.append(req.meta['item'])
                return request

    def parse_single(self, response):
        item = response.meta['item']
        para_text = ''.join(response.xpath('//p//text()').extract())
        span_text = ''.join(response.xpath('//span//text()').extract())
        div_text = ''.join(response.xpath('//div/text()').extract())
        item['text'] = clean_text(para_text + ' ' + span_text + ' ' + div_text)
        return item

我什至试过这个 library 但它似乎不起作用。

这是根据请求使用元数据的典型用例。你想做的在下面

  1. 生成没有文本的项目
  2. 将项目作为元数据传递给需要收集文本的请求url
  3. 一旦文本可用就产生该项目

未测试,但下面几行内容应该对您有所帮助

class TravelSpider(CrawlSpider):
    name = "travel"
    allowed_domains = allowed_domains
    start_urls = urls

    custom_settings = {
        'DOWNLOAD_DELAY': 5,
        'DEPTH_LIMIT': 1,
        #  'CLOSESPIDER_PAGECOUNT': 5
    }

    rules = [Rule(LinkExtractor(unique=True), callback='parse', follow=True, process_links=process_links)]

    def parse(self, response):
        items = []
        links = LinkExtractor(canonicalize=True, unique=True).extract_links(response)

        for link in links:
            is_allowed = False
            for allowed_domain in self.allowed_domains:
                if allowed_domain in link.url:
                    is_allowed = True

            if is_allowed:
                item = ScraperItem()
                item['url_from'] = response.url
                item['url_to'] = link.url
                yield scrapy.Request(link.url , self.parse_single, meta={'item': item}, dont_filter=True)

    def parse_single(self, response):
        item = response.meta['item']
        para_text = ''.join(response.xpath('//p//text()').extract())
        span_text = ''.join(response.xpath('//span//text()').extract())
        div_text = ''.join(response.xpath('//div/text()').extract())
        combined_text = clean_text(para_text + ' ' + span_text + ' ' + div_text)
        item['text'] = combined_text
        return item

meta 解决方案是一个很好的解决方案 (or even better using cb_kwargs) 但如果我正确理解你的问题,你就不需要这样做。

每个 response 都有 its request 作为属性。您可以访问请求的 headers 以获取 Referer,即发出请求的 url。您可以通过

response.request.headers.get("referer")

这个 returns 字节,所以你可以解码它(如果它不是 None),例如

from_url = response.request.headers.get("referer").decode("utf-8")

因为 scrapy 在其日志记录中执行此操作,所以实际上有一个函数可以直接获取此字符串

from scrapy.utils.request import referer_str
from_url = referer_str(response.request)

因此您可以将其直接放入您的 parse_single 函数中以获取您需要的所有信息

def parse_single(self, response):
    item = ScraperItem()
    item['url_from'] = referer_str(response.request)
    item['url_to'] = response.url
    
    para_text = ''.join(response.xpath('//p//text()').extract())
    span_text = ''.join(response.xpath('//span//text()').extract())
    div_text = ''.join(response.xpath('//div/text()').extract())
    combined_text = clean_text(para_text + ' ' + span_text + ' ' + div_text)
    item['text'] =  combined_text
    yield item