scrapy_splash开发记录

splash安装

splash真是好物,由于网站做了很多反爬虫,直接使用 scrapy.Request 访问网站接口爬取信息有很多限制,甚至连接口都不能直接发起成功,逆向 js 又特别麻烦,splash可以帮爬虫在访问网站时模拟浏览器,不管网站 js 怎么绕,都像你用浏览器打开这个网站一样方便,之后你指定 splash 返回的格式就可以愉快的处理爬取信息了,splash 的属性和定义网上都有哦。

我用的环境是 win7,splash 可以找教程来安装,和教程一样的步骤我在这里就不说了,我只说说我安装、开发splash遇到的问题及解决办法。

docker安装问题

按教程把 C:\Program Files\Docker Toolbox 目录下的 boot2docker.iso 放入 C:\Users\A-257.docker\machine\cache 中,但打开 docker 并未安装该镜像文件,而是联网下载同名的 iso 文件。
处理方法:docker首次安装需要 断网,它自己就会按你放的 iso 文件来安装了。
安装之后有只小鲸鱼,之后在 pull 下拉 splash 什么的就按教程走。
下载好后就启动,使用如下代码,可以后台运行 splash 服务。

docker run -it -d -p 8050:8050 scrapinghub/splash

验证是否开启就打开浏览器,输入http://192.168.99.100:8050/
网页能打开就是 splash 服务运行成功,接下来就可以用 splash 来请求爬取了。

scrapy对接splash

根据教程配置对接好 splash 后,项目有需求,需要访问两个网站,做不同的处理,一个是 json 格式,一个是 html 格式。
json 格式 Luna 脚本:

function main(splash, args)
  splash.response_body_enabled=1	# 这个一定要有,因为处理的是json的响应结果
  assert(splash:go(args.url))
  assert(splash:wait(3))
  return splash:har()
end

json 响应回调处理:

result = json.loads(response.body)
result['log']['entries'][-1]	# 这是我想处理的最后一个响应的url
# splash 返回成功的状态:
result['_splash_processing_state'] == 'finished'
result['response']['status'] == 200

html 格式 Luna 脚本:

function main(splash, args)
  splash:set_custom_headers({
      ["Cookie"] = args.cookie		# 这个对应网站的登录限制,成功登录网站后,刷新浏览器,控制台network看请求头的cookie,完整复制下来就好了,注意失效时要重登并更新此处的cookie哦
    })
  assert(splash:go(args.url))
  assert(splash:wait(3))
  return splash:html()
end

html 响应回调处理:

doc = pq(response.body)
# pyquery处理html,像jquery提取元素那样使用,很方便,doc()等同于$()

在 start_request 中请求 json 后,yield SplashRequest 排在后面请求 html,但发起请求时乱套了。。。
脚本本应该发起2个请求,但控制台总共输出3个,多出来的那个还是错的,出现异常:访问 json 网址,但回调处理的却是 html 的方法。
解决方法:在 json 回调方法中再用 yield SplashRequest 发起 html 请求。
发现问题:我遇到发起 html 请求时,发起失败了。后面找到原因是 meta 参数用了 json 响应的 meta 参数(前面用 scrapy.Request 时这两类请求的 meta 参数一样),splash 发起请求到响应过程中,meta 参数被重写了,,因此发起 html 请求时,splash 把这条请求做重发处理,阻止它发起。
解决方法:在响应方法中写每个 yield SplashRequest 时,meta、args 参数都要重新赋值,千万别图省事直接用了,不然摔倒都不知道在哪里绊的。

splash服务自动关闭

写好代码,愉快的看着爬虫爬取,结果爬了大概2小时,splash 请求没响应了。。
一开始以为是 docker 不经我允许自己私自关闭了,网上查的结果是docker容器自己会自动退出。好吧,自己退出我就用代码在把你拉起来。
splash服务关闭时,SplashRequest 请求失败会触发中间件的 process_exception 抛出异常,在这里我判断 request.meta 是否有 splash 参数,是就写如下代码来重新运行 splash 服务

    def process_exception(self, request, exception, spider):
        if 'splash' in request.meta:  # splash服务关闭
            scraping_hub = os.system("docker ps --format scrapinghub/splash")
            if scraping_hub == 1:
                print('docker 异常,请手动重启')
                time.sleep(30)
            elif scraping_hub == 0:
                scraping_hub = os.popen("docker ps --format scrapinghub/splash", "r")
                if not scraping_hub.read():
                    print('30s后自动开启splash服务,请保持docker正常连接')
                    time.sleep(30)
                    print('splash服务异常,重新开启splash服务中...')
                    os.system("docker run -d -p 8050:8050 scrapinghub/splash")
                elif 'proxy' in request.meta['splash']['args']:     # splash服务正常,换IP重新请求
                    ip = self.get_proxy(spider.name)
                    if ip:
                        request.meta['splash']['args']['proxy'] = ip
                scraping_hub.close()
        return request

在 process_exception 中加 return request 是不希望爬虫遇到异常抛出就自己关闭了,我要它一直爬下去,return request 就重新发起这个请求,反正我也用 redis 来缓存已成功爬取的信息了,没成功的再执行一次爬虫就好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值