scrapy对接scrapy-splash

发布时间丨2021-12-09 19:14:08作者丨zhaomeng浏览丨8


最近工作中需要采集一些文献作为项目的内容,依旧是使用scrapy框架作为爬虫项目的基础,搭建分布式爬虫系统,提高效率。但是在分析到详情信息的时候发现,作者的基本信息无法获取到,看了一下是基于第三方的js渲染出来的(可以确认的是页面对作者信息做了保护,直接点击页面的作者信息的链接,会转到一个页面,意思就是不支持javascript)到这里我一开始是使用的selenium作为渲染的中间件,但是使用的效果并不理想,后来就使用了官方的scrapy-splash这个插件,这个需要安装,我是使用docker进行安装的。之后就是对他的使用有几种方式,下面一一解答。这个工具我一开始使用的常规的代理中间件的赋值方式,后来一直运行也正常,但实际时使用的本机IP,直到前天这个网站显示封掉了,爬虫报错了,what?什么鬼!,开始在网上找资料,终于找到了scrapy-splash的代理赋值不同于常规的方式。以为就此解决了,开始运行依旧不行。满脑子what????,明明代理ip已经添加了啊!输出参数里面也有啊!查资料,找到一篇知乎的文章发现他有讲到splash的代理源码,觉只是个大神,应该没错了,前面都没有问题,唯一不同就是中间件的优先级不同!问题找到啦!网络资源是比较多的但是也不是每篇都是对的,踩坑经过。特此来记录一下,以防后面时间久了忘了,毕竟不是谁都能背的上自己写的代码的!

第一步:scrapy-splash的docker安装如下:

docker pull scrapinghub/splash
docker run -d -p 8050:8050 --name splash scrapinghub/splash

本机浏览器运行结果如下:

第二步:scrapy-splash在scrapy中的三种使用方式:

首先安装:pip install scrapy-splash

配置settings.py,这里的代理中间件的数字是整个项目代理成功的关键!(这里网上还有博主说要在下载中间件的最后面设置代理中间件数字825,这TM天坑啊,就这个问题加班好一会才爬出来!)

DOWNLOADER_MIDDLEWARES = {
    'pubs.middlewares.ProxyMiddleware': 724, # 这个是重点数字小于725才生效
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,

}

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

项目依旧是按照分部署爬虫的配置进行的,上面的添加到配置文件settings.py就行,其他不变,还有就是spider.py文件的发起请求代码做一些修改,有三种方式:

  • 常规的分布式爬虫的入口请求
    # return scrapy.Request(url=data.get("url"),
            #                       headers=headers,
            #                       # dont_filter=True,
            #                       callback=self.parse,
            #                       cb_kwargs=cb_kwargs
            #                       )

     

  • 直接使用官方提供的:SplashRequest(url,callback=self.parse,args={'wait':'0.5'})方法
    # return SplashRequest(url=data.get('url'), callback=self.parse, args={'wait': '0.5'}, cb_kwargs=cb_kwargs)
  • 使用原生的scrapy.Request()运行splash配置
    return scrapy.Request(url=data.get("url"), callback=self.parse, meta={
                'splash': {
                    'args': {
                        # 在此处设置端点API的参数
                        'html': 1,
                        'png': 1,
    
                        # 'url' is prefilled from request url
                        # 'http_method' is set to 'POST' for POST requests
                        # 'body' is set to request body for POST requests
                    },
    
                    # optional parameters
                    'endpoint': 'render.html',  # optional; default is render.json
                    'splash_url': 'http://*******:8050',  # optional; overrides SPLASH_URL
                    'slot_policy': scrapy_splash.SlotPolicy.PER_DOMAIN,
                    'splash_headers': headers,  # optional; a dict with headers sent to Splash
                    'dont_process_response': True,  # optional, default is False
                    'dont_send_headers': True,  # optional, default is False
                    'magic_response': False,  # optional, default is True
                }
            }, cb_kwargs=cb_kwargs)

    我这边使用的是第三种的方式,配置splash。

第三步;编写及配置爬虫代理中间件(这里的代理ip池后面有时间也会专门写两篇文章记录一下,与各位分享)代码如下:

    def process_request(self, request, spider):
        # Called for each request that goes through the downloader
        # middleware.

        if not request.meta.get('proxy'):
            IP = requests.get(url=settings.get('PROXY_URL'))
            if IP.status_code == 200:
                IP = IP.json()
                if spider.name == "detailinfo":  # 需要使用splash渲染的爬虫名称
                    if request.meta.get('_splash_processed') is None:
                        request.meta['splash']['args']['proxy'] = "http://" + IP.get("ip")  # scrapy-splash配置ip
                        print(request.meta['splash'])
                else:  # 其余爬虫使用常规的代理配置
                    request.meta['proxy'] = "http://" + IP.get("ip")
                spider.logger.info("使用代理:" + "http://" + IP.get("ip"))

            elif IP.status_code == 500:
                spider.logger.info("代理服务器出错!")
            else:
                pass
        else:
            logging.info("代理存在")

 代理信息打印结果如下图:

到这里基本我遇到的代理不生效的问题就解决了!关键就是中间件的优先级问题!详细原因可以参考知乎这篇scrapy-splash的代理不生效?,本片文章没有详细介绍爬虫项目,而是着重记录了scrapy对接scrapy-splash的一系列问题!

文章原创,创作不易,转载请指明出处!

推荐文章:windows安装golang