美文网首页Python3自学 爬虫实战python学习Python
爬虫之scrapy-splash——scrapy+js渲染容器

爬虫之scrapy-splash——scrapy+js渲染容器

作者: playwolf719 | 来源:发表于2016-10-29 17:53 被阅读12874次

    简介


    scrapy作为爬虫利器,我就不多说了。
    常见的结合js的爬虫,一般用来扒取网页动态内容,就是通过操作js获取渲染的内容。
    现在大部分网站都是ajax+json获取数据的方式,所以,大家习惯性一上来爬虫,第一件事就是抓包,然后找规律抓数据。当然有时候,接口加密算法很复杂,短时间内很难破解,通过js抓取内容相对容易,这时候结合js的爬虫就能比较直接地达到目的,当然数据抓取效率不如直接抓接口来得快。

    结合js的爬虫


    目前,我知道的结合js的爬虫有以下3种。(有补充的,麻烦大神留言。)

    1. selenium+webdriver(如firefox,chrome等)。这要求你系统有对应浏览器,并且过程中要全程开浏览器。说白了,就是你通过浏览器能看到啥,就能抓到啥。一般遇到特别复杂的验证码时,这个方法是有必要的,当然,开着浏览器爬虫的效率可想而知。
    2. selenium+phantomjs。PhantomJS是一个WebKit,他的使用方法和webdriver一样,但是他不需要开浏览器,你可以直接跑在无需GUI的linux服务器上,这点很赞。
    3. scrapy-splash。这个和以上两种方法比,优势有以下几点。
    • splash作为js渲染服务,是基于Twisted和QT开发的轻量浏览器引擎,并且提供直接的http api。快速、轻量的特点使其容易进行分布式开发。
    • splash和scrapy融合,两种互相兼容彼此的特点,抓取效率较好。
    • 虽然目前只有英文文档,但写的已经很详细了,仔细阅读便能快速开发。

    本文主要介绍第三种爬虫方案的使用。

    安装


    关于安装,网上有很多了,请自行谷歌。
    这里建议遵循官网安装方式。但注意因为splash服务需要依托docker。而docker在Ubuntu的安装方法,需要仔细看下文档,并注意Ubuntu版本。

    启动


    安装docker之后,官方文档给了docker启动splash容器的命令(docker run -d -p 8050:8050 scrapinghub/splash),但一定要查阅splash文档,来了解启动的相关参数。
    比如我启动的时候,就需要指定max-timeout参数。因为我操作js时间较长时,很有可能超出默认timeout时间,以防万一我设定为3600(一小时),但对于本来js操作时间就不长的的同学,注意不要乱设定max-timeout。
    docker run -d -p 8050:8050 scrapinghub/splash --max-timeout 3600

    使用


    关于scrapy-splash的使用教程主要来自scrapy-splash githubsplash官方文档。除此之外,给出我最近写的一个scrapy-splash的代码。该代码主要实现js页面不断切换,然后抓取数据,下面是该代码的核心部分。因为,splash使用lua脚本实现js的操作,看下官方文档和这个代码,基本可以入门splash了。

    fly_spider.py

    class FlySpider(scrapy.Spider):
        name = "FlySpider"
        house_pc_index_url='xxxxx'
    
        def __init__(self):
            client = MongoClient("mongodb://name:pwd@localhost:27017/myspace")
            db = client.myspace
            self.fly = db["fly"]
    
        def start_requests(self):
            
    
            for x in xrange(0,1):
                try:
                    script = """
                    function process_one(splash)
                        splash:runjs("$('#next_title').click()")
                        splash:wait(1)
                        local content=splash:evaljs("$('.scrollbar_content').html()")
                        return content
                    end
                    function process_mul(splash,totalPageNum)
                        local res={}
                        for i=1,totalPageNum,1 do
                            res[i]=process_one(splash)
                        end
                        return res
                    end
                    function main(splash)
                        splash.resource_timeout = 1800
                        local tmp=splash:get_cookies()
                        splash:add_cookie('PHPSESSID', splash.args.cookies['PHPSESSID'],"/", "www.feizhiyi.com")
                        splash:add_cookie('FEIZHIYI_LOGGED_USER', splash.args.cookies['FEIZHIYI_LOGGED_USER'],"/", "www.feizhiyi.com" )
                        splash:autoload("http://cdn.bootcss.com/jquery/2.2.3/jquery.min.js")
                        assert(splash:go{
                            splash.args.url,
                            http_method=splash.args.http_method,
                            headers=splash.args.headers,
                        })
                        assert(splash:wait(splash.args.wait) )
                        return {res=process_mul(splash,100)}
                        
                    end
                    """
                    agent = random.choice(agents)
                    print "------cookie---------"
                    headers={
                        "User-Agent":agent,
                        "Referer":"xxxxxxx",
                    }
                    splash_args = {
                        'wait': 3,
                        "http_method":"GET",
                        # "images":0,
                        "timeout":1800,
                        "render_all":1,
                        "headers":headers,
                        'lua_source': script,
                        "cookies":cookies,
                        # "proxy":"http://101.200.153.236:8123",
                    }
                    yield SplashRequest(self.house_pc_index_url, self.parse_result, endpoint='execute',args=splash_args,dont_filter=True)
                    # +"&page="+str(x+1)
                except Exception, e:
                    print e.__doc__
                    print e.message
                    pass
    

    如果想更深地利用scrapy-splash,请研究splash官方文档,另外,欢迎留言交流学习。

    相关文章

      网友评论

      • 小胖确实胖:很好!
      • 喵自在:你好楼主,我windows10本地安装的docker程序运行一段时间就显示服务器拒绝,http://localhost:8050也访问不了,但右下角docker还显示正在运行
        playwolf719:@喵自在 一个月50买台云主机吧,真心方便
      • 上將noodle:请问楼主,我原本可以爬取的网页,加了splash之后,就不停出现连接错误了。
        Error downloading <POST http://192.168.99.100:8050/render.html&gt;
        ...
        twisted.web_newclient.ResponseNeverReceived: [<twisted.python.failure.Failure twisted.internet.error.ConnectionLost: Connection to the other side was lost in a non-clean fashion.>]

        相关部分代码如下:
        def start_requests(self): for url in self.start_urls: yield scrapy.Request(url, self.parse, meta={ 'splash': { 'endpoint': 'render.html', 'args': {'wait': 0.5} } })

        请问有解决方法么?
      • 耶律履:请问下博主,因为我返回的response对象是SplashJsonResponse类型的,如果我想改变其body里面的值应该如何操作呢?其实我觉得你的代码可以改进,for循环取出每个网页的源代码后可以直接value赋值给body(然后直接用response.xpath就可以提取内容了)。但是问题就出在修改response的body报错了。
        playwolf719:这个我后来没有再研究了,不过,splash拿body的方式,我用的是js的方式,可能有别的方法,你可以看下。
      • 耶律履:楼主,请问下如果处理点击(比如点击下一页)这种异步加载的事件时,如何判断页面加载完后才获取页面代码呢?如果单独用splash:wait(1)可能有些页面没有加载完成,那可能有获取到前一页的代码。不知道博主用过splash:wait_for_resume这个函数吗?研究了很久也没有弄懂,但是感觉像是等待异步加载完成后在去获取页面源代码。
        耶律履:@playwolf719 @playwolf719 ready事件对应的是首次加载页面的时候吧?我记得selenium这些常用的自动化测试工具都有函数实现等待页面加载在执行的功能。splash硬是找不到。
        playwolf719:@Shyness 这个需要监测浏览器的ready事件,但我自己并没有再深入。
      • 4417970afa26:你好,请问SplashRequest的详细文档哪里有,告诉每一个参数是干什么的,可以取哪些值,这个文档不是splash的文档 吧!
        playwolf719:@破破爱吹牛 谢谢点赞,官方文档我文章中有提供链接,你看看就找到了
        4417970afa26:真心觉得楼主的代码写的好,特别清晰!!!
      • 腊伍璐:楼主不知道有没有找到可以让Splash保持渲染状态的方法?楼主贴的这种方法是一个lua脚本执行很多次,最后返回所有的结果。这样爬取的颗粒比较大,如果中间出现异常,不好处理。
        4417970afa26:您还,我也遇到相同的问题,不知道你是否找到了解决办法。
        playwolf719:@腊伍璐 这个可能需要你深入看下splash文档了,可以借助lua脚本记录日志或缓存

      本文标题:爬虫之scrapy-splash——scrapy+js渲染容器

      本文链接:https://www.haomeiwen.com/subject/kwcyuttx.html