python 爬虫 入门 三、登录以及代理。

目录

一、登录

(一)、登录4399

1.直接使用Cookie

2.使用账号密码进行登录 

        可选观看内容,使用python对密码进行加密(无结果代码,只有过程分析)

二、代理

免费代理

后续:协程,抓取视频


        这节我们来尝试一下登录和代理。

一、登录

        很多网站登录和不登陆显示的内容是不一样的,这主要和Cookie有关。用户先向网站发送账号密码以获取Cookie作为凭证,之后用户发送请求时,携带着Cookie就能让网页知道你是谁了,经过一段时间后,Cookie失效(过有效时段之类的)就需要重新登陆。

(一)、登录4399

        4399童年回忆(应该有账号吧?这个账号注册可能要实名了,不想注册的换个其他的不需要验证码登录的网站,差不多),今天我们就试试进入登录4399新用户-4399用户中心_4399.com这个网址:

但你没Cookie肯定进不去,会跳转到登录界面,咱们先来整点简单的方法

1.直接使用Cookie

        登陆后,我们可以抓到一些请求,其中有个 profile/ 请求,得到它就代表我们成功了。(如果获取到的依然是‘登录4399新用户’代表没登录成功)

        直接看它的标头,其中Cookie这一段就是我们需要的信息,直接全部复制

        之后直接在请求头中加入复制的Cookie就能够登录成功了。 用记事本看一眼打开的结果能看到“我的信息”几个字就代表成功了。

import requestsurl = "https://u.4399.com/profile/"
headers = {# 用户代理,某些网站验证用户代理,微微改一下,如果提示要验证码之类的,使用它"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0","Cookie":''# 这里用你自己的Cookie
}
session = requests.session()
with session.post(url=url, headers=headers,) as resp:resp.encoding = "utf-8"print(resp)with open("4399_profile.html", mode="w",encoding="utf-8") as f:f.write(resp.text)  # 读取到网页的页面源代码"

2.使用账号密码进行登录 

        咱们可以去登录4399新用户-4399用户中心_4399.com这个网站进行登录。我先用i道i做用户名,123456做密码打个样。

        先不要急不可耐的登录抓包,你尝试了就会发现所有抓到的包里面没有跟登录相关的部分。 因为这里跳转了其他的界面,自动清除了之前的抓包结果。咱们先选中装包工具上面的保留日志再开始抓包。(4399采用表单登录,提交表单后跳转到其他界面)

        最后我们可以成功找到 login.do的请求,他的负载里面刚好有username(用户名)和password(密码),但是用户名能看到,密码却不是123456,这是因为有的网站会将密码加密后再发送,或者发送哈希值。(提一句,这种加密啊,哈希啊,很多是不可逆的,所以许多服务器也不知道你的密码具体是什么。)

         接下来,我们就可以根据这条请求来编写我们的代码了。这里使用了session开启了一个会话,第一次请求,会话获取了cookie的值,后面的会话便会自动携带获取的cookie值,以保证连续。可以打断点看看 resp.cookies的变化。

import requestsurl = "https://ptlogin.4399.com/ptlogin/login.do?v=1"
url_2 = "https://u.4399.com/profile/"
headers = {# 用户代理,某些网站验证用户代理,微微改一下,如果提示要验证码之类的,使用它"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
}
data = {'loginFrom': 'uframe','postLoginHandler': 'refreshParent','layoutSelfAdapting': 'false','externalLogin': 'qq','displayMode': 'embed','layout': 'vertical','bizId': '','appId': 'u4399','gameId': '','css': 'https://uc.img4399.com/root/css/ptlogin.css?a3993b7','redirectUrl': '','sessionId': '','mainDivId': 'embed_login_div','includeFcmInfo': 'false','level': '0','regLevel': '4','userNameLabel': '4399用户名','userNameTip': '请输入4399用户名','welcomeTip': '欢迎回到4399','sec': '1','password': 'U2FsdGVkX181bGhjYtZJJrfI3NjzazeojBKK+KVCcn4='.encode('utf-8'),  # 这里用你自己的密码'username': 'i道i',
}
session = requests.session()
with session.post(url=url, data=data, ) as resp:resp.encoding = "utf-8"print(resp)with open("4399.html", mode="w", encoding="utf-8") as f:f.write(resp.text)  # 读取到网页的页面源代码"resp = session.get(url=url_2)print(resp)with open("4399_profile.html", mode="w", encoding="utf-8") as f:f.write(resp.text)  # 读取到网页的页面源代码"

 

        可选观看内容,使用python对密码进行加密(无结果代码,只有过程分析)

        接下来,我们就要确定输入的密码是如何变成这段字符的。我们再尝试登陆一次,发现这段字符有变化。这表明它是跟时间有关的加密。(可能有时间种子随机数,所以一般加密都会让线程睡一小会,保证种子随机性足够)

        第一想法是找到登录按钮(或者回车)的回调函数,向后寻找肯定能够发现包装请求的地方。第二想法是请求的url有login.do,我们就先看看网页源代码里有没有login.do存在,那里肯定和发送请求有关,向后找到请求的负载怎么产生的就知道如何加密了。

        通过页面元素检查,找到登录按钮的位置,发现登录按钮没有什么有意义的回调函数,但有id和class,搜索id的值,可以发现上面有该按钮的事件处理器,这就是我们要找的地方。

        或者直接在全部代码中搜索 login.do,刚好只发现一处有login.do,同样是这个代码。

         找到位置后,我们在39行设置一个断点,(点击39数字,前面出现小红点即可)然后再次登录即可在断点处暂停,

        然后选择右上角步入,进入check_login函数中。找到了一处注释有“密文传输的地方”(好注释),通过变量值的变化推断,红框标注的就是加密部分。

 

        接下来,我们就需要通过 python实现上面的 encryptAES 加密,发送请求了。

        AES是一种对称加密技术,即加密解密密钥相同,而所需密钥长度不及16倍数需要补齐,而且补齐方式比较特殊,比如少4个,需要补四个chr(4)。CryptoJS.AES.encrypt默认aes-256,加密模式CBC,填充方式Pkcs7,也就是说,上面的字符不是真正的密钥,而只是密钥“种子而已”。

        这就比较麻烦了,我们需要用python模拟这一复杂过程,为了避免这一麻烦,我们继续往深处走,看看CryptoJS.AES.encrypt函数内部怎么执行的,能不能从中套出真正的密钥。

 通过debug模式的步入,我们找到了这里,这段代码的b就是我们的密码 123456 ,c是密钥短文 'lzYW5qaXVqa' 最终对里面代码分析结果如下:

# encrypt: function(c, d, e) {return a(d).encrypt(b, c, d, e)       # -》3行# encrypt: function(a, b, c, d) {   # b-》密码 c-》密钥短语 d-》无
#     var e, f;
#     return d = this.cfg.extend(d),
#     e = d.kdf.execute(c, a.keySize, a.ivSize),        # -》13行
#     d.iv = e.iv,  # b是密码,e.key是32位密钥,d是16位偏移量
#     f = x.encrypt.call(this, a, b, e.key, d),-》43行
#     f.mixIn(e),-》75行
#     f
# },# execute: function(a, b, c, d) { a-》密钥短语 b-》8 c-》4 d-》无
#     var e, g;
#     return d || (d = f.random(8)),    # 生成8位随机数
#     e = l.create({
#         keySize: b + c
#     }).compute(a, d),     # -》28行  最后e长度48
#     g = f.create(e.words.slice(b), 4 * c),    # g是e最后16位
#     e.sigBytes = 4 * b,   # 相当于截断到32位
#     u.create({
#         key: e,
#         iv: g,
#         salt: d
#     })
# }# compute: function(a, b) { a-》密钥短语 b->8位随机数
#     for (var j, k, c = this.cfg,  # 密钥长度h-》12,迭代次数i-》1
#     d = c.hasher.create(), f = e.create(), g = f.words, h = c.keySize, i = c.iterations; g.length < h; ) {
#         for (j && d.update(j),若j存在,使用j(不执行下几行代码,短路),否则使用哈希器d包含j
#         j = d.update(a).finalize(b),  使用哈希器包含a,并用b计算新哈希值,结果放在j
#         d.reset(),    重置哈希器
#         k = 1; i > k; k++)
#             j = d.finalize(j),
#             d.reset();
#         f.concat(j)将计算得到的哈希值合并起来,简单拼接
#     }
#     return f.sigBytes = 4 * h,
#     f
# }# encrypt: function(a, b, c, d) {   # cfg,密码,密钥,偏移量
#     var e, f, g;
#     return d = this.cfg.extend(d),
#     e = a.createEncryptor(c, d),  #创建加密器实例
#     f = e.finalize(b),    # 进行加密 -》61行
#     g = e.cfg,
#     u.create({
#         ciphertext: f,    # 16位加密结果
#         key: c,   # 32位密钥
#         iv: g.iv, # 16位偏移量
#         algorithm: a,
#         mode: g.mode,
#         padding: g.padding,
#         blockSize: a.blockSize,
#         formatter: d.format
#     })
# },# finalize: function(a) {
#                 a && this._append(a);
#                 var b = this._doFinalize();   -》67行
#                 return b
#             },# _doFinalize: function() {
#     var b, a = this.cfg.padding;
#     return this._xformMode == this._ENC_XFORM_MODE ? (a.pad(this._data, this.blockSize),  对数据进行填充
#     b = this._process(!0)) : (b = this._process(!0),  # 获得最终加密结果
#     a.unpad(b)),
#     b -》16位
# },# mixIn: function(a) {
#     for (var b in a)
#         a.hasOwnProperty(b) && (this[b] = a[b]);  # 如果b是a的属性,直接复制
#     a.hasOwnProperty("toString") && (this.toString = a.toString)
# },# stringify: function(a) {  # toString内部,
#     var d, b = a.ciphertext, c = a.salt;  # ciphertext加密结果16位,salt 8位随机数
#     return d = c ? f.create([1398893684, 1701076831]).concat(c).concat(b) : b,
#     d.toString(j)
# },

        也就是说,我们仿照上面的过程,产生最后一个函数的结果:d.toString(j)即可,

        如果认为麻烦,可以尝试固定execute的随机数,这样密钥和偏移量就固定了,只需根据43行的函数,对密码使用固定密钥加密(AES,CBC,Pkcs7填充方式)之后参照81行的函数,使用加密结果和偏移量合并出完整参数即可。

        有挺多常用的网站,发送消息都加密,所以自己看看,以后遇到加密的负载知道怎么做。这个login.do没有启动器,所以无法查看堆栈,需要自己找,有启动器的请求可以从启动器的链接里快速定位改变的位置。

        这里挖个坑,等说完Selenium后,会单出一篇使用Selenium登录知乎的文章。没填的话提醒我一下。

总而言之,直接使用Cookie比较简单,不过时间久了会失效,账号密码自动化能够持久一点。

二、代理

        有一些网站,会限制ip的访问频率,比如很多登录页面,一天内不能登录超过五次。超过次数了,你这个ip就无法访问这个网站了,也就是有人说的封ip。这个时候,我们就需要通过ip代理,让拥有其他ip的计算机代替我们发送或者转发请求。

免费代理

        这里推荐一个网站:免费代理IP [ 实时更新 ] - 站大爷

        有一些免费代理供临时使用,到时候选择响应时间短的一些代理。

        类型有普匿 高匿 透明之分,网站可以通过REMOTE_ADDR、HTTP_VIA、HTTP_X_FORWARDED_FOR这三个值知道你的ip地址。透明和普匿能够让网站知道你在使用代理,高匿不会。普匿和高匿都可以让网站无法知道你的真实IP地址,所以很多人都喜欢用高匿。

REMOTE_ADDRHTTP_VIAHTTP_X_FORWARDED_FOR
真实ip
透明代理ip真实ip
普匿代理ip代理ip代理ip
高匿代理ip

        现在来尝试通过代理访问百度,很多免费代理不支持https,所以访问http://baidu.com

        将ip:端口号拼一起就是代理地址,(便宜没好货,多换几个,总有一个能用)。使用proxies参数即可使用ip

import randomimport requestsurl = "http://www.baidu.com/"
proxies_all = ["221.6.139.190:9002"]    # 列表中可以放多个代理def get_proxies(proxies_all):   # 随机获取列表中的一个代理ip = random.choice(proxies_all)return {  # 有的代理不支持https有的不支持http,注意"https": "https://" + ip,"http": "http://" + ip,}with requests.get(url=url, proxies=get_proxies(proxies_all)) as resp:resp.encoding = "utf-8"  # 当页面乱码改这里print(resp)print(resp.text)

 

后续:协程,抓取视频

改天写协程(顺道提一下线程)和如何爬取视频(或许还会有音频)四、协程和视频

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/882411.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业级调度器 LVS

集群和分布式基础知识 系统性能的扩展方式 当一个系统&#xff0c;或一个服务的请求量达到一定的数量级的时候&#xff0c;运行该服务的服务器的性能和资源上限&#xff0c; 很容易成为其性能瓶颈。除了性能问题之外&#xff0c;如果只部署在单台服务器上&#xff0c;在此服务…

gitee建立/取消关联仓库

目录 一、常用指令总结 二、建立关联具体操作 三、取消关联具体操作 一、常用指令总结 首先要选中要关联的文件&#xff0c;右击&#xff0c;选择Git Bash Here。 git remote -v //查看自己的文件有几个关联的仓库git init //初始化文件夹为git可远程建立链接的文件夹…

uniapp uni.uploadFile errMsg: “uploadFile:fail

uniapp 上传后一直显示加载中 1.检查前后端上传有无问题 2.检查失败信息 await uni.uploadFile({url,filePath,name,formData,header,timeout: 30000000, // 自定义上传超时时间fail: async function(err) {$util.hideAll()// 失败// err 返回 {errMsg: "uploadFile:fai…

SpringCloud学习:Openfeign组件实现服务调用和负载均衡

OpenFeign&#xff1a;服务调用与负载均衡&#xff08;服务端接口&#xff09; 是什么&#xff1a;通过OpenFeign可以实现服务调用和负载均衡 OpenFeign是一个声明性web服务客户端&#xff0c; 怎么用&#xff1a;服务提供者提取公共接口用FrignClient标注&#xff0c;服务调…

kernel32.dll下载地址:如何安全地恢复系统文件

关于从网络上寻找kernel32.dll的下载地址&#xff0c;这通常不是一个安全的做法&#xff0c;而且可能涉及到多种风险。kernel32.dll是Windows操作系统的核心组件之一&#xff0c;负责内存管理、进程和线程管理以及其他关键系统功能。因为kernel32.dll是系统的基础文件&#xff…

信息安全工程师(57)网络安全漏洞扫描技术与应用

一、网络安全漏洞扫描技术概述 网络安全漏洞扫描技术是一种可以自动检测计算机系统和网络设备中存在的漏洞和弱点的技术。它通过使用特定的方法和工具&#xff0c;模拟攻击者的攻击方式&#xff0c;从而检测存在的漏洞和弱点。这种技术可以帮助组织及时发现并修补漏洞&#xff…

【数据结构与算法】链表(上)

记录自己所学&#xff0c;无详细讲解 无头单链表实现 1.项目目录文件 2.头文件 Slist.h #include <stdio.h> #include <assert.h> #include <stdlib.h> struct Slist {int data;struct Slist* next; }; typedef struct Slist Slist; //初始化 void SlistI…

C++20中头文件ranges的使用

<ranges>是C20中新增加的头文件&#xff0c;提供了一组与范围(ranges)相关的功能&#xff0c;此头文件是ranges库的一部分。包括&#xff1a; 1.concepts: (1).std::ranges::range:指定类型为range&#xff0c;即它提供开始迭代器和结束标记(it provides a begin iterato…

系统托盘图标+快捷启动(Python)

QkStart 我把这个程序命名为QkStart 代码 # -*- coding: utf-8 -*- # Environment PyCharm # File_name QkStart |User Pfolg # 2024/10/19 22:06 import threading import time import pystray from PIL import Image from pystray import MenuItem, Menu import o…

leetcode.204.计数质数

#中等#枚举 给定整数 n &#xff0c;返回 所有小于非负整数 n 的质数的数量 。 埃氏筛 枚举没有考虑到数与数的关联性&#xff0c;因此难以再继续优化时间复杂度。接下来我们介绍一个常见的算法&#xff0c;该算法由希腊数学家厄拉多塞&#xff08;Eratosthenes&#xff09;提…

文字跑马灯:实现文字自动滚动策略的原理分析

一. 背景 在前端开发中&#xff0c;不少网站和应用都会运用到动态效果来吸引用户的注意&#xff0c;并提升用户体验。文字跑马灯是一种常见的动态效果&#xff0c;通过文字不断滚动来展示内容&#xff0c;吸引用户的注意力。 最近的一个项目就需要实现文字跑马灯效果&#xf…

【消息队列】RabbitMQ实现消费者组机制

目录 1. RabbitMQ 的 发布订阅模式 2. GRPC 服务间的实体同步 2.1 生产者服务 2.2 消费者服务 3. 可靠性 3.1 生产者丢失消息 3.2 消费者丢失消息 3.3 RabbitMQ 中间件丢失消息 1. RabbitMQ 的 发布订阅模式 https://www.rabbitmq.com/tutorials/tutorial-three-go P 生…

基于SpringBoot+Vue+uniapp微信小程序的乡村政务服务系统的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

【软件测试】JUnit

Junit 是一个用于 Java 编程语言的单元测试框架&#xff0c;Selenium是自动化测试框架&#xff0c;专门用于Web测试 本篇博客介绍 Junit5 文章目录 Junit 使用语法注解参数执行顺序断言测试套件 Junit 使用 本篇博客使用 Idea集成开发环境 首先&#xff0c;创建新项目&#…

VUE 仿神州租车-开放平台

项目背景&#xff1a; 神州租车是一家提供汽车租赁服务的公司&#xff0c;其API开放平台为开发者提供了访问神州租车相关服务和数据的接口。用VUE技术来仿照其开发平台。 成果展示&#xff1a; 首页&#xff1a; API文档&#xff1a; 关于我们&#xff1a;

牛只行为及种类识别数据集18g牛只数据,适用于多种图像识别,目标检测,区域入侵检测等算法作为数据集。数据集中包括牛只行走,站立,进食,饮水等不同类型的数据

18g牛只数据&#xff0c;适用于多种图像识别&#xff0c;目标检测&#xff0c;区域入侵检测等算法作为数据集。 数据集中包括牛只行走&#xff0c;站立&#xff0c;进食&#xff0c;饮水等不同类型的数据&#xff0c;可以用于行为检测 数据集中包含多种不同种类的牛只&#xff…

黑盒测试 | 挖掘.NET程序中的反序列化漏洞

通过不安全反序列化漏洞远程执行代码 今天&#xff0c;我将回顾 OWASP 的十大漏洞之一&#xff1a;不安全反序列化&#xff0c;重点是 .NET 应用程序上反序列化漏洞的利用。 &#x1f4dd;$ _序列化_与_反序列化 序列化是将数据对象转换为字节流的过程&#xff0c;字节流可以…

基于SpringBoot+Vue+uniapp的诗词学习系统的详细设计和实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

Maxwell 底层原理 详解

Maxwell 是一个 MySQL 数据库的增量数据捕获&#xff08;CDC, Change Data Capture&#xff09;工具&#xff0c;它通过读取 MySQL 的 binlog&#xff08;Binary Log&#xff09;来捕获数据变化&#xff0c;并将这些变化实时地发送到如 Kafka、Kinesis、RabbitMQ 或其他输出端。…

0x3D service

0x3D service 1. 概念2. Request message 数据格式3. Respone message 数据格式3.1 正响应格式3.2 negative respone codes(NRC)4. 示例4.1 正响应示例:4.2 NRC 示例1. 概念 UDS(统一诊断服务)中的0x3D服务,即Write Memory By Address(按地址写内存)服务,允许客户端向服…