Scrapy框架-模拟登录之JWT验证及post特殊格式数据(json)

简介: 一、背景之前有记录过普通的scrapy模拟登录,这种方法可以满足了日常爬虫的登录需求。但是技术一直在进步,近几年前后端分离的趋势越来越好,很多web都采用前后端分离的技术。

一、背景

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

但是技术一直在进步,近几年前后端分离的趋势越来越好,很多web都采用前后端分离的技术。那么登录后的用户权限验证就会出现jwt的形式。(主要是token方式的验证,在模拟登录中要解决的问题)

这里记录一下。

二、登录操作

前后端分离的项目,一般都是react、vue等js语言编写的(没有这方面经验的同志,可以不用往下看了)

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

输入图片说明

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

输入图片说明

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

输入图片说明

[图片上传失败...(image-9401fa-1531469273677)]

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

    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的意思,就是未获得授权,也就是用户权限验证不通过,经过多方资料查找,发现请求头中有这么一条:

[图片上传失败...(image-1322be-1531469273677)]

它就是用于用户权限验证的,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必须是数组

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

[图片上传失败...(image-e2574e-1531469273677)]

叫做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)

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

目录
相关文章
|
7天前
|
JSON 安全 数据安全/隐私保护
深度剖析:Python如何运用OAuth与JWT,为数据加上双保险🔐
【10月更文挑战第10天】本文介绍了OAuth 2.0和JSON Web Tokens (JWT) 两种现代Web应用中最流行的认证机制。通过使用Flask-OAuthlib和PyJWT库,详细展示了如何在Python环境中实现这两种认证方式,从而提升系统的安全性和开发效率。OAuth 2.0适用于授权过程,JWT则简化了认证流程,确保每次请求的安全性。结合两者,可以构建出既安全又高效的认证体系。
25 1
|
1月前
|
存储 中间件 API
ThinkPHP 集成 jwt 技术 token 验证
本文介绍了在ThinkPHP框架中集成JWT技术进行token验证的流程,包括安装JWT扩展、创建Token服务类、编写中间件进行Token校验、配置路由中间件以及测试Token验证的步骤和代码示例。
ThinkPHP 集成 jwt 技术 token 验证
|
16天前
|
数据采集 前端开发 数据处理
Scrapy的Lambda函数用法:简化数据提取与处理的技巧
在现代爬虫开发中,**Scrapy** 是一个广泛使用的高效 Python 框架,适用于大规模数据爬取。本文探讨如何利用 Python 的 **Lambda 函数** 简化 Scrapy 中的数据提取与处理,特别是在微博数据爬取中的应用。通过结合 **代理IP**、**Cookie** 和 **User-Agent** 设置,展示了实际用法,包括代码示例和优化技巧,以提高爬虫的稳定性和效率。使用 Lambda 函数能显著减少代码冗余,提升可读性,有效应对复杂的数据清洗任务。
|
15天前
|
消息中间件 数据采集 数据库
小说爬虫-03 爬取章节的详细内容并保存 将章节URL推送至RabbitMQ Scrapy消费MQ 对数据进行爬取后写入SQLite
小说爬虫-03 爬取章节的详细内容并保存 将章节URL推送至RabbitMQ Scrapy消费MQ 对数据进行爬取后写入SQLite
14 1
|
2月前
【Azure APIM】在APIM中实现JWT验证不通过时跳转到Azure登录页面
【Azure APIM】在APIM中实现JWT验证不通过时跳转到Azure登录页面
|
2月前
|
存储 开发框架 算法
ASP.NET Core 标识(Identity)框架系列(四):闲聊 JWT 的缺点,和一些解决思路
ASP.NET Core 标识(Identity)框架系列(四):闲聊 JWT 的缺点,和一些解决思路
|
2月前
|
API
【Azure Developer】记录一段验证AAD JWT Token时需要设置代理获取openid-configuration内容
【Azure Developer】记录一段验证AAD JWT Token时需要设置代理获取openid-configuration内容
|
2月前
|
JSON Java API
【Azure Developer】如何验证 Azure AD的JWT Token (JSON Web 令牌)?
【Azure Developer】如何验证 Azure AD的JWT Token (JSON Web 令牌)?
|
2月前
|
JSON 算法 API
【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
|
2月前
|
存储 开发框架 JSON
ASP.NET Core 标识(Identity)框架系列(二):使用标识(Identity)框架生成 JWT Token
ASP.NET Core 标识(Identity)框架系列(二):使用标识(Identity)框架生成 JWT Token