woaipojiene 发表于 2021-7-21 09:30

scrapy模拟登录的三种方式

@(目录)

### 1. 了解模拟登录的作用
有些网站是需要登录之后才能访问的,即便是同一个网站,在用户登录前后页面所展示的内容也可能会大不相同,例如,未登录时访问http://www.openedv.com/home.php时,将会是以下的提示信息:


然而,登录后访问http://www.openedv.com/home.php将包含如下页面内容:


如果我们要爬取的是一些需要登录之后才能访问的页面数据就需要模拟登录了。通常我们都是利用的 Cookies 来实现模拟登录,在Scrapy中,模拟登陆网站一般有如下两种实现方式:
(1) 请求时携带Cookies
(2) 发送Post请求获取Cookies
### 2. scrapy请求时携带Cookies
#### 2.1 什么是cookies
Cookies简单来说就是用来存储用户的登录信息。
在 Web认证中 ,因为HTTP协议本身的局限,必须采用其他技术将相关认证标记以某种方式持续传送,以免客户从一个页面跳转至另一个页面时重新输入认证信息。基于Cookie的认证过程,主要由以下三个阶段组成:
(1)发布Cookie。当用户试图访问某Web站点中需要认证的资源时,Web服务器会检查用户是否提供了认证Cookie,如果没有,则将用户重定向到登录页面。在用户成功登录后,Web服务器会产生认证Cookie,并通过HTTP响应中的Set-Cookie头发送给客户端,用于对用户随后的请求进行检查和验证,接着将用户重定向到初始请求的资源。
(2)检索Cookie。在用户随后的访问请求中,客户端浏览器检索Path和Domain等属性与用户请求资源相匹配的Cookie,并将找到的Cookie通过HTTP请求中的Cookie头提交给Web服务器 。
(3)验证CookieWeb服务器提取客户端浏览器递交的Cookie,验证其中的访问令牌。若合法,则将访问请求的资源发送给客户端浏览器;反之则拒绝用户的访问请求。Cookie 认证技术简化了用户访问 Web 网站资源的过程,即用户只需在初次登录网站时输入身份信息进行认证,随后便可以访问被授权的所有站点资源,不再需要重复手工提交身份信息。
#### 2.2 cookies的组成
Cookie是一段不超过4KB的小型文本数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。其中:
(1)        Name/Value:设置Cookie的名称及相对应的值,对于认证Cookie,Value值包括Web服务器所提供的访问令牌。
(2)Expires属性:设置Cookie的生存期。有两种存储类型Cookie,会话性与持久性。Expires属性缺省时,为会话性Cookie,仅保存在客户端内存中,并在用户关闭浏览器时失效;持久性Cookie会保存在用户的硬盘中,直至生存期到或用户直接在网页中单击“注销”等按钮结束会话时才会失效。
(3)Path属性:定义了Web站点上可以访问该Cookie的目录。
#### 2.3 抓取cookies数据

#### 2.4        代码实现scrapy携带cookies请求
**1.**        scrapy默认初始(第一次)发起的是get请求,如果你想发起post请求或者是携带cookies参数进行请求,那该怎么办呢
解决办法就是利用start_request方法,对该方法进行改写,进行post请求或者是携带cookies的参数请求。
携带cookies参数请求的start_requests结构如下:

```
# 构造带cookies参数的初始请求
def start_requests (self):
      yield scrapy.Request(
            self.start_urls,
                                # 在本次请求中携带构造的cookies
                                # 这里需要注意cookies字典格式的数据
            cookies=cookies,
      )

```
**2.**        将字符串格式的cookie转化为字典格式
这里使用的是列表推导式,列表推导式提供了一种创建list的简便方法。应用程序创建列表时,列表中的元素来源于其他序列、可迭代对象或创建的一个满足一定条件的序列。

```
cookies = {i.split('='): i.split('=') for i in Cookie.split('; ')}
        print(cookies)
```
列表推导式最大的特点就是简洁,可以缩减代码量,若不使用列表推导式,那么以上代码可以等价为:

```
        item = {}
for i in Cookie.split('; '):
    key = i.split('=')
    value = i.split('=')
    item = value
print(item)
```
运行查看两个输出对应的结果:

从结果可以看出,两个代码运行结果完全一致,而列表推导式只用一行代码,就可以达到我们预期的效果。

**3.**        为了方便查看实验结果,我们将获取到的前端响应(response)的字符串保存到文件中。此时我们新定义一个parse函数来保存保存文件,默认保存到当前目录下,文件名为test.html。


**4**.        打开保存的test.html页面,与成功登录的页面进行对比


从实验结果中可以看出:我们保存的页面,和正常登录后访问的页面是一致的。至此,携带cookes参数的模拟登录实验成功。
完整代码:

```
import scrapy
class LogOpenSpider(scrapy.Spider):
    name = 'log_open'
    allowed_domains = ['openedv.com']
    start_urls = ['http://www.openedv.com/home.php']

#结合start_requests和列表推导式进行构造带cookie的请求
    def start_requests(self):
# 这里需自行复制cookies,过长不宜展示
                Cookie = ""   
      cookies = {i.split('='):i.split('=') for i in Cookie.split('; ')}
      yield scrapy.Request(
            self.start_urls,
            cookies=cookies,
      )
    def parse(self, response):
      print(response.request.headers)
      with open('test.html', 'w') as fp:
            fp.writelines(response.text)

```

### 3.         使用FormRequest发送POST模拟登录
#### 3.1GET请求和POST请求的区别
表单提交中get和post方式的区别有5点:
1)get是从服务器上获取数据,post是向服务器传送数据。
2)get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTPpost机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
3)对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。
4)get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。(这里有看到其他文章介绍get和post的传送数据大小跟各个浏览器、操作系统以及服务器的限制有关)
5)get安全性非常低,post安全性较高。
最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。
#### 3.2 抓包过程及代码实现
**1.**        Form表单中必需的 action 属性规定当提交表单时,向何处发送表单数据。这里我们抓取到action提交的url请求。如下图所示:


**2.**        使用谷歌浏览器抓包抓到第一步对应的action链接,查看post请求提交的参数

3.        接下来我们开始实验,代码如下:

```
import scrapy

class LogOpenSpider(scrapy.Spider):
    name = 'log_open'
    allowed_domains = ['openedv.com']
    start_urls = ['http://www.openedv.com/home.php']
       
# 发送Post请求获取Cookies
def parse(self, response):
          # 这里的post_data是上一步中抓取到的参数
      post_data = {
            'username': '15666054570',
            'cookietime': '2592000',
            'password': '15666054570li',
            'quickforward': 'yes',
            'handlekey': 'ls'
      }
# 这里的url链接是form表单提交(action)到的url链接
url='http://www.openedv.com/member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes'
      yield scrapy.FormRequest(url=url,
                           formdata=post_data,
                           callback=self.after_login)

    # 验证是否请求成功
    def after_login(self, response):
      print(response.request.headers)
      with open('test.html', 'w') as fp:
            print('保存成功')
            fp.writelines(response.text)

```

**4.**        查看运行结果

从运行的日志结果中可以看出,我们的带账号密码的form_data的POST请求已经发送成功,重定向到home.php页面,打开保存的html文件。
显示结果如下:

成功跳转到登录成功后页面,该实验完成。

### 4.         使用FormRequest.from_response模拟登录
scrapy.FormRequest.from_response()使用起来scrapy.FormRequest()更加简单方便,我们通常只需要提供用户相关信息(账户和密码)即可,scrapy.FormRequest.from_response()将通过模拟点击为我们填充好其他的表单字段并提交表单。
        抓包过程同上(略)
       实验代码如下:       
       

```
import scrapy

class LogOpenSpider(scrapy.Spider):
    name = 'log_open'
    allowed_domains = ['openedv.com']
    start_urls = ['http://www.openedv.com/home.php']

    # 自动获取相应中的表单,提交用户数据
def parse(self, response):
                                #这里注意form_data的键
#要跟前端form表单的name属性一致
      form_data = {
            'username': '15666054570',
            'password': '15666054570li'
      }
      yield scrapy.FormRequest.from_response(
response,
                  formdata=form_data,
callback=self.after_login)

    # 验证是否请求成功
    def after_login(self, response):
      print(response.request.headers)
      with open('test.html', 'w') as fp:
            fp.writelines(response.text)

```

代码运行结果:

实验完成!

woaipojiene 发表于 2021-7-21 09:34

这里不太好编辑,
感兴趣可以查看:https://blog.csdn.net/lijiamingccc/article/details/118958259?spm=1001.2014.3001.5501

QingYi. 发表于 2021-7-21 10:03

好文我需要學習一下。

h07799486 发表于 2021-7-21 10:50

你这厉害了,小白我看不懂哈

UangTsui 发表于 2021-7-21 11:04

学习了,就是代码格式没弄好
页: [1]
查看完整版本: scrapy模拟登录的三种方式