使用Scrapy-Splash加载抓取一个巨大的网页

时间:2018-03-20 22:36:48

标签: python selenium web-scraping scrapy scrapy-splash

我的系统规格:Ubuntu 17.10,4 gb RAM,50 gb swap

我的目标简短

我想从https://www.sanego.de/Arzt/Allgemeine+Chirurgie/抓取所有24.453条记录。

问题

我无法加载页面,似乎是因为它的大小

有关页面内容的更多详细信息

最初,网页只显示前30条记录。点击按钮' title =" Mehr anzeigen"'有一次我可以加载另外+30多条记录。这可以重复,直到加载所有记录。所以,它是用javascript动态生成的。

我的一般策略

我的想法是按下按钮' title =" Mehr anzeigen"'所有24.453条记录在页面上显示所需的次数。一旦完成,我将能够解析页面并收集所有记录。

Scrapy + Selenium方法

我尝试了两种不同的蜘蛛。首先,我尝试编写一个实现Selenium的Scrapy蜘蛛来渲染动态内容。但是,就内存使用而言,这种解决方案的成本太高。加载了大约1500条记录后,该过程会占用所有RAM和崩溃

Scrapy + Splash方法

我认为这个解决方案可能比前一个解决方案更快,内存要求更低,但是,页面加载超过了Splash的最大超时限制3600秒并且蜘蛛崩溃了。我下面只提供这个蜘蛛的代码,因为我觉得Splash可能是这种情况下更好的解决方案。请问你是否想要我添加另一个。

限制内存使用量

我在cgroups中运行了每个蜘蛛,内存限制为1GB。 spides保持在内存限制内,但在页面完全加载之前无论如何都会崩溃。

问题

请向我提供有关如何实现目标的任何建议

代码

我是如何开始飞溅的:

sudo cgexec -g memory:limitmem docker run -it --memory="1024m"
--memory-swappiness="100" -p 8050:8050 scrapinghub/splash --max-timeout 3600

我是如何运行蜘蛛的:

sudo cgexec -g memory:limitmem scrapy crawl spersonel_spider

蜘蛛的主要部分:

from scrapy_splash import SplashRequest
import time
import json     
import scrapy
from scrapy import Request
from sanego.items import PersonelItem

class SanegoSpider(scrapy.Spider):

    name = "spersonel_spider"

    start_urls = ['https://www.sanego.de/Arzt/Fachgebiete/','https://www.sanego.de/Zahnarzt/Fachgebiete/', 'https://www.sanego.de/Heilpraktiker/Fachgebiete/', 'https://www.sanego.de/Tierarzt/Fachgebiete/',]  

    def parse(self, response):

        search_urls = ["https://www.sanego.de" + url for url in response.xpath('//ul[@class="itemList"]/li[contains(@class,"col-md-4")]/a/@href').extract()]

        script = """
        function main(splash)

            local url = splash.args.url
            splash.images_enabled = false

            assert(splash:go(url))
            assert(splash:wait(1))

            local element = splash:select('.loadMore')
            while element ~= nil do
                assert(element:mouse_click())
                assert(splash:wait{2,cancel_on_error=true})
                element = splash:select('.loadMore')
            end
            return {
                html = splash:html(),
                --png = splash:png(),
                --har = splash:har(),
            }
        end
        """

        for url in search_urls:
            if url == 'https://www.sanego.de/Arzt/Allgemeine+Chirurgie/':
                yield SplashRequest(url, self.parse_search_results, args={'wait': 2, 'lua_source': script, 'timeout':3600},endpoint='execute', headers={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'})

1 个答案:

答案 0 :(得分:3)

该页面加载了更多关于AJAX的数据,因此使用简单的Scrapy模拟AJAX,而不使用Splash。

('p', '1')

注意$cultureInfo = New-Object System.Globalization.CultureInfo('de-de') 参数,并在到达最终页面之前保持增量。