大数据

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

简介


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的demo。该demo主要实现js页面不断切换,然后抓取数据,下面是该demo的核心部分。因为,splash使用lua脚本实现js的操作,看下官方文档和这个demo,基本可以入门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官方文档,另外,欢迎留言交流学习。