用scrapy 模拟知乎的登录过程

本人刚开始学习,可能有些不对的地方,希望大家指正~~

首先,我们分析下知乎登陆的接口,打开浏览器,到知乎的登陆界面,随便输入一个账号密码,查看点击登陆它干了些什么(别输入正确的,不然他就跳到首页去啦~)
用scrapy 模拟知乎的登录过程_第1张图片
可以看到它调用了一个phone_num的接口(邮箱登陆同理就不演示了),再看下这个接口的参数
用scrapy 模拟知乎的登录过程_第2张图片
出了那个_xsrf外,其他参数根据名字大概都可以猜到了
我们先来看看这个_xsrf从哪里来的,打开网页源码,查找_xsrf,发现有一个叫_xsrf的隐藏input标签,值和我们传入的这个参数是一样的
这里写图片描述
这样,我们就可以直接去取了
除了这个_xsrf外,我们还看到有一个叫captcha的参数,我们猜测它应该就是验证码,我们为了看看这个验证码是如何获得的,刷新一下看看
这里写图片描述
发现它调了这样一个接口,我们把这个url复制下来,然后直接打开看看~发现正是我们的验证码,我们看这个验证码,他是让我们点击倒立的字,再看我们上传的参数,除了那张图片的大小外,还有一个input_points的参数,应该就是我们点击的点的坐标,服务器通过这个判断我们是否点击了倒立的字,如果我们这样传参数的话,验证码图片的大小我们看上去是固定的,但是这个坐标就比较麻烦了,我们再来分析一下这个请求验证码的url的参数,有3个参数,r,type,lang,最后一个参数好像是表示语言是中文,我们把它变为en验证一下,
这里写图片描述
发现请求变成了这样一张图片,这不就是直接输入验证码的图片了么~如果可以用这个输入验证码的话我们就可以解决验证码这个参数了

好了,请求的分析差不多就这样了~下面我们可以开始写代码了

先一下我使用的python版本为3.6
新建一个scrapy的项目,新建一个爬虫(以scrapy的base模板新建~另外,这篇文章就做登录的过程,item,pipelines,middleware,settings这些文件就用默认的就行了~)

我们想一下,这个登录的过程中,我们有两个接口需要调用,1是获取验证码,2就是登录,毫无疑问,获取验证码应该优先调用,我们把我们的初始url定为获取验证码,再看一下我们上面验证码接口的参数,有个r的参数,是一串数字,我们优先应该想到是一个和时间有关的参数,我们先用当前时间来试试,我们的入口函数start_requests就变成下面这样

    def start_requests(self):
        t = str(int(time.time() * 1000))
        captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + '&type=login&lang=en'
        return [scrapy.Request(url=captcha_url, headers={},
        callback=self.parser_captcha)]

debug 看下我们的回调函数的response
发现服务器返回了500的错误,并未进入我们的回调函数,再去看下我们的网络请求的header,我们知道scrapy对于cookie等一系列值都已经封装好了,但是下面有一个Use-Agent的参数,是需要我们传的,它表示了我们的系统信息以及我们的浏览器信息等一系列信息,我们直接在我们的浏览器复制这个,在我们的header里传进去,再次debug,进入到回调函数里了
用scrapy 模拟知乎的登录过程_第3张图片
看出body是一个二进制文件,我们把文件写入本地看看是不是我们要的验证码图片(注意:这里要用pillow的Image来把图片展示出来),发现我们的猜测都是正确的,打开就是我们的验证码图片了,然后就是读取验证码里的信息问题了,这里就用简单的打开图片我们手动输入的方式,当然,还可以用云打码这种三方平台来读取验证码信息,就可以让爬虫全程不需要人来操作了
接下来,我们就需要去调用登录的接口了,记得前面我们说的参数有个_xsrf的,我们先去取这个参数

_xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()

参数都齐了,我们去调接口去~

    def login(self, response):
        xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()
        if xsrf is None:
            return ''
        post_url = 'https://www.zhihu.com/login/phone_num'
        post_data = {
            "_xsrf": xsrf,
            "phone_num": 'your phone number',
            "password": 'your password',
            "captcha": response.meta['captcha']
        }
        return [scrapy.FormRequest(url=post_url, formdata=post_data, headers=self.header, callback=self.check_login)]

后面还写了个检查登录是否成功的回调

    def check_login(self, response):
        js = json.loads(response.text)
        if 'msg' in js and js['msg'] == '登录成功':
            for url in self.start_urls:
                yield scrapy.Request(url=url, headers=self.header, dont_filter=True)

运行一下我们的爬虫
这里写图片描述
嗯 ,成功了,接下来就可以去主页上爬取自己感兴趣的内容了
第一次写博客,有很多东西可能描述的也不是很清楚,最后把这个爬虫的完整代码放上来吧

# -*- coding: utf-8 -*-
import json
import os

import scrapy
import time

from PIL import Image


class ZhihuloginSpider(scrapy.Spider):
    name = 'zhihulogin'
    allowed_domains = ['www.zhihu.com']
    start_urls = ['https://www.zhihu.com/']
    Agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
    header = {
        'User-Agent': Agent,
    }

    def parse(self, response):
        #主页爬取的具体内容
        pass

    def start_requests(self):
        t = str(int(time.time() * 1000))
        captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + '&type=login&lang=en'
        return [scrapy.Request(url=captcha_url, headers=self.header, callback=self.parser_captcha)]

    def parser_captcha(self, response):
        with open('captcha.jpg', 'wb') as f:
            f.write(response.body)
            f.close()
        try:
            im = Image.open('captcha.jpg')
            im.show()
            im.close()
        except:
            print(u'请到 %s 目录找到captcha.jpg 手动输入' % os.path.abspath('captcha.jpg'))
        captcha = input("please input the captcha\n>")
        return scrapy.FormRequest(url='https://www.zhihu.com/#signin', headers=self.header, callback=self.login, meta={
            'captcha': captcha
        })

    def login(self, response):
        xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()
        if xsrf is None:
            return ''
        post_url = 'https://www.zhihu.com/login/phone_num'
        post_data = {
            "_xsrf": xsrf,
            "phone_num": 'your phone number',
            "password": 'your password',
            "captcha": response.meta['captcha']
        }
        return [scrapy.FormRequest(url=post_url, formdata=post_data, headers=self.header, callback=self.check_login)]

    # 验证返回是否成功
    def check_login(self, response):
        js = json.loads(response.text)
        if 'msg' in js and js['msg'] == '登录成功':
            for url in self.start_urls:
                yield scrapy.Request(url=url, headers=self.header, dont_filter=True)

你可能感兴趣的:(scrapy学习笔记)