scrapy模拟登录代码演示及cookie原理说明

简介: 登录的需求有些数据,必须在登录之后才能查看,所以我们在爬取过程中就会产生模拟登录的需求,它有两个点:1、未登录的情况下无法查看数据,或者直接弹出登录框提示你先登录2、登录后登录状态的保持(通常可以理解为cookie的处理)登录的逻辑访问登录页面(部分网站会在登录页面设定token或标识来反爬虫,根据Network查看post数据来确认)构造登录所需数据,并携带伪造的数据发送登录请求(如token或标识、User-Agent/HOST/Referer等数据,向登录地址POST数据。

登录的需求

有些数据,必须在登录之后才能查看,所以我们在爬取过程中就会产生模拟登录的需求,它有两个点:
1、未登录的情况下无法查看数据,或者直接弹出登录框提示你先登录
2、登录后登录状态的保持(通常可以理解为cookie的处理)

登录的逻辑

  • 访问登录页面(部分网站会在登录页面设定token或标识来反爬虫,根据Network查看post数据来确认)
  • 构造登录所需数据,并携带伪造的数据发送登录请求(如token或标识、User-Agent/HOST/Referer等数据,向登录地址POST数据。)
  • 根据某个状态码或者登录后跳转url判断是否登录成功
  • 登录成功后获取start_urls,并且调用parse进行数据爬取

模拟登录注意的地方

登录爬取有几个特点,比如浏览器不能换,可能UserAgent也不能换、要用到cookie、页面可能会有重定向,通常表现为登录后跳转、页面需要发送token或其他标识,所以正则是个关键。

  • 最好不要用自动切换UserAgent的功能(未测试)
  • 必须在配置开启cookie,COOKIES_ENABLED = True
  • 关闭重定向禁止开关 #REDIRECT_ENABLED = False # 禁止重定向
  • robots协议也关掉 ROBOTSTXT_OBEY = False

代码实现

这里以东盟贷为例子,


示例网站

这是最简单的一种例子(登录时没有验证码、不用携带token、不用携带其他标识),仅仅需要把用户名和密码发送过去即可。

当你需要爬取投资列表的数据时,要到【我要投资】页面去爬,你想要打开那个页面他就会判断你是否登录,如果没登录就会给你直接跳转到登录界面

被强制跳转到登录页面
审查元素,看input name

那我们面对这种情况,就必须先登录后请求页面再爬取数据(我这里仅演示到登录完成),示例代码:

# -*- coding: utf-8 -*-
import scrapy


class DongmengSpider(scrapy.Spider):
    name = 'dongmeng'
    allowed_domains = ['www.dongmengdai.com']
    start_urls = ['https://www.dongmengdai.com/view/Investment_list_che.php?page=1']

    # 根据浏览器Network返回值来构造header,这是比较简单的header,复杂的还会有很多信息
    header = {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0",
        "HOST": "www.dongmengdai.com",
        "Referer": "https://www.dongmengdai.com/index.php?user&q=action/login",
    }

    def parse(self, response):
        """ 正式进入爬取区域 """
        pass

    def start_requests(self):
        """
        重载start_requests方法 待登录成功后,再进入parse进行数据爬取
            访问登录页面 并调用do_login方法进行登录
        """
        return [scrapy.Request('https://www.dongmengdai.com/index.php?user&q=action/login', headers=self.header, callback=self.do_login)]

    def do_login(self, response):
        """
        根据Network的信息 向登录地址发送请求
            携带用户名和密码 如果需要token或者其他标识则需要用正则进行匹配,然后放到login_data中
            调用is_login方法判断是否登录成功
        """
        login_url = "https://www.dongmengdai.com/index.php?user&q=action/login"
        login_data = {
            "keywords": "18077365555",
            "password": "123456789"
        }
        return [scrapy.FormRequest(url=login_url,formdata=login_data,headers=self.header,callback=self.is_login)]

    def is_login(self, response):
        """
        这个网站登陆后会自动跳转到用户中心 可根据返回的url判断是否登录成功
            其他网站可以依靠状态码进行判断
            如果登录成功则从 start_urls中抽取url进行爬取
            这里不用设置callback回调parse 因为它默认调用parse
                如果是在crawl模板的爬虫,可能需要设置callback调用
         """
        if "index.php?user" in response.url:
            for url in self.start_urls:
                yield scrapy.Request(url, dont_filter=True, headers=self.header)
        else:
            print("登录失败")

具体逻辑整理

具体的逻辑我已经写在代码中了,这里再整理一下:
1、先确定起始url和设置domains
2、根据观察浏览器Network返回值来构造header(因为它也识别请求头信息)
3、重载start_requests方法并带上请求头信息来发起请求
4、do_login方法中执行具体的登录操作,(keywords和password是登录框的input name,通过右键审查元素可以看到html结构,通过input name来定位输入框)以及发起请求
5、is_login方法来判断是否登录成功,并且指定了下一步操作的方法(可以开始爬数据了)

Cookie的问题

可以看到,上面的代码里面只是发送了用户名和密码,但是常规的登录请求是需要保存和发送cookie的,我们在代码中并没有保存cookie和二次请求携带cookie的操作,那Scrapy是如何完成这个行为的呢?
在源码目录site-packages/scrapy/downloadermiddlewares/cookies.py文件中,可以看到具体的源码:

CookiesMiddleware的第前面两个个方法是重载from_crawler:

    def __init__(self, debug=False):
        self.jars = defaultdict(CookieJar)
        self.debug = debug

    @classmethod
    def from_crawler(cls, crawler):
        if not crawler.settings.getbool('COOKIES_ENABLED'):
            raise NotConfigured
        return cls(crawler.settings.getbool('COOKIES_DEBUG'))

init在加载的时候初始化CookieJar,from_crawler则是检查settings里面的cookie配置情况。

接着到process_request方法:

    def process_request(self, request, spider):
        if request.meta.get('dont_merge_cookies', False):
            return

        cookiejarkey = request.meta.get("cookiejar")
        jar = self.jars[cookiejarkey]
        cookies = self._get_request_cookies(jar, request)
        for cookie in cookies:
            jar.set_cookie_if_ok(cookie, request)

        # set Cookie header
        request.headers.pop('Cookie', None)
        jar.add_cookie_header(request)
        self._debug_cookie(request, spider)

它完成的任务大致就是设置cookie,请求的时候就带上。

而process_response方法又完成了什么任务呢:

    def process_response(self, request, response, spider):
        if request.meta.get('dont_merge_cookies', False):
            return response

        # extract cookies from Set-Cookie and drop invalid/expired cookies
        cookiejarkey = request.meta.get("cookiejar")
        jar = self.jars[cookiejarkey]
        jar.extract_cookies(response, request)
        self._debug_set_cookie(response, spider)

它是完成cookie的筛选,提取cookie和删除废弃的cookie

下面还有几个方法_debug_cookie、_debug_set_cookie、_format_cookie、_get_request_cookies他们几个完成了cookie的获取、生成和格式化等任务。

cookie小结

可以得出结论,Scrapy框架会自动帮我们处理cookie的问题,在常规的使用当中我们不需要关心它的切换和更新问题。只有在一些逻辑处理的时候,有可能涉及到登录逻辑的改动,才需要了解底层原理并对某个方法进行重载,以实现逻辑的变化。

目录
相关文章
|
4月前
|
存储 编解码 开发者
Cookie原理及使用细节
Cookie原理及使用细节
29 0
|
数据采集 中间件 Python
Python爬虫:scrapy管理服务器返回的cookie
Python爬虫:scrapy管理服务器返回的cookie
341 0
|
1月前
|
存储 安全 对象存储
Cookie和Session的区别:从原理到应用
【2月更文挑战第18天】
56 6
|
4月前
|
Python
scrapy模拟登录
scrapy模拟登录
21 0
|
5月前
|
数据采集 存储 中间件
【 ⑭】Scrapy架构(组件介绍、架构组成和工作原理)
【 ⑭】Scrapy架构(组件介绍、架构组成和工作原理)
145 0
|
JSON 中间件 数据格式
解决scrapy设置cookie中间件时遇到的问题
解释COOKIES_ENABLED作用: * 当COOKIES_ENABLED是注释的时候scrapy默认没有开启cookie * 当COOKIES_ENABLED没有注释设置为False的时候scrapy默认使用了settings里面的cookie * 当COOKIES_ENABLED设置为True的时候scrapy就会把settings的cookie关掉,使用自定义cookie
294 1
|
8月前
|
数据安全/隐私保护 Python
Python | Scrapy + Selenium模拟登录CSDN
Python | Scrapy + Selenium模拟登录CSDN
|
8月前
|
存储 编解码
cookie的相关概念及原理
cookie的相关概念及原理
76 0
|
9月前
|
存储 PHP
php开发实战分析(2):cookie的动态使用(设置、获取、删除、猜你喜欢原理、购物车调用)
php开发实战分析(2):cookie的动态使用(设置、获取、删除、猜你喜欢原理、购物车调用)
135 0
|
PHP 数据安全/隐私保护
PHP的cookie的域名、路径的区别是什么?底层原理是什么?
PHP的cookie的域名、路径的区别是什么?底层原理是什么?