如何使用Scrapy和Splash刮取基于AJAX的网站?

时间:2017-06-08 12:43:27

标签: javascript html ajax scrapy scrapy-splash

我想制作一个通用的刮刀,可以抓取并抓取任何类型的网站(包括AJAX网站)的所有数据。我已经广泛搜索了互联网,但找不到任何正确的链接,可以解释我如何Scrapy和Splash一起刮掉AJAX网站(包括分页,表格数据和点击页面显示之前的按钮)。我提到的每个链接都告诉我,Javascript网站可以使用Splash呈现,但没有关于使用Splash呈现JS网站的良好教程/解释。请不要给我与使用浏览器相关的解决方案(我想以编程方式执行所有操作,欢迎使用无头浏览器建议..但我想使用Splash)。

class FlipSpider(CrawlSpider):
    name = "flip"
    allowed_domains = ["www.amazon.com"]

    start_urls = ['https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=mobile']  

    rules = (Rule(LinkExtractor(), callback='lol', follow=True),

    def parse_start_url(self,response):

       yield scrapy.Request(response.url, self.lol, meta={'splash':{'endpoint':'render.html','args':{'wait': 5,'iframes':1,}}})

    def lol(self, response):
       """
       Some code

3 个答案:

答案 0 :(得分:1)

通过编写 JavaScript 功能,您可以模拟行为,例如 ckick 滚动告诉 Splash 在呈现页面时执行该脚本。

一个小例子:

您定义了一个 JavaScript 函数,用于选择页面中的元素,然后点击

(来源:splash doc

  -- Get button element dimensions with javascript and perform mouse click.
_script = """
function main(splash)
    assert(splash:go(splash.args.url))
    local get_dimensions = splash:jsfunc([[
        function () {
            var rect = document.getElementById('button').getClientRects()[0];
            return {"x": rect.left, "y": rect.top}
        }
    ]])
    splash:set_viewport_full()
    splash:wait(0.1)
    local dimensions = get_dimensions()
    splash:mouse_click(dimensions.x, dimensions.y)

    -- Wait split second to allow event to propagate.
    splash:wait(0.1)
    return splash:html()
end
"""

然后,当您request时,修改endpoint并将其设置为"execute",然后将"lua_script": _script添加到 args

例如:

def parse(self, response):
    yield SplashRequest(response.url, self.parse_elem,
                        endpoint="execute",
                        args={"lua_source": _script})

您会找到有关启动脚本 here

的所有信息

答案 1 :(得分:1)

Splash和分页的问题如下:

我无法生成一个Lua脚本,该脚本提供了一个响应格式的新网页(点击分页链接后)。而不是纯HTML。

因此,我的解决方案如下 - 点击链接并提取新生成的网址并将抓取工具指向此新网址。

所以,我在页面上有我执行的分页链接

yield SplashRequest(url=response.url, callback=self.get_url, endpoint="execute", args={'lua_source': script})

使用以下Lua脚本

def parse_categories(self, response):
script = """
             function main(splash)
                 assert(splash:go(splash.args.url))
                 splash:wait(1)
                 splash:runjs('document.querySelectorAll(".next-page")[0].click()')
                 splash:wait(1)
                 return splash:url()  
             end
             """

和get_url函数

def get_url(self,response):
    yield SplashRequest(url=response.body_as_unicode(), callback=self.parse_categories)

这样我就能循环查询。

同样地,如果你不期望新的URL,你的Lua脚本可以生成纯html,你必须使用正则表达式(这很糟糕) - 但这是我能做的最好的。

答案 2 :(得分:0)

我刚刚在这里回答了一个类似的问题:scraping ajax based pagination。我的解决方案是获取当前页面和最后页面,然后替换请求URL中的页面变量。

此外 - 您可以做的另一件事是查看浏览器开发工具中的网络选项卡,看看您是否可以识别调用的任何 API。如果您查看 XHR 下的请求,您可以看到返回 json 的请求。

然后就可以直接调用API,解析json/html响应了。以下是来自 scrapy 文档的链接:The Network-tool