当前位置: 首页 > news >正文

Python 模拟登录网页,或者编写爬虫时模拟登录的详细总结

参考

Python模拟登陆网页的三种方法_python模拟登录-CSDN博客

python-模拟登陆多种方法总结_python模拟登录-CSDN博客

Python模拟登录的几种方法_实现模拟登录的方式有哪些?-CSDN博客

Python爬虫——模拟登录_python 模拟登录-CSDN博客

Python3 爬虫 模拟登录_python模拟登录网站-CSDN博客

模拟登录
模拟登录现在主要分为两种模式,一种是基于Session和Cookie的模拟登录,一种是基于JWT(JSON Web Token)的模拟登录。

简单来说,打开网页后模拟登录,服务器会返回带有Set-Cookie字段的响应头,客户端会生成对应的Cookie,其中保存着与SessionID相关的信息,之后发送给服务器的请求都会携带这个生成的Cookie。这种模式的核心是获取客户端登录后生成的Cookie。对于第二种模式也是如此,现在很多网站采取的开发模式是前后端分离式,所以使用JWT进行登录校验越来越普遍。请求数据时,服务器会校验请求中携带的JWT是否有效,如果有效,就返回正常的数据,所以,这种模式其实就是获取JWT。

基于分析结果,我们可以手动在浏览器里输入用户名和密码,再把Cookie或者JWT复制到代码中请求数据,但是这样做明显会增加人工工作量。所以说实现爬虫,就要程序模拟登录。

1. 模拟登录的基本原理

### 模拟登录的必要性

- **获取身份验证后的数据**:有些网页需要用户登录后才能访问,这些页面的数据是通过身份验证来保护的,爬虫需要模拟登录才能获取这些数据.
- **维持会话状态**:网站通常通过 cookies 维持用户的会话状态,模拟登录后可以保持登录状态,以便进行后续的爬取操作,如访问登录后的页面、获取用户数据等.

### 模拟登录的基本步骤

1. **分析登录页面**:
   - 在浏览器中打开目标网站的登录页面,使用开发者工具(F12)查看登录请求是如何发送的.
   - 在 **Network** 选项卡中查找登录请求的 URL,找到需要提交的表单字段(如用户名、密码等),并确认是否需要发送其他隐藏字段,如 `token` 或 `CSRF`(跨站请求伪造)防护码.

2. **发送登录请求**:
   - 使用 Python 的 `requests` 库模拟用户发送登录表单数据,获取登录后的会话.
   - 创建一个 `Session` 对象来保持会话状态,使用 `session.post()` 方法提交登录表单,表单数据包括用户名、密码和其他必要的隐藏字段.

3. **维持会话状态**:
   - 登录成功后,`Session` 对象会自动保存 cookies,你可以使用同一个会话对象进行后续的请求,以保持登录状态并访问登录后的页面.
   - 如果需要手动处理 cookies,可以在请求时将 cookies 作为参数传递给 `requests` 方法.

### 常用工具与库

- **requests**:用于发送 HTTP 请求,是模拟登录的核心工具.
- **BeautifulSoup**(可选):用于解析网页数据,提取登录页面中的隐藏字段(如 CSRF 令牌)等信息.
- **Selenium**:用于模拟真实浏览器操作,适用于处理复杂的登录流程,如带有验证码或动态加载内容的页面.

### 实战案例:模拟登录 GitHub

1. **获取登录页面和 CSRF 令牌**:
   - 使用 `requests` 获取 GitHub 登录页面,解析页面内容,提取 `authenticity_token`(CSRF 令牌).

2. **提交登录表单**:
   - 构造登录表单数据,包括用户名、密码和 `authenticity_token`,使用 `session.post()` 方法提交表单,登录 GitHub.

3. **访问登录后页面**:
   - 使用已登录的会话对象请求登录后的页面,如 GitHub 个人主页,获取页面内容.

### 处理常见问题

- **处理验证码**:
  - **手动输入**:在脚本运行时暂停,人工输入验证码.
  - **OCR(光学字符识别)**:使用 `Tesseract` 等库自动识别验证码图片(如果验证码不是太复杂).
  - **绕过验证码**:通过分析网站接口,找到无验证码的登录方式(某些 API 不需要验证码).

- **使用代理**:
  - 如果目标网站对频繁的登录请求有限制(如 IP 封禁),可以使用代理池来发送请求,通过 `proxies` 参数指定代理服务器.

- **处理动态加载内容**:
  - **抓取 API**:找到页面背后调用的接口,直接请求 API 获取数据.
  - **Selenium**:使用 Selenium 模拟真实浏览器操作,处理 JavaScript 动态加载的内容.

### 保存用户信息的方法

- **通过 Session 保存登录信息**:
  - 使用 `requests.Session()` 创建会话对象,通过会话对象发送请求,会自动保存和携带 cookies,保持登录状态.
  - 示例代码:
    ```python
    import requests
    s = requests.Session()
    r = s.post(url, headers=headers)
    ```

- **通过 Cookie 保存登录信息**:
  - 使用 `http.cookiejar` 模块初始化 Cookie,通过 `urllib.request.HTTPCookieProcessor` 处理 Cookie,保存登录信息.
  - 示例代码:
    ```python
    import urllib.request, http.cookiejar
    cookie = http.cookiejar.CookieJar()
    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))
    urllib.request.install_opener(opener)
    ```

### 注意事项

- **遵守网站的爬虫政策**:在进行模拟登录和爬取数据时,务必遵守目标网站的爬虫协议和使用条款,不要对网站造成过大的负载或违反法律法规.
- **处理异常和错误**:在代码中添加异常处理和错误检查,确保在登录失败或请求出错时能够及时发现并处理,避免程序崩溃或数据丢失.
- **更新和维护**:网站的登录机制和页面结构可能会发生变化,定期检查和更新爬虫代码,以适应网站的更新和变化,确保爬虫的稳定性和有效性.
 

使用Selenium模拟登录

注意 ChromeDriver和chrome版本要对应上,   

当然第三个小数点后面的版本好不对应也可以

#  Chrome 版本 109.0.5414.120(正式版本) (64 位)
# 指定 ChromeDriver 的路径
service = Service(executable_path='K:/download/chromedriver109.0.5414.25.exe')

下载 ChromeDriverGitCode - 全球开发者的开源社区,开源代码托管平台GitCode是面向全球开发者的开源社区,包括原创博客,开源代码托管,代码协作,项目管理等。与开发者社区互动,提升您的研发效率和质量。icon-default.png?t=O83Ahttps://gitcode.com/open-source-toolkit/da9da?utm_source=highlight_word_gitcode&word=ChromeDriver&isLogin=1ChromeDriver GitCode - 全球开发者的开源社区,开源代码托管平台

更多版本 这个网址 GitCode - 全球开发者的开源社区,开源代码托管平台GitCode是面向全球开发者的开源社区,包括原创博客,开源代码托管,代码协作,项目管理等。与开发者社区互动,提升您的研发效率和质量。icon-default.png?t=O83Ahttps://gitcode.com/org/open-source-toolkit/repos,搜索 chromedriver

对于 登陆方式是比较特殊的 。直接在js中实现的

一、使用Selenium模拟登录
        使用Selenium来进行模拟登录,整个过程非常简单。流程如下。
        (1)初始化ChromeDriver。
        (2)打开知乎登录页面。
        (3)找到用户名的输入框,输入用户名。
        (4)找到密码输入框,输入密码。
        (5)手动单击验证码。
        (6)按下Enter键。
        以上过程,若使用Selenium,一般情况下只需要不到20行代码就可以完成:

selenium 4以下的的老版本

from selenium import webdriver 
from elenium.webdriver.common.keys import Keys 
import time  driver = webdriver.Chrome('./chromedriver') #填写你的chromedriver的路径 
driver.get("https://www.zhihu.com/#signin")  elem = driver.find_element_by_name("account") #寻找账号输入框 
elem.clear() 
elem.send_keys("xxx@gmail.com") #输入账号 
password = driver.find_element_by_name('password') #寻找密码输入框 
password.clear() 
password.send_keys("12345678") #输入密码 
input('请在网页上点击倒立的文字,完成以后回到这里按任意键继续。') 
elem.send_keys(Keys.RETURN) #模拟键盘回车键 
time.sleep(10) #这里可以直接sleep, 也可以使用等待某个条件出现 
print(driver.page_source) 
driver.quit()


        上面的代码就是使用Selenium登录知乎的全部代码,包括空行一共18行。程序首先打开知乎的登录页面,然后使用“find_element_by_name”分别找到输入账号和密码的两个输入框。这两个输入框的name属性值分别为“account”和“password”。 

     新版本

from selenium import webdriver
from selenium.webdriver.chrome.service import Service#  Chrome 版本 109.0.5414.120(正式版本) (64 位)
# 指定 ChromeDriver 的路径
service = Service(executable_path='K:/download/chromedriver109.0.5414.25.exe')# 创建 WebDriver 实例
driver = webdriver.Chrome(service=service)# 打开一个网页
driver.get('https://www.example.com')# 执行一些操作,例如获取页面标题
print(driver.title)# 关闭浏览器
driver.quit()

  在Selenium中可以使用send_keys()方法往输入框中输入字符串。在输入了密码以后,验证码框就会弹出来。知乎使用的验证码为点击倒立的文字,这种验证码不容易自动化处理,因此在这个地方让爬虫先暂停,手动点击倒立文字。爬虫中的input()语句会阻塞程序,直到在控制台按下Enter键,爬虫才会继续运行,触发知乎的登录行为,实现登录。

        无论是使用Selenium来运行异步加载的网站,还是模拟登录,代码少,效果好,看起来简直完美。但是Selenium的缺点就是它的速度太慢了。如果一个网页有很多图片又有很多的异步加载,那么使用Selenium处理完成一个网页要十几秒甚至几十秒。而且如果是在服务器上使用PhantomJS作为WebDriver,还会出现内存泄漏的问题,爬虫轻轻松松就会把服务器内存撑爆。因此,Selenium不适合用于大规模的爬虫开发。虽然Selenium和WebDriver不适合做主力,但是用其来做辅助操作,却有意想不到的效果。

selenium模拟登陆
 
Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。这个工具的主要功能包括:测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。测试系统功能——创建回归测试检验软件功能和用户需求。支持自动录制动作和自动生成.Net、Java、Perl等不同语言的测试脚本。
 
3.1.常见的函数使用
selenium.webdriver支持各种浏览器,包括谷歌、火狐、IE等浏览器,这里主要使用谷歌,不同浏览器操作区别不太。常用的几个函数包如下
from selenium import webdriver #基础模块应用,用来创建浏览器对象,操作浏览器
from selenium.common.exceptions import TimeoutException #异常处理
from selenium.webdriver.support.ui import WebDriverWait # 设置等待浏览器加载
 

 
3.2.html中的定位元素
html中的元素定位上面都准备好了之后,只要熟悉了html的定位就可以很好的进行模拟登陆了。元素查找分为以下几类:
(1)find_element_by_name------通过它的name属性单位到这个元素
(2)find_element_by_id--------通过它的id属性单位到这个元素。
(3)find_element_by_xpath-----如果一个元素它既没有id、name、class属性也不是超链接,这么办呢?或者说它的属性很多重复的。这个时候就可以用xpath解决
(4)find_element_by_link_text--通过link超链接属性定位
(5)find_element_by_partial_link_text-有时候一个超链接它的字符串可能比较长,如果输入全称的话,会显示很长,这时候可以用一模糊匹配方式,截取其中一部分字符串就可以了
(6)find_element_by_tag_name---每个元素都有tag(标签)属性
(7)find_element_by_class_name-通过它的class属性定位到这个元素
(8)find_element_by_css_selector
 

 
 
1.find_element_by_id--定位id属性
以百度搜索 框为例,id属性由浏览器-->F12寻找搜索框的id属性得来。如下:
 

 
 
 
其他类似的属性:

 
 
 
 
link属性按钮比如hao123

 
 
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
# 通过id属性定位百度搜索框,并输入“python”
driver.find_element_by_id("kw").send_keys("python")
# 通过name属性定位百度搜索框,并输入“python”--->可能会产生报错,主要是由于name属性不唯一
dirver.find_element_by_name("wd").send_keys("python")
# 通过class属性定位百度搜索框,并输入“python”
driver.find_element_by_class_name("s_ipt").send_keys("python")
# 从上面定位到的元素属性中,可以看到每个元素都有tag(标签)属性,如搜索框的标签属性,就是最前面的input-->直接运行是会报错的
driver.find_element_by_tag_name("input").send_keys("python")
# 通过link(超链接)属性定位hao123按钮,并点击
driver.find_element_by_link_text("hao123").click()
# 有时候一个超链接它的字符串可能比较长,如果输入全称的话,会显示很长,这时候可以用一模糊匹配方式,截取其中一部分字符串就可以了
#partial_link是一种模糊匹配的方式,对于超长字符中的一段进行匹配
driver.find_element_by_partial_link_text("ao123").click()
# 通过xpath语法进行定位
driver.find_element_by_xpath('//*[@id="kw"]').send_keys("python")
 

 
find_element_by_xpath()------以上定位方式都是通过元素的某个属性来定位的,如果一个元素它既没有id、name、class属性也不是超链接,这么办呢?或者说它的属性很多重复的。这个时候就可以用xpath解决
使用方法:chrome应用商店下载xpath helper插件,该插件在安装后,打开某个网页 拷贝目标页面元素的XPATH,如下图所示。copy的结果为:
//*[@id="kw"]/html/body/div[1]/div[2]/div[5]/div[1]/div/form/span[1]/input


selenium模拟登陆的代码如下:
find_element_by_css_selector中的元素我  们可以在chrome中右边copy selector选择得出,具体如下图所示:
 
 
 
#方式三:selenium模拟登录
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('http://jsnu.fuyunweb.com/login2.html')
sleep(2)
driver.find_element_by_name("user").send_keys("用户名")
driver.find_element_by_name("passwordLogin").send_keys("密码")
sleep(2)
# find_element_by_css_selector中的元素在chrome中可以通过右键copy selector 进行选择
driver.find_element_by_css_selector("body > div.login2.log > div > div.loginbtn > button").click()#登录点击模拟
 

自动输入用户名和密码进行登录
 
 
 
 

四.socket模拟登陆
什么是Socket?
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
# 方式四:socket编程
import socket
from urllib.parse import urlparse
 
url = urlparse('http://XXX/login2.html')#登录界面
host = url.netloc        #获取url中的host
path = url.path #获取url后面的路径
#data为抓到的响应包
data = '''
POST /manage/admin/pt_login.aspx HTTP/1.1
Host: jsnu.fuyunweb.com
Content-Length: 40
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://XXX
Referer: http:/XXX/login2.html
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: ASP.NET_SessionId=2fwb5pydk0htjy45nanudauf; userinfo=userid=ZTxan6d5Aja4AMMDe5yu&uid=pCRUyMSkr5XlOxie3ganHRdIJ7fQDe5yuDe5yu&pass=837A6C7DDD08D1629D0F1394190687EE&schoolid=7YTECdKVMaQDe5yu&cookid=9f729e29-a4d2-4b39-8bbc-068e2c7ab644
Connection: close
action=login&uid=用户名&pass=密码
'''
# 建立socke连接,如果是https请求需要使用ssl,例如:ssl.wrap_socket(socket.socket())
# ssl是专门用来处理https的模块,我们使用该模块的wrap_socket函数生成一个SSLSocket对象,使用前需要使用import进行导入
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host,80))        #建立连接
sock.send(data.format(path, host).encode("utf-8"))        #发送数据
#recv_data = sock.recv(8192) #可以直接获取响应包的数据,以下循环纯属是用来对响应包格式进行一个规范的没有什么意义
recv_data = b""
while True:
    d = sock.recv(1024)
    if d:
        recv_data += d
    else:
        break
recv_data = recv_data.decode("utf-8")
print(recv_data)
sock.close()
 

 
输出结果如下:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 91
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.0
X-AspNet-Version: 2.0.50727
Set-Cookie: userinfo=; expires=Sat, 12-Dec-2020 07:55:03 GMT; path=/
Set-Cookie: userinfo=userid=ZTxan6d5Aja4AMMDe5yu&uid=pCRUyMSkr5XlOxie3ganHRdIJ7fQDe5yuDe5yu&pass=837A6C7DDD08D1629D0F1394190687EE&schoolid=7YTECdKVMaQDe5yu&cookid=be8bf64b-430a-400c-b735-bd11ce65c6cc; domain=jsnu.fuyunweb.com; expires=Sat, 02-Jan-2021 07:55:03 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Sun, 13 Dec 2020 07:55:02 GMT
Connection: close
 
success<[        DISCUZ_CODE_2        ]gt;/manage/admin/admin_pt_main.aspx<[        DISCUZ_CODE_2        ]gt;/manage/admin/admin_pt_order_mydbgd.aspx
 

socket拓展:
 
一些来自于链接:https://www.cnblogs.com/limengda/p/10785719.html
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
socket又称为套接字,可以将其分为多种:
1.基于文件类型的套接字:AF_UNIX unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
2.基于网络类型的套接字:AF_INET/6 还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET
 
 
一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。
客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
# 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
# 例如tcpSock = socket(AF_INET, SOCK_STREAM)

'''
# 涉及到的参数
AF_UNIX : 文件类型的套接字
AF_INET/6 :网络类型的套接字
SOCK_STREAM:提供面向连接的稳定数据传输,即TCP协议
SOCK_DGRAM :是基于UDP的,专门用于局域网
protocal : 协议默认为0填写的就是tcp协议
'''

# 服务端套接字函数
s.bind()    绑定(主机,端口号)到套接字
s.listen()  开始TCP监听,半连接池可以指定等待数量
s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来

# 客户端套接字函数


s.connect()     主动初始化TCP服务器连接
s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

# 公共用途的套接字函数
s.recv()            接收TCP数据
s.send()            发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall()         发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom()        接收UDP数据
s.sendto()          发送UDP数据
s.getpeername()     连接到当前套接字的远端的地址
s.getsockname()     当前套接字的地址
s.getsockopt()      返回指定套接字的参数
s.setsockopt()      设置指定套接字的参数
s.close()           关闭套接字

# 面向锁的套接字方法
s.setblocking()     设置套接字的阻塞与非阻塞模式
s.settimeout()      设置阻塞套接字操作的超时时间
s.gettimeout()      得到阻塞套接字操作的超时时间

# 面向文件的套接字的函数
s.fileno()          套接字的文件描述符
s.makefile()        创建一个与该套接字相关的文件
 

PS:一些用户名和密码比较涉及隐私,就码掉了,调用函数这自行添加啊


http://www.mrgr.cn/news/82924.html

相关文章:

  • 121 买入股票的最佳时机
  • matlab中高精度计算函数vpa与非厄米矩阵本征值的求解
  • 【数据结构-堆】力扣2530. 执行 K 次操作后的最大分数
  • 注册中心如何选型?Eureka、Zookeeper、Nacos怎么选
  • 【计算机视觉】单目深度估计模型-Depth Anything-V2
  • 5.2 数据库:UPDATE子句
  • 【Rust自学】10.7. 生命周期 Pt.3:输入输出生命周期与3规则
  • 30天开发操作系统 第 12 天 -- 定时器
  • Java虚拟机面试题:JVM调优
  • [创业之路-241]:《从偶然到必然-华为研发投资与管理实践》-2- IPD流程中的业务线、技术线、职能支撑线
  • Web渗透测试之XSS跨站脚本 原理 出现的原因 出现的位置 测试的方法 危害 防御手段 面试题 一篇文章给你说的明明白白
  • Effective C++读书笔记——item11(自赋值)
  • 来说数据库
  • C++ Qt练习项目 QChar功能测试
  • 尚硅谷· vue3+ts 知识点学习整理 |14h的课程(持续更ing)
  • aardio —— 虚表 —— 模拟属性框
  • 安卓OCR使用(Google ML Kit)
  • 【华为OD机试E卷C卷D卷】跳马【C++/Java/Python】
  • Python应用指南:高德交通态势数据(一)
  • java 核心知识点——基础知识
  • 群论学习笔记
  • 关于大一上的总结
  • 【Linux】sed编辑器
  • Functions
  • 高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图
  • SQL编程语言