知乎登陆[通俗易懂]

知乎登陆[通俗易懂]知乎登陆@(博客)[Python,登陆,知乎,爬虫]知乎登陆背景题外话环境寻找切入点问题的转移1问题的转移2继续撸开始代码完善代码018.8.12背景因为学年综合实践准备的一部分需要爬取知乎全站

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

知乎登陆

@(博客)[Python, 登陆, 知乎, 爬虫]

018.8.12

背景

因为学年综合实践准备的一部分需要爬取知乎全站,所以为了方便,自动登陆是很有必要的。而由于许多学习爬虫的各友,都爱拿知乎练手——其实我倒非然,这算是第一次对知乎“开战”,是客观因素导致的必然——以至于知乎加强了反扒机制
这里写图片描述

我爬虫经验有限,实在不知该对这样的加密如何下手,一番搜索引擎之后,得到的都是过期操作。Github上找到了通过二维码扫描登陆的思路,那就以此宣战吧。

也在此感谢这名网友的无私奉献,点击可查看

题外话

说句题外话:切不可以惯性思维

另:完整代码已上传Github,文章末尾有链接。里边的study文件是我整个思考过程中产生的测试代码,如果只是需要实现知乎登陆,则study文件可以直接删除

环境

(1)python3.6
(2)主要第三方库:
requests
PILpip3 install -i https://pypi.douban.com/simple/ pillow 利用豆瓣源,加快下载速度,因为直接安装可能会出现timeout的错误

(3)chrome

寻找切入点

这里写图片描述

第一步肯定是先来到知乎提供二维码登陆的界面,利用开发工具,可查看请求这个二维码图片需要那些数据
这里写图片描述
这里写图片描述

能看到是get请求,headers也很寻常,但多次刷新可发现请求的url地址有一部分在改变
这里写图片描述

这肯定算不上什么难点,我们寻找前面的文件,能找到这部分动态改变的值
这里写图片描述

为了方便阐述,那就把image称之为A文件,qrcode成为B文件。这里就有了一个思路,先请求B文件,拿到token值以后,拼接成目的url,再去请求A文件

问题的转移1

于是我们从A迁移到了B

这里写图片描述

可见请求B文件的时候,headers字段是真的很多,但绝对不会所有都必要,这只能排除法了

以我拙见是这样处理的,首先看清楚了,是POST请求(从爬虫到现在也几个月了,还是爬了不少网站,真的不提交数据用post请求的,我第一次见,所以之前一直是惯性思维的用get,然后一直请求失败, 所以各位入门爬虫的注意了,千万注意了别掉坑里
这里写图片描述

复制了所有headers,做一次post的请求,再看看状态码是不是201(为了避免请求被重定向,建议打印请求内容,或者关闭重定向,后面皆以打印内充处理不再单独提示)(对应study/test1.py文件
这里写图片描述

可以说很OK,然后就开始排除法,首先去掉的是最常用不到的噻。通过几轮排除下来,发现CookieUser-Agent是必要的,既然需要用到cookie,我们就得维持会话,所以要实例化一个session对象了,实现如下:
session = requests.session()

顺便也把Cookie分解了,看看需要哪些内容

for item in headers["Cookie"].split(";"):
    print(item.split("=")[0])

这里写图片描述
这些很重要,可得记住了

问题的转移2

那么如何让session对象持有完整的cookie呢?

我们回到最初的起点,再来分析一下完整的过程
这里写图片描述

打开开发者工具,刷新页面,然后点击二维码登陆(当然,这里建议你清除一下cookies,最好选择【高级】而不是【基本】)

这里写图片描述

我们可以看到第一次请求登陆界面的时候,请求是不带cookies的;而请求之后,按照响应体的要求,会设置对应的_xsrf_zaptgw_17。前面我们知道需要6个,这里才三个肯定是不够的,所以继续找signin后面的文件,看看到底有什么猫腻在里头

于是在udid这个文件中,你会发现响应体要求设置q_c1d_c0;也就是说,在成功请求这个文件之后,Cookie就包含这两个部分了
这里写图片描述

照例复制下完整的headers,找到请求的url,以及请求方式(注意了!这里也是post),最后排除法,找到必要的部分(对应study/test2.py文件
这里写图片描述

仍然是Cookie以及User-Agent

继续撸

还不够,现在我们的cookies还差capsion_ticket部分,所以继续撸

于是找到了captcha?lang=cn文件,它的响应体告诉浏览器,可以设置capsion_ticket
这里写图片描述

对应study/test3.py文件
这里写图片描述

开始代码

有了这波分析,我们就可以开始动手敲代码了

对应studyget-qrcode.py文件

import requests


session = requests.session()

HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 \ (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'
}

# 第一次请求,为了Cookie(_xsrf,_zap,tgw_17)
session.get(url="https://www.zhihu.com/signin", headers=HEADERS)
# 第二次请求,为了Cookie(q_c1,d_c0)
session.post(url="https://www.zhihu.com/udid", headers=HEADERS)
# 第三次请求,为了Cookie(capsion_ticket)
session.get(url="https://www.zhihu.com/api/v3/oauth/captcha?lang=cn", headers=HEADERS)
# 第四次请求,为了token,用于构建二维码图片的请求链接
response = session.post(url="https://www.zhihu.com/api/v3/account/api/login/qrcode", headers=HEADERS)
# print(response.json())

# 第五次请求,为了二维码图片
url4QR = "https://www.zhihu.com/api/v3/account/api/login/qrcode/{0}/image".format(response.json().get("token"))

response = session.get(url=url4QR, headers=HEADERS)
if response.status_code == 200:
    with open("qr.jpg", "wb") as file:
        file.write(response.content)
    print("【保存二维码成功】")
else:
    print("【请求二维码图片错误】")

运行结果如下
这里写图片描述

这时候以为扫描二维码就登陆成功了吗?然而没有
我们扫描一下网页的二维码登陆一下试试,会发现在手机上点击确认登陆以后,请求知乎www.zhihu.com网页的时候,Cookie又多了一个z_c0
这里写图片描述

晕!但是扶住墙,老规矩。可以看到距离知乎首页文件最近的一个scan_info文件,说了要设置z_c0
这里写图片描述

于是在我们扫描二维码之后,应该先请求这个文件,再请求首页文件;查看请求的url,也能发现,这个文件也有一部分是动态的,而且正是之前获取的token
这里写图片描述

为了确保我们成功登陆,可测试编辑页面,因为这个页面只有在登陆成功后可以访问,不然就会被重定向到登陆页面去
这里写图片描述

添加代码如下

# 阻塞程序,给予用户扫描二维码的时间
input("请随便输入后回车")

# 请求scan_info文件,并打印状态码
print(session.get("https://www.zhihu.com/api/v3/account/api/login/qrcode/{0}/scan_info".format(token), headers=HEADERS).status_code)

# 请求编辑页面
response = session.get("https://www.zhihu.com/people/edit", headers=HEADERS, allow_redirects=False)
if response.status_code == 200:
    print("登陆成功")

    print(response.text[:10000])

嗯,写到这儿的时候,宿舍断网了,于是我打开手机热点准备测试代码(之所以要说这个细节,因为我不确实是不是因为使用的手机热点,才造成了后面的错误),结果第一次请求的时候报了如下错
这里写图片描述

其实关闭SSL验证就好,加上参数verify=False,加了这个参数以后会报InsecureRequestWarning警告,我的处理方式是关闭这个警告。加上如下代码即可

from requests.packages import urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning

urllib3.disable_warnings(InsecureRequestWarning)

好了,测试代码吧。效果如下
这里写图片描述

成功


华丽的分割线—————————————————————————

今天起来测试过了,的确是因为使用手机热点才造成SLLError。不过我认为也可以加上之前的处理措施,避免因此出错

完善代码

现在基本功能实现了,但不够完善
– 比如难道用户每次使用都要登陆?我们可以设置本地cookies,这样就可以等cookies失效之后再登陆
– 比如难道每次用户都要手动去打开二维码图片?我们可以利用PIL库来实现图片自动打开

以下是我程序的整体逻辑设计
这里写图片描述

以下是我代码的逻辑设计
这里写图片描述


因为完整代码已经上传GitHub,有详细注释,就不在这细说了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/167277.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 卷积神经网络CNN的反向传播原理

    卷积神经网络CNN的反向传播原理  上一篇博客《详解神经网络的前向传播和反向传播》推导了普通神经网络(多层感知器)的反向传播过程,这篇博客则讨论一下卷积神经网络中反向传播的不同之处。先简单回顾一下普通神经网络中反向传播的四个核心公式:…

  • android中怎么在View构造的attrs中拿到android给的属性以及attrs属性介绍[通俗易懂]

    android中怎么在View构造的attrs中拿到android给的属性以及attrs属性介绍[通俗易懂]attrs获得,而自定义的属性获得值方式如下,当然原生的也是一样,只需要把attrname该成系统的。一、首先要在res/values目录下建立一个attrs.xml(名字可以自己定义)的文件,并在此文件中增加对控件的属性的定义.其xml文件如下所示:在这里,需要补充attrs属性的相关知识,即Attr属性是如何在

    2022年10月17日
  • mysql自定义异常_mysql自定义函数详解

    mysql自定义异常_mysql自定义函数详解[最近研究mysql数据库性能的相关问题,为了对比不同版本之间的差别。笔者找了一台测试服务器升级了该服务器的mysql数据库进行测试,在升级mysql过程中遇到了一些问题并将其1、在MySql中创建自定义函数报错信息如下:ERROR1418(HY000):ThisfunctionhasnoneofDETERMINISTIC,NOSQL,orREADSSQLDATAin…

  • 敏捷软件开发 原则_敏捷方法论

    敏捷软件开发 原则_敏捷方法论《敏捷软件开发》读书分享由于书是由英文书籍翻译,读起来会难免拗口,本次分享是由《敏捷软件开发》结合网上相关资料总结而成。传统的瀑布式开发瀑布模型式是最典型的预见性的方法,严格遵循预先计划的需求、分析、设计、编码、测试的步骤顺序进行。步骤成果作为衡量进度的方法,例如需求规格,设计文档,测试计划和代码审阅等等。瀑布式的主要的问题是它的严格分级导致的自由度降低,项目早期即作出承诺导致…

    2022年10月29日
  • 数据结构:Binary and other trees(数据结构,算法及应用(C++叙事描述语言)文章8章)

    数据结构:Binary and other trees(数据结构,算法及应用(C++叙事描述语言)文章8章)

  • Go语言初见println和fmt.Println区别「建议收藏」

    Go语言初见println和fmt.Println区别「建议收藏」目录println()函数:fmt.println()函数:总结区别:1.包不同:2.输出方式不同:3.方法返回值不同:4.内置print/println函数的调用不能接受数组和结构体参数。5.对于组合类型的参数,内置的print/println函数将输出参数的底层值部的地址,而fmt和log标准库包中的打印函数将输出接口参数的动态值的字面形式。6.如果一个实参有String()string或Error()string方法,那么fmt和log标准库包里的…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号