美文网首页
scrapy模拟登录代码演示及cookie原理说明

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

作者: 中乘风 | 来源:发表于2018-07-13 14:56 被阅读0次

    登录的需求

    有些数据,必须在登录之后才能查看,所以我们在爬取过程中就会产生模拟登录的需求,它有两个点:
    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的问题,在常规的使用当中我们不需要关心它的切换和更新问题。只有在一些逻辑处理的时候,有可能涉及到登录逻辑的改动,才需要了解底层原理并对某个方法进行重载,以实现逻辑的变化。

    相关文章

      网友评论

          本文标题:scrapy模拟登录代码演示及cookie原理说明

          本文链接:https://www.haomeiwen.com/subject/dcnjpftx.html