文档章节

Scrapy登录之JWT验证及post特殊格式数据(json)

RNGLetme
 RNGLetme
发布于 2018/05/08 17:09
字数 1811
阅读 36
收藏 0

一、背景

之前有记录过,scrapy模拟登录。这种方法可以满足了日常爬虫的登录需求。

但是技术一直在进步,近几年前后端分离的趋势越来越好,很多web都采用前后端分离的技术。那么登录后的用户权限验证就会出现jwt的形式。

这里记录一下。

二、登录操作

前后端分离的项目,一般都是react、vue等js语言编写的,有些会采用成型的前端框架,如AntDesign,ElementUI等,它们写出来的web页面,如果用css定位或者xpath定位,是很不准确的。所以最好的办法就是观察数据流,找到api和发送的参数进行构造。

输入图片说明

以这里的登录为例,通过css定位其实也可以,但是有不稳定的风险。所以还是看api和参数比较稳妥,毕竟css怎么变,api都不会随意改变。

输入图片说明

选中post那条数据流,看到右侧的请求地址、请求头和参数

输入图片说明

输入图片说明

这样就可以根据请求地址、请求头和参数来构造登录用的代码:

    def start_requests(self):
        """ 重载start_requests方法 通过is_login方法判断是否成功登录 """
        login_url = "http://xxx.yyy.ccc.aa/api/v1/oauth/login"
        login_data = {
            "username": "abcd@easub.com",
            "password": "faabbccddeeffggd5",
            "type": "email"
        }

        return [scrapy.FormRequest(url=login_url, formdata=login_data, callback=self.is_login)]

    def is_login(self, response):
        """
        根据返回值中的message值来判断是否登录成功
            如果登录成功则对数据传输页发起请求,并将结果回传给parse方法
            如果登录失败则提示
        由于后面的用户权限验证需要用到token信息,所以这里取到登录后返回的token并传递给下一个方法
        """
        results = json.loads(response.text)
        if results['message'] == "succeed":
            urls = 'http://xxx.yyy.ccc.aa'
            access_token = results['data']['access_token']
            print("登录成功,开始调用方法")
            yield Request(url=urls, callback=self.parse, meta={"access_token": access_token})
        else:
            print("登录失败,请重新检查")

如果返回信息的json里面message值为succeed及认为登录成功,并调用parse方法。

三、用户权限验证

登录完毕后,我想执行其他的操作,比如上传(post)数据,跟刚才一样,需要观察api的地址和所需参数请求头信息等。

输入图片说明

输入图片说明

同样是根据返回的参数和请求头,来构造代码

然而这次却不行,返回的状态码是401,由于scrapy默认只管200和300的状态码,4开头和5开头的都不处理。但是又需要观察401状态返回的东西,可以在settings.py中空白处新增代码:

""" 状态码处理 """
HTTPERROR_ALLOWED_CODES = [400, 401]

然后在下一个方法中观察response回来的数据。

======================================

后来又查询了401的意思,就是未获得授权,也就是用户权限验证不通过,经过多方资料查找,发现请求头中有这么一条:

输入图片说明

它就是用于用户权限验证的,authorization的值分为两部分<type>和<credentials>,前者是验证采用的类型,后者是具体的参数值。这里的类型可以看到用的是Bearer类型,(传说值默认是用户名+密码的base64字符串,但这个这么长,显然不是64)。

我又去观察登录时候的返回值,发现登录成功后的返回值除了succeed之外,还有其他的一些返回值,里面包括了一个叫access_token的字段,它是用于JWT登录方式用来鉴权的token信息,而且authorization用的也正好就是这个token作为值。

那么代码就应该在第一次登录时候,取出access_token的值,并传递下去,用于后面请求的鉴权:

    def is_login(self, response):
        """
        根据返回值中的message值来判断是否登录成功
            如果登录成功则对数据传输页发起请求,并将结果回传给parse方法
            如果登录失败则提示
        由于后面的用户权限验证需要用到token信息,所以这里取到登录后返回的token并传递给下一个方法
        """
        results = json.loads(response.text)
        if results['message'] == "succeed":
            urls = 'http://xxx.yyy.ccc.aa'
            access_token = results['data']['access_token']
            print("登录成功,开始调用方法")
            yield Request(url=urls, callback=self.parse, meta={"access_token": access_token})
        else:
            print("登录失败,请重新检查")

下面的pase方法中,将authorization设定到header中以对数据进行请求:

header = {
            "authorization": "Bearer " + access_token
        }

这样就解决了用户权限的问题,不再出现401

四、postman发送请求特殊格式数据(json)

在parse方法中,根据浏览器观察到的参数,进行构造:

datas = {
                "url": "https://www.youtube.com/watch?v=eWeACm7v01Y",
                "title": "看上去可爱其实很笨的狗#动物萌宠#",
                "share_text": "看上去可爱其实很笨的狗#动物萌宠#[doge]",
                "categories": {'0': '00e2e120-37fd-47a8-a96b-c6fec7eb563d'}
        }

由于categories里面是个数组,所以在构造的时候也可以直接写数据,然后用scrapy.Formdata来进行post。发现返回的状态是这次是400,并且提示:categories必须是数组

再次观察请求头信息,发现请求头信息中还有:

输入图片说明

叫做content-type的参数,我将它加入到header中:

        header = {
            "authorization": "Bearer " + access_token,
            "content-type": "application/json",
        }

这样关于categories的提示就没有了。但是返回的状态码依然是400,而且提示变成了url不能为空,这到底又是怎么一回事?

多方探查都没有结果。

真是伤心

后来我又想起了,既然这里的文本类型是application/json,那么提交出去的文本应该是json类型数据,而不是python的dict字典类型数据。

于是打开json在线解析,对传递的参数进行观察,发现这样的数据并不满足json格式:

输入图片说明

后来尝试对它进行更改:

输入图片说明

在外层增加了一对{},然后又将categories的值加上了双引号,才是正确的json格式。

但是如果这样,拿到postman中进行测试,是不行的,后来经过反复测试,最终确定了postman的请求格式为:

输入图片说明

输入图片说明

输入图片说明

对Auth、Headers和Raw进行设置,才终于成功发送post,返回正确的信息!!!

五、scrapy发送Json格式数据

在postman测试通过后,说明这样的做法是可行的,但是代码上怎么编写呢?

用之前的scrapy.Formdata是不行的,它的formdat=默认使用dict格式,如果强行转成json格式也是会报错的。经过群里咨询和搜索,发现要用scrapy.http的Requst方法(平时常用的这个):

access_token = response.meta['access_token']
        urls = "http://aaa.bbb.xxx.yy/api/v1/material/extract"
        datas = {
                "url": "https://www.youtube.com/watch?v=eWeACm7v01Y",
                "title": "看上去可爱其实很笨的狗#动物萌宠#",
                "share_text": "看上去可爱其实很笨的狗#动物萌宠#[doge]",
                "categories": {'0': '00e2e120-37fd-47a8-a96b-c6fec7eb563d'}
        }
        header = {
            "authorization": "Bearer " + access_token,
            "content-type": "application/json",
        }
        yield Request(url=urls, method='POST', body=json.dumps(datas), headers=header, callback=self.parse_details)

这样才发送请求,终于成功了!!!

© 著作权归作者所有

RNGLetme
粉丝 0
博文 66
码字总数 77479
作品 0
朝阳
后端工程师
私信 提问
理解JSON Web Token【译】

原文 本文我们将来聊一聊JSON Web Token是什么。 先介绍一下他的基本概念,再来看看它的结构、最后创建一个服务器来获取一些数据然后插入到一个JWT中。 什么是JSON Web Token?为什么我们需要...

ITgecko
2018/11/27
0
0
单点登录(Single Sign On)解决方案

需求 多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登...

小致Daddy
2019/10/09
54
0
理解 JSON Web Tokens (JWT) 的 5 个简单步骤

原文链接:medium.com/vandium-sof… 在本文中,将解释JSON Web Tokens(JWT)的基本原理以及使用原因。 JWT 是确保应用程序信任和安全的重要部分。 JWT 允许以安全的方式表示诸如用户数据之...

腾讯IVWEB团队
2018/10/08
0
0
除了cookie,你还可以用jwt(json web token)!

1. 认识jwt(json web token) jwt是为了在网络应用环境传递声明而执行的一种基于json的开放标准。 jwt被用来在身份提供者和服务提供者间传递被认证的用户身份信息,简单来说,就是用来验证身...

Jeffywin
2018/08/03
0
0
JWT refreshtoken 实践

Json web token (JWT), 根据官网的定义,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)...

goodspeed
2019/04/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

今日头条技术架构分析,看这篇就对了!

点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 Anywhere, it is a good in the past, recall the number of times many, all would be ligh......

吧主
8分钟前
30
0
影响K8S Pod分配和调度策略的两大关键特性

在Kubernetes中有一个最复杂的调度器可以处理pod的分配策略。基于在pod规范中所提及的资源需求,Kubernetes调度器会自动选择最合适的节点来运行pod。 但在许多实际场景下,我们必须干预调度过...

RancherLabs
10分钟前
37
0
Linux笔记

Linux常用命令之chmod修改文件权限777和754 示例:chmod 777 /etc/squid 运行命令后,squid文件夹(目录)的权限就被修改为777(可读可写可执行)。...

owenzhang24
14分钟前
11
0
教你如何在CentOS7系统上安装postgreSQL11

本文教你如何在CentOS7系统上安装postgreSQL11。 1.添加PostgreSQL Yum存储库 sudo yum install https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-centos11-11-......

Linux就该这么学
21分钟前
37
0
欧盟将禁止公共场所人脸识别:谷歌支持,微软反对

   来源:新浪、VB   近日,彭博社披露的一份欧盟人工智能“白皮书”草案显示,欧盟计划对人工智能开发者提出具有法律约束力的新要求,以确保现代科技的开发和使用符合道德规范。    ...

水果黄瓜
24分钟前
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部