Scrapy: нехватка памяти за считанные минуты (уже используется аргумент JOBDIR) - PullRequest
0 голосов
/ 06 февраля 2020

Я строю скребок, который должен очищать изображения и кусочки информации о продуктах, найденных на Houzz.com. У меня есть ~ 460 стартовых URL, которые являются сетками продуктов, и я go для всех последующих страниц (нумерация страниц), чтобы сканировать все продукты. Я захожу на страницы продукта, чтобы получить некоторую информацию и одно изображение продукта.

При запуске моего паука у меня заканчивается память в течение нескольких минут, хотя я запускаю его на экземпляре EC2 с 32 ГБ памяти. Я просматривал некоторые страницы об утечках памяти на веб-сайтах Scrapy Docs, но не могу понять, почему у моего паука так мало памяти.

Я уже использую "-s" JOBDIR = crawls / houzz_spider "аргумент при сканировании. При взгляде на prefs () запросы, кажется, не взрываются, когда паук все еще работает, а у экземпляра еще не исчерпана память.

Кроме этого, я открываю некоторые txt-файлы в начале выполнения и напишите им URL-адреса, сведения о которых не могут быть найдены в данный момент. В случае, если это может иметь какое-либо отношение к этому ...

Мой паук (избавился от некоторых переменных, которые не являются):

import boto3
from boto3.dynamodb.conditions import Key
import logging

class HouzzSpider(scrapy.Spider):
    name = 'houzz_spider'

    log_file = open(LOG_FILENAME, "w+")
    left_file = open(LEFT_FILENAME, "w+")
    dup_file = open(DUP_FILENAME, "w+")

    logging.basicConfig(
        filename=CRAWLER_LOG_FILENAME,
    )

    wait = 4

    allowed_domains = ["www.houzz.com"]

    start_urls_file = 'start_urls.txt'

    product_page_url_selector = ".hz-product-card__link::attr(href)"
    product_name_selector = "h1.product-title::text"
    main_product_image_selector = "img.view-product-image-print::attr(src)"
    product_description_selector = "#productDescription *::text"
    price_selector = ".product-final-price::text"
    n_products_claimed_selector = ".hz-top-pagination__text > b::text"

    cats_dict = {}

    # AWS DynamoDB
    dynamodb = boto3.resource(...)
    table = dynamodb.Table('my-table')

    def get_product_grid_pages(self):
        f = open(self.start_urls_file, "r")
        cats_dict = {}
        for cat in f:
            if 'https' in cat:
                if '\n' in cat:
                    cat = cat.split('\n')[0]
                cats_dict[cat] = {'n_products_claimed' : None,              # N products the website claims there are
                                  'n_product_pages_counted': 0,            # N product pages visited
                                  'n_items_yielded': 0,                    # N items returned
                                  'n_overview_pages_counted': 0,           # Overview pages visited
                                  'n_pages_claimed': 1000}                 # N pages the website claims there are
        return cats_dict

    def start_requests(self):
        self.cats_dict = self.get_product_grid_pages()
        print("\n CATS:", list(self.cats_dict.keys()), '\n')
        for product_grid_url in list(self.cats_dict.keys()):
            yield SplashRequest(url=product_grid_url, callback=self.parse,  args={"wait": self.wait})

    def parse(self, response):
        for item in self.scrape_overview_page(response):
            yield item

    def parse_product_page(self, response):
        print("Start parsing product page...", response.url)

        furniture_item = response.meta['furniture_item']

        # PRODUCT NAME
        product_name = response.css(self.product_name_selector).extract_first()

        furniture_item['product_name'] = product_name

        if product_name != None:
            # Check if product is already in DB
            resp = self.table.query(
                KeyConditionExpression=Key('product_name').eq(product_name)
            )

            # Item does not exist yet
            if len(resp['Items']) == 0:

                # PRODUCT DESCRIPTION
                furniture_item['product_description'] = " ".join(response.css(self.product_description_selector).extract())
                furniture_item['price'] = response.css(self.price_selector).extract_first()

                # IMAGES
                furniture_item['image_urls'] = response.css(self.main_product_image_selector).extract()


                if (len(furniture_item['image_urls']) > 0) and (product_name != None):
                    yield furniture_item
            else:
                print('DUPLICATE')
        else:
            print('NONE as PRODUCT NAME')



    def scrape_overview_page(self, response):
        n_products_claimed_text_list = response.css(self.n_products_claimed_selector).extract()

        if '/p' in response.url:
            cat = response.url.split('/p/')[0]
        else:
            cat = response.url

        # LINKS TO PRODUCT PAGES
        product_page_urls = list(set(response.css(self.product_page_url_selector).extract()))
        N = len(product_page_urls)

        # RETRIEVE PRODUCTS
        for i in range(N):
            # INIT ITEM
            furniture_item = Houzz_Furniture_Item()
            furniture_item['product_page_url'] = product_page_urls[i]

            furniture_item['category'] = cat

            # Load product page with Splash
            product_page_request = SplashRequest(url=product_page_urls[i], callback=self.parse_product_page, args={"wait":self.wait})
            product_page_request.meta['furniture_item'] = furniture_item

            # Return the item + product details and images found on product page back to parser
            yield product_page_request
        # GO TO NEXT PAGE
        i = self.cats_dict[cat]['n_product_pages_counted']
        if i < self.cats_dict[cat]['n_pages_claimed']:

            next_page_full_url = cat + '/p/' + str(i)
            yield SplashRequest(url=next_page_full_url, callback=self.scrape_overview_page, args={"wait":self.wait})

Мои настройки:


#####################################
# S3                                #
#####################################

# IMAGES_STORE = MY S3 BUCKET

BOT_NAME = 'houzz_spider'

SPIDER_MODULES = ['furniture_scraper.spiders']
NEWSPIDER_MODULE = 'furniture_scraper.spiders'

# ALLOW DUPLICATES: FALSE (needed for different colours of same furniture item)
DUPEFILTER_CLASS = 'scrapy.dupefilters.BaseDupeFilter'

#####################################
# FOR USING SPLASH                  #
#####################################

SPLASH_URL = 'http://localhost:8050'

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

#####################################
# USING THE IMAGES PIPELINE         #
#####################################

ITEM_PIPELINES = {
    'furniture_scraper.pipelines.FurnitureImagePipeline': 1,
    'furniture_scraper.pipelines.DynamoDbPipeline': 1
}

IMAGES_URLS_FIELD = 'image_urls'
IMAGES_RESULT_FIELD = 'images'

#####################################
# AWS      ACCESS                   #
#####################################

# MY CREDENTIALS

#####################################
# AWS      dynano db                #
#####################################

# MY DB

#####################################
# DEBUG                             #
#####################################

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36'

MEMUSAGE_ENABLED = 1
MEMUSAGE_LIMIT_MB = 1024
CONCURRENT_REQUESTS = 100

Если бы кто-то мог указать мне правильное направление, это было бы здорово.

Заранее спасибо!

...