利用Python实现模拟登录知乎


Posted in Python onMay 25, 2022

环境与开发工具

在抓包的时候,开始使用的是Chrome开发工具中的Network,结果没有抓到,后来使用Fiddler成功抓取数据。下面逐步来细化上述过程。

模拟知乎登录前,先看看本次案例使用的环境及其工具:

  • Windows 7 + Python 2.75
  • Chrome + Fiddler: 用来监控客户端与服务器的通讯情况,以及查找相关参数的位置。

Github源码下载

模拟过程概述

  • 使用Google浏览器结合Fiddler来监控客户端与服务端的通讯过程;
  • 根据监控结果,构造请求服务器过程中传递的参数;
  • 使用Python模拟参数传递过程。

客户端与服务端通信过程的几个关键点:

  • 登录时的url地址。
  • 登录时提交的参数【params】,获取方式主要有两种:第一、分析页面源代码,找到表单标签及属性。适应比较简单的页面。第二、使用抓包工具,查看提交的url和参数,通常使用的是Chrome的开发者工具中的Network, Fiddler等。
  • 登录后跳转的url。

参数探索

首先看看这个登录页面,也就是我们登录时的url地址。

利用Python实现模拟登录知乎

看到这个页面,我们也可以大概猜测下请求服务器时传递了几个字段,很明显有:用户名、密码、验证码以及“记住我”这几个值。那么实际上有哪些呢?下面来分分析下。

首先查看一下HTML源码,Google里可以使用CTRL+U查看,然后使用CTRL+F输入input看看有哪些字段值,详情如下:

利用Python实现模拟登录知乎

通过源码,我们可以看到,在请求服务器的过程中还携带了一个隐藏字段”_xsrf”。那么现在的问题是:这些参数在传递时是以什么名字传递的呢?这就需要借用其他工具抓包进行分析了。笔者是Windows系统,这里使用的是Fiddler(当然,你也可以使用其他的)。

抓包过程比较繁琐,因为抓到的东西比较多,很难快速的找到需要的信息。关于fiddler,很容易使用,有过不会,可以去百度搜一下。为了防止其他信息干扰,我们先将fiddler中的记录清除,然后输入用户名(笔者使用的是邮箱登录)、密码等信息登录,相应的在fiddler中会有如下结果:

利用Python实现模拟登录知乎

备注:如果是使用手机登录,则对应fiddler中的url是“/login/phone_num”。

为了查看详细的请求参数,我们左键单机“/login/email”,可以看到下列信息:

利用Python实现模拟登录知乎

请求方式为POST,请求的url为https://www.zhihu.com/login/email。而从From Data可以看出,相应的字段名称如下:

  • _xsrf
  • captcha
  • email
  • password
  • remember

对于这五个字段,代码中email、password以及captcha都是手动输入的,remember初始化为true。剩下的_xsrf则可以根据登录页面的源文件,取input为_xsrf的value值即可。

利用Python实现模拟登录知乎

对于验证码,则需要通过额外的请求,该链接可以通过定点查看源码看出:

利用Python实现模拟登录知乎

链接为https://www.zhihu.com/captcha.gif?type=login,这里省略了ts(经测试,可省略掉)。现在,可以使用代码进行模拟登录。

温馨提示:如果使用的是手机号码进行登录,则请求的url为https://www.zhihu.com/login/phone_num,同时email字段名称将变成“phone_num”。

模拟源码

在编写代码实现知乎登录的过程中,笔者将一些功能封装成了一个简单的类WSpider,以便复用,文件名称为WSpider.py。

# -*- coding: utf-8 -*-
"""
Created on Thu Nov 02 14:01:17 2016
@author: liudiwei
"""
import urllib
import urllib2
import cookielib
import logging  

class WSpider(object):
    def __init__(self):
        #init params
        self.url_path = None
        self.post_data = None
        self.header = None
        self.domain = None
        self.operate = None

        #init cookie
        self.cookiejar = cookielib.LWPCookieJar()
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookiejar))
        urllib2.install_opener(self.opener)

    def setRequestData(self, url_path=None, post_data=None, header=None):
        self.url_path = url_path
        self.post_data = post_data
        self.header = header

    def getHtmlText(self, is_cookie=False):
        if self.post_data == None and self.header == None:
            request = urllib2.Request(self.url_path)
        else:
            request = urllib2.Request(self.url_path, urllib.urlencode(self.post_data), self.header)
        response = urllib2.urlopen(request)
        if is_cookie: 
            self.operate = self.opener.open(request)
        resText = response.read()
        return resText

    """
    Save captcha to local    
    """    
    def saveCaptcha(self, captcha_url, outpath, save_mode='wb'):
        picture = self.opener.open(captcha_url).read() #用openr访问验证码地址,获取cookie
        local = open(outpath, save_mode)
        local.write(picture)
        local.close()    

    def getHtml(self, url):
        page = urllib.urlopen(url)
        html = page.read()
        return html


    """
    功能:将文本内容输出至本地
    @params
        content:文本内容
        out_path: 输出路径
    """
    def output(self, content, out_path, save_mode="w"):
        fw = open(out_path, save_mode)
        fw.write(content)
        fw.close()
        
    """#EXAMPLE
    logger = createLogger('mylogger', 'temp/logger.log')
    logger.debug('logger debug message')  
    logger.info('logger info message')  
    logger.warning('logger warning message')  
    logger.error('logger error message')  
    logger.critical('logger critical message')  
    """    
    def createLogger(self, logger_name, log_file):
        # 创建一个logger
        logger = logging.getLogger(logger_name)  
        logger.setLevel(logging.INFO)  

        # 创建一个handler,用于写入日志文件    
        fh = logging.FileHandler(log_file)  

        # 再创建一个handler,用于输出到控制台    
        ch = logging.StreamHandler()  
        # 定义handler的输出格式formatter    

        formatter = logging.Formatter('%(asctime)s | %(name)s | %(levelname)s | %(message)s')  
        fh.setFormatter(formatter)  
        ch.setFormatter(formatter)  
        # 给logger添加handler    

        logger.addHandler(fh)  
        logger.addHandler(ch)  
        return logger

关于模拟登录知乎的源码,保存在zhiHuLogin.py文件,内容如下:

# -*- coding: utf-8 -*-
"""
Created on Thu Nov 02 17:07:17 2016
@author: liudiwei

"""
import urllib
from WSpider import WSpider
from bs4 import BeautifulSoup as BS
import getpass
import json
import WLogger as WLog
"""
2016.11.03 由于验证码问题暂时无法正常登陆
2016.11.04 成功登录,期间出现下列问题
验证码错误返回:{ "r": 1, "errcode": 1991829, "data": {"captcha":"验证码错误"}, "msg": "验证码错误" }
验证码过期:{ "r": 1, "errcode": 1991829, "data": {"captcha":"验证码回话无效 :(","name":"ERR_VERIFY_CAPTCHA_SESSION_INVALID"}, "msg": "验证码回话无效 :(" }
登录:{"r":0, "msg": "登录成功"}
"""
def zhiHuLogin():
    spy = WSpider()
    logger = spy.createLogger('mylogger', 'temp/logger.log')
    homepage = r"https://www.zhihu.com/"    
    html = spy.opener.open(homepage).read()
    soup = BS(html, "html.parser")
    _xsrf = soup.find("input", {'type':'hidden'}).get("value")

    #根据email和手机登陆得到的参数名不一样,email登陆传递的参数是‘email',手机登陆传递的是‘phone_num'
    username = raw_input("Please input username: ")
    password = getpass.getpass("Please input your password: ")
    account_name = None
    if "@" in username:
        account_name = 'email'
    else:
        account_name = 'phone_num' 

    #保存验证码
    logger.info("save captcha to local machine.")
    captchaURL = r"https://www.zhihu.com/captcha.gif?type=login" #验证码url
    spy.saveCaptcha(captcha_url=captchaURL, outpath="temp/captcha.jpg") #temp目录需手动创建

    #请求的参数列表
    post_data = {
        '_xsrf': _xsrf,
        account_name: username,
        'password': password,
        'remember_me': 'true',
        'captcha':raw_input("Please input captcha: ")

    }

    #请求的头内容
    header ={
        'Accept':'*/*' ,
        'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With':'XMLHttpRequest',
        'Referer':'https://www.zhihu.com/',
        'Accept-Language':'en-GB,en;q=0.8,zh-CN;q=0.6,zh;q=0.4',
        'Accept-Encoding':'gzip, deflate, br',
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
        'Host':'www.zhihu.com'
    }

    url = r"https://www.zhihu.com/login/" + account_name
    spy.setRequestData(url, post_data, header)
    resText = spy.getHtmlText()
    jsonText = json.loads(resText)

    if jsonText["r"] == 0:
        logger.info("Login success!")
    else:
        logger.error("Login Failed!")
        logger.error("Error info ---> " + jsonText["msg"])

    text = spy.opener.open(homepage).read() #重新打开主页,查看源码可知此时已经处于登录状态
    spy.output(text, "out/home.html") #out目录需手动创建

if __name__ == '__main__':
    zhiHuLogin()

关于源码的分析,可以参考代码中的注解。

运行结果

在控制台中运行python zhiHuLogin.py,然后按提示输入相应的内容,最后可得到以下不同的结果(举了三个实例):

结果一:密码错误

利用Python实现模拟登录知乎

结果二:验证码错误

利用Python实现模拟登录知乎

结果三:成功登录

利用Python实现模拟登录知乎

通过代码,可以成功的登录到知乎,接着如果要爬取知乎里面的内容,就比较方便了。

以上就是利用Python实现模拟登录知乎的详细内容!


Tags in this post...

Python 相关文章推荐
简单介绍Python中的try和finally和with方法
May 05 Python
python编写简单爬虫资料汇总
Mar 22 Python
Ubuntu 16.04 LTS中源码安装Python 3.6.0的方法教程
Dec 27 Python
python与C互相调用的方法详解
Jul 14 Python
分享一个可以生成各种进制格式IP的小工具实例代码
Jul 28 Python
python爬虫租房信息在地图上显示的方法
May 13 Python
PyQt4 treewidget 选择改变颜色,并设置可编辑的方法
Jun 17 Python
通过selenium抓取某东的TT购买记录并分析趋势过程解析
Aug 15 Python
python 求定积分和不定积分示例
Nov 20 Python
python中count函数知识点浅析
Dec 17 Python
Python带你从浅入深探究Tuple(基础篇)
May 15 Python
使用python向MongoDB插入时间字段的操作
May 18 Python
python双向链表实例详解
May 25 #Python
Python实现双向链表基本操作
May 25 #Python
python实现双向链表原理
May 25 #Python
Python代码实现双链表
详解NumPy中的线性关系与数据修剪压缩
python实现双链表
May 25 #Python
Python实现双向链表
May 25 #Python
You might like
使用MaxMind 根据IP地址对访问者定位
2006/10/09 PHP
优化NFR之一 --MSSQL Hello Buffer Overflow
2006/10/09 PHP
php文件怎么打开 如何执行php文件
2011/12/21 PHP
PHP安装threads多线程扩展基础教程
2015/11/17 PHP
WordPress中访客登陆实现邮件提醒的PHP脚本实例分享
2015/12/14 PHP
PHP 使用位运算实现四则运算的代码
2021/03/09 PHP
2014 HTML5/CSS3热门动画特效TOP10
2014/12/07 Javascript
jQuery简单tab切换效果实现方法
2015/04/08 Javascript
详解JavaScript中数组的相关知识
2015/07/29 Javascript
基于jQuery实现的QQ表情插件
2015/08/25 Javascript
jQuery模拟实现天猫购物车动画效果实例代码
2017/05/25 jQuery
20行js代码实现的贪吃蛇小游戏
2017/06/20 Javascript
Vue.js常用指令之循环使用v-for指令教程
2017/06/27 Javascript
Angularjs的启动过程分析
2017/07/18 Javascript
vue进行图片的预加载watch用法实例讲解
2018/02/07 Javascript
原生JS实现前端本地文件上传
2018/09/08 Javascript
解决父组件将子组件作为弹窗调用只执行一次created的问题
2020/07/24 Javascript
使用Python的web.py框架实现类似Django的ORM查询的教程
2015/05/02 Python
再谈Python中的字符串与字符编码(推荐)
2016/12/14 Python
Python中模块与包有相同名字的处理方法
2017/05/05 Python
Python多版本开发环境管理工具介绍
2019/07/03 Python
python操作微信自动发消息的实现(微信聊天机器人)
2020/07/14 Python
python爬虫如何解决图片验证码
2021/02/14 Python
用CSS3实现瀑布流布局的示例代码
2017/11/10 HTML / CSS
新电JAVA笔试题目
2014/08/31 面试题
工商学院毕业生个人自我评价
2013/09/19 职场文书
信息专业个人的自我评价
2013/12/27 职场文书
2014年工作总结及2015工作计划
2014/12/12 职场文书
幼儿园三八妇女节活动总结
2015/02/06 职场文书
2015年度优秀员工自荐书
2015/03/06 职场文书
JavaScript实现贪吃蛇游戏
2021/06/16 Javascript
总结几个非常实用的Python库
2021/06/26 Python
Python上下文管理器Content Manager
2021/06/26 Python
css3中transform属性实现的4种功能
2021/08/07 HTML / CSS
德生TECSUN S-2000使用手册文字版
2022/05/10 无线电
使用opencv-python如何打开USB或者笔记本前置摄像头
2022/06/21 Python