【问题标题】:Scrapy multiprocessingScrapy 多处理
【发布时间】:2021-10-07 16:21:48
【问题描述】:

我正在尝试构建一个爬虫(使用 scrapy)从 main.py 启动蜘蛛并进行多处理。

第一个蜘蛛 (cat_1) 使用 scrapy.crawler.CrawlerProcess 启动而不进行多处理:

crawler_settings = Settings()
crawler_settings.setmodule(default_settings)
runner = CrawlerProcess(settings=crawler_settings)
runner.crawl(cat_1)
runner.start(stop_after_crawl=True)

它工作正常,我拥有 FEED 处理的所有数据。

下一个蜘蛛需要第一个蜘蛛的结果并进行多处理:

从第一个蜘蛛加载结果后,我创建了一个 URL 列表并将其发送到我的函数 process_cat_2()。该函数创建进程,每个进程都会启动蜘蛛 cat_2:

from multiprocessing import Process

def launch_crawler_cat_2(crawler, url):
    cat_name = url[0]
    cat_url = url[1]
    
    runner.crawl(crawler, cat_name, cat_url)


def process_cat_2(url_list):
    nb_spiders = len(url_list)
    list_process = [None] * nb_spiders
    
    while(url_list):
        for i in range(nb_spiders):
            if not (list_process[i] and list_process[i].is_alive()):
                list_process[i] = Process(target=launch_crawler_cat_2, args=(cat_2, url_list.pop(0)))
                list_process[i].start()
                # break

    # Wait all thread end
    for process in list_process:
        if process:
            # process.start()
            process.join()

问题是runner.crawl(crawler, cat_name, cat_url)(在 cat_2 中)没有抓取任何东西:

2021-10-07 17:20:38 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)

而且我不知道如何使用现有的twisted.internet.reactor 所以要避免这个错误:

twisted.internet.error.ReactorNotRestartable

使用时:

def launch_crawler_cat_2(crawler, url):
    cat_name = url[0]
    cat_url = url[1]
    
    runner.crawl(crawler, cat_name, cat_url)
    runner.start()

如何使用现有的 reactor 对象启动新蜘蛛?

【问题讨论】:

    标签: python web-scraping scrapy


    【解决方案1】:

    这里有一个解决方案,适用于那些与我一样陷入困境的人。我能够运行多个蜘蛛,其中一些蜘蛛需要以前的结果,而一些蜘蛛需要多处理。

    在不同的进程中初始化每个爬虫:

    import sys
    import json
    import pandas as pd
    from multiprocessing import Process
    
    ## Scrapy
    from scrapy.crawler import CrawlerProcess
    from scrapy.settings import Settings
    
    ## Spiders & settings
    from myproject.spiders.cat_1 import cat_1
    from myproject.spiders.cat_2 import cat_2
    from myproject import settings as default_settings
    
    ## Init crawler
    crawler_settings = Settings()
    crawler_settings.setmodule(default_settings)
    
    # runner = CrawlerRunner(settings=default_settings)
    runner = CrawlerProcess(settings=crawler_settings)
    
    def launch_crawler_cat_2(crawler, url):
        process = CrawlerProcess(crawler_settings)
        process.crawl(crawler,url[0],url[1])
        process.start(stop_after_crawl=True)
    
    def process_cat_2(url_list):
        nb_spiders = 5
        list_process = [None] * nb_spiders
        
        while(url_list):
            for i in range(nb_spiders):
                if not (list_process[i] and list_process[i].is_alive()):
                    list_process[i] = Process(target=launch_crawler_cat_2, args=(cat_2, url_list.pop(0)))
                    list_process[i].start()
                    break
    
        # Wait all thread end
        for process in list_process:
            if process:
                process.join()
    
    def crawl_cat_1():
        process = CrawlerProcess(crawler_settings)
        process.crawl(cat_1)
        process.start(stop_after_crawl=True)
    
    if __name__=="__main__":
    
        ## Scrape cat_1
        process_cat_1 = Process(target=crawl_cat_1)
        process_cat_1.start()
        process_cat_1.join()
    
        ##########################################################################
        ########## LOAD cat_1 RESULTS
        try:
            with open('./cat_1.json', 'r+', encoding="utf-8") as f:
                lines = f.readlines()
                lines = [json.loads(line) for line in lines]
                df_cat_1 = pd.DataFrame(lines)
        except:
            df_cat_1 = pd.DataFrame([])
    
        print(df_cat_1)
        if df_cat_1.empty:
            sys.exit('df_cat_1 empty DataFrame')
    
        df_cat_1['cat_1_tuple'] = list(zip(df_cat_1.cat_name, df_cat_1.cat_url))
        df_cat_1_tuple_list = df_cat_1.cat_1_tuple.tolist()
    
        process_cat_2(df_cat_1_tuple_list)
    

    【讨论】:

      【解决方案2】:

      嗯.. 我找到了一个解决方案,可以按照文档https://docs.scrapy.org/en/latest/topics/practices.html#run-scrapy-from-a-script

      的推荐,使用 CrawlerRunner 多次运行多个蜘蛛

      还有另一个 Scrapy 实用程序可以更好地控制爬取过程:scrapy.crawler.CrawlerRunner。这个类是一个瘦包装器,它封装了一些简单的帮助器来运行多个爬虫,但它不会以任何方式启动或干扰现有的反应器。

      使用这个类,应该在调度蜘蛛之后显式运行反应器。如果您的应用程序已经在使用 Twisted 并且您想在同一个反应器中运行 Scrapy,建议您使用 CrawlerRunner 而不是 CrawlerProcess。

      这是我的解决方案:https://stackoverflow.com/a/71643677/18604520

      【讨论】:

        猜你喜欢
        • 2019-05-12
        • 1970-01-01
        • 1970-01-01
        • 2015-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-28
        相关资源
        最近更新 更多