【问题标题】:How to make a for-loop to finish and only then fire a scrapy function如何使for循环完成,然后才触发scrapy函数
【发布时间】:2019-10-28 14:18:24
【问题描述】:

我有一个简单的蜘蛛类,它有两个功能。一个从起始页面获取链接并输入它们(也 - 获取下一页链接),另一个 - 解析每个链接(它指向的页面)。问题是我有一个 for 循环,它遍历链接并为每个链接生成一个 scrapy.Request,在这个 for 循环之后,我有一个 if 语句来检查当前页面是否是最后一个,如果不是 - - 我想产生带有下一页链接的第一个功能,如果是的话 - 停止蜘蛛并说“最后一页,伙计!”。

def parse(self, response):

    links = response.xpath('//tags_to_be_chosen/@href').getall()

    next_page = response.xpath('//tag_to_be_chosen/@href').get()

    check = response.xpath('//tag_to_be_chosen/text()').get()

    for link in links:
        yield scrapy.Request(response.urljoin(link.strip()), callback=self.parse_page)

    if 'specific_string_is' in check: # go to next page, but only after for loop has finished its job
        yield scrapy.Request(response.urljoin(next_page.strip()), callback=self.parse)
    else: # stop the crawler, because we've reached the last page
        print('We\'ve reached the last page!')

def parse_page(self, response):

    with open('file_to_write', 'a') as file: # when there's a table of items to be crawled (different tags used than for a single item)
        for item in response.xpath('//tags_to_be_chosen/text()').getall():
            file.write('{}\n'.format(item.strip()))
        else: # when there's a single item to be crawled (different tag used than for multiple items
            item = response.xpath('//tag_to_be_chosen').get()
            item = item.strip()
            item = re.sub('sth_to_be_deleted', '', item)
            file.write('{}\n'.format(item))

预期的结果是等到for循环完成调用第2个函数(输入并解析所有链接),然后才输入下一页链接。出于某种原因,if 正在检查,而for 仍在循环链接,正在调用解析下一页的函数(这意味着更改链接),并且该过程开始于未完成“旧”链接的新链接。


如 cmets 中所指出的,已完成大编辑:

【问题讨论】:

  • 您说“出于某种原因(可能就是这样),如果在 for 仍在循环链接时正在检查 if ”。我认为这是不可能的,除非parse 被多次调用,在这种情况下,可能其中一个调用在loop 中,而另一个调用已经到达if 语句。

标签: python function for-loop scrapy


【解决方案1】:

你究竟为什么要使用yield?这个方法是在外部迭代的吗?最后一个 IF 将在外部迭代完成后调用,但看起来您正在迭代局部变量 links。你可能不需要 yield 那里。

也不清楚您是尝试通过输入链接然后抓取链接的链接进行深度优先,还是尝试广度优先,从页面获取每个链接,然后解析主页,然后转到收集的链接。

对于链接scraping,您可以通过串行或并行两种方式实现此目的。

  • 对于串行,您只需执行一个 for 循环,通过其回调调用请求
  • 对于并行,您必须有一个线程池,将每个链接处理发送到一个线程,然后在 for 循环之后,加入池以等待所有线程,然后调用函数 2。

【讨论】:

  • 我正在使用yield,因为我认为这是 Scrapy 的工作方式......第一个链接在start_urlsparse 函数解析第一个链接,并从其内容中抓取 next_page 链接和所有链接到输入和抓取页面内容来源(它是 link for links)。然后是这个检查,如果next_page 链接被刮掉:如果是——它应该在循环结束后用新链接重新调用parse 函数(或者parse 函数可能只用于start_urls?) .如果不是——结束进程。出于某种原因,这个if 不是在之后调用的,而是与之并行的。是因为yield吗?
  • 是的,yield 会把你的方法变成一个生成器,所以当调用你的函数的外部函数调用next 时,for 循环会前进。一旦迭代完成,它将继续使用来自if not condition 的代码。您应该提供完整的示例,以便更容易理解。整个函数 1 和 2 以及这些函数的调用者。
  • 我对我的问题进行了重大修改。也许现在会更清楚,对于给您带来的不便,我们深表歉意。
  • parse_page 将在循环时被调用,因为您将它定义为 Request 对象的回调。所以:有人迭代parse,每次迭代都会创建一个请求,该请求将调用 parse_page。迭代完成后,将调用 parse 的最后几行,它们创建另一个 Request 对象,并回调 parse_page 。由于 parse_page 是同时调用的,因此您必须确保线程安全
  • 据我了解 Scrapy,parse 将以start_urls=[] 中的一个或多个链接开头。在我的情况下,这是一个单一的链接。前 3 个 response.xpath 分配指的是该链接。然后我循环并调用parse_page。但是在那个循环之后我没有调用parse_page。我正在调用parse,假设满足if 条件。无论如何,如何使parse_page 线程安全?
猜你喜欢
  • 1970-01-01
  • 2017-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多