编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Python 爬虫-如何抓取需要登录的网页

wxchong 2025-07-07 23:46:45 开源技术 4 ℃ 0 评论

本文是 Python 爬虫系列第四篇,前三篇快速入口:
Python 爬虫-开启数据世界的钥匙
Python 爬虫-HTTP 协议和网页基础
Python 爬虫-使用 requests 和 BeautifulSoup 抓取数据


前言

你是否遇到过这样的问题?想用爬虫抓取某网站的数据,却发现内容必须登录才能查看。直接访问只会跳转到登录页,手动复制粘贴又太麻烦……

别担心!今天教你一种方法,用 Python 轻松突破登录限制,抓取目标数据!无论你是数据分析师、开发者还是技术爱好者,这篇干货都能让你事半功倍!

前一篇文章中,我们学习了 requests 库和 BeautifulSoup 库的用法,通过实战获取豆瓣 Top250 电影数据并保存为结构化的 CSV 文件。本文将为大家介绍如何借助 requests 库的 Session 机制,来实现模拟登录 GitHub 网站,并获取个人详情信息。


requests.Session 的核心机制
在之前的文章中,我们已经学习过 requests 库的用法,这里我们主要讲解一下 Session 对象如何模拟浏览器行为:

1. 自动管理 Cookies


2. 连接池与 Keep-Alive


3. 持久化请求头与参数


分析网站登录过程
首先,你需要使用开发者工具(如 Chrome 的开发者工具)来分析登录过程。主要关注以下几点:

用 Chrome 浏览器打开 GitHub 的登录页面,链接为 https://github.com/login,输入 GitHub 的用户名和密码,打开开发者工具,点击 【Network】选项卡,将 Preserve Log 选项勾选上,这表示显示持续日志,如下图所示:

输入用户名和密码,点击登录按钮(Sign in),便会看到开发者工具下方显示了各个请求过程,如下图所示:

点击第一个请求,进入详情页面,在 Headers 标签,可以看到请求的 URL 为 https://github.com/session,请求方式为 POST,以及 Response Headers 和 Request Headers 头信息,如下图所示:

点击 Headers 标签右边的 Payload 标签,可以看到 Form Data,如下图所示:

其中,commit 是固定的字符串 Sign in, authenticity_token 较长,初步判断是一个 Base64 加密的字符串,login 是登录的用户名,password 是登录的密码。
通过分析以上的登录过程,我们发现,现在无法直接构造的内容有 Request Headers 里的 Cookie 和 authenticity_token。下面我们再来探寻一下这两部分的内容如何获取。

在登录之前会先访问一个登录页面( https://github.com/login),此页面是通过 GET 方式访问的。输入用户名和密码后,点击登录按钮,浏览器发送这两部分信息,也就是说 Cookie 和 authenticity_token 一定是在访问登录页面的时候设置的。
我们先退出之前的登录,回到登录页,同时清空 Cookie,重新访问登录页,截获发生的请求,如下图所示:

可以看到 Response Headers 里有 Set-Cookie 字段。这就是设置 Cookie 的过程。
但是,在 Response Headers 里并没有发现 authenticity_token 的信息,所以可能 authenticity_token 还隐藏在其他的地方或者是计算出来的。我们再去网页的源码里搜寻一下,点击 Response 标签,搜索“ authenticity_token”,发现源代码里有一个隐藏式表单元素就是 authenticity_token 的值,如下图所示:

至此,我们已经了解了 GitHub 的登录过程,以及登录所需要的所有信息,接下来我们实现模拟登录。

三 实现模拟登录
第一步,先定义一个 Login 类,初始化一些变量。
代码如下:
import requests
class Login(object): def __init__(self): self.headers = { 'Referer': 'https://gibhub.com/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36' } self.login_url = 'https://github.com/login' self.post_url = 'https://github.com/session' self.logined_url = 'https://github.com/settings/profile' self.session = requests.Session()
以上代码中,requests 库的 Session,它可以帮助我们维持一个会话,并自动处理 Cookie。

第二步,访问登录页面,获取到初始的 Cookie 和 authenticity_token 的值。
代码如下:
# 获取 authenticity_tokendef token(self):    response = self.session.get(self.login_url, headers=self.headers)    selector = etree.HTML(response.text)    token = selector.xpath('//div//input[2]/@value')    return token
以上代码中,使用 Session 对象的 get 方法,访问 GitHub 的登录页面,然后用 XPath 解析出 authenticity_token 信息并返回。

第三步,获取到 Cookie(requests 会自动处理,并在后续请求中携带) 和 authenticity_token 信息后,开始模拟登录。
代码如下:
# 开始模拟登录def login(self, login_name, password):    post_data = {        'commit': 'Sign in',        'authenticity_token': self.token()[0],        'login': login_name,        'password': password    }        response = self.session.post(self.post_url, data=post_data, headers=self.headers)    if response.status_code == 200:        # 登录成功后,获取我的个人信息        response = self.session.get(self.logined_url, headers=self.headers)        if response.status_code == 200:            self.profile(response.text)# 获取个人信息:姓名、邮箱def profile(self, html):    selector = etree.HTML(html)    name = selector.xpath('//input[@id="user_profile_name"]/@value')[0]    email = selector.xpath('//select[@id="user_profile_email"]/option[@value!=""]/text()')[0]    print('Name:', name)    print('Email:', email)
以上代码中,构建一个表单,将用户名、密码、 authenticity_token 等字段信息填入,然后用 Session 对象的 post 方法模拟登录。登录成功后,再用 Session 对象个人详情页,并用 profile 方法来提取用户名、邮箱等信息。
完整代码如下:
import requestsfrom lxml import etree
class Login(object): def __init__(self): self.headers = { 'Referer': 'https://gibhub.com/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36' } self.login_url = 'https://github.com/login' self.post_url = 'https://github.com/session' self.logined_url = 'https://github.com/settings/profile' self.session = requests.Session() # 获取 authenticity_token def token(self): response = self.session.get(self.login_url, headers=self.headers) # 解析 HTML selector = etree.HTML(response.text) # 获取 authenticity_token 的值 token = selector.xpath('//input[@name="authenticity_token"]/@value') return token # 开始模拟登录 def login(self, login_name, password): post_data = { 'commit': 'Sign in', 'authenticity_token': self.token()[0], 'login': login_name, 'password': password } response = self.session.post(self.post_url, data=post_data, headers=self.headers) if response.status_code == 200: # 登录成功后,获取我的个人信息 response = self.session.get(self.logined_url, headers=self.headers) if response.status_code == 200: self.profile(response.text) def profile(self, html): selector = etree.HTML(html) name = selector.xpath('//input[@id="user_profile_name"]/@value')[0] email = selector.xpath('//select[@id="user_profile_email"]/option[@value!=""]/text()')[0] print('Name:', name) print('Email:', email)
if __name__ == "__main__": login = Login() login.login(login_name='idroidr', password='123456')
输出结果:
Name: 梦想Email: idroidr@163.com

小结:我们利用 requests 库的 Session 实现了模拟登录操作,在整个登录的过程中 requests 库对重定向和 Cookie 默认自动处理,不需要我们做干预。

四 进阶:处理验证码

有很多网站在登录时,还需要输入验证码,验证码是网站防止自动化登录的常见手段。 在 Python 爬虫开发中,处理验证码是一个常见而又具有挑战性的问题。验证码通常分为两大类:图形验证码(如图片中的文字或图案)和动态验证码(如滑动验证或点击验证)。下面我将分别介绍如何处理这两种类型的验证码。


4.1 图形验证码

图形验证码通常包含文本、数字或图片,需要识别后输入。处理这类验证码的常见方法有:

(1)手动输入验证码

示例代码如下:

import requestsfrom PIL import Imagefrom io import BytesIO
# 获取验证码图片captcha_url = 'https://example.com/captcha'response = session.get(captcha_url)
# 显示验证码图片image = Image.open(BytesIO(response.content))image.show()
# 手动输入验证码captcha_code = input("请输入验证码:")
# 将验证码发送至登录请求中payload = { 'username': 'your_username', 'password': 'your_password', 'captcha': captcha_code}login_response = session.post(login_url, data=payload)


(2) 使用 Tesseract OCR 库或其他库来识别图片中的文字。

以下是使用 Tesseract OCR 识别简单验证码的示例:
import requestsfrom PIL import Imageimport pytesseractfrom io import BytesIO
session = requests.Session()
# 获取验证码图片captcha_url = 'https://example.com/captcha'response = session.get(captcha_url)image = Image.open(BytesIO(response.content))image.save('captcha.png')
# 使用Tesseract识别验证码captcha_text = pytesseract.image_to_string(image).strip()print("识别的验证码:", captcha_text)
# 准备登录数据login_data = { 'username': 'your_username', 'password': 'your_password', 'captcha': captcha_text}
# 提交登录response = session.post('https://example.com/login', data=login_data)
if '欢迎' in response.text: print("登录成功!")else: print("登录失败!")
注意: OCR 的识别准确率不一定很高,尤其是验证码图像具有干扰线或噪点时。如果准确率不高,可能需要使用图像处理技术预处理验证码图片,提高识别效果。

(3) 调用第三方验证码识别平台
对于复杂的验证码, 如果 OCR 无法准确识别验证码,可以考虑使用第三方 验证码识别平台(如 超级鹰、2Captcha、Anti-Captcha等),这些服务可以帮你解决验证码问题。 此类平台通常是收费的,但其识别准确率较高。
以"超级鹰"为例,代码如下:
import requestsfrom PIL import Imagefrom io import BytesIO
CHAOJIYING_USERNAME = 'your_username'CHAOJIYING_PASSWORD = 'your_password'CHAOJIYING_SOFT_ID = 'your_softid'CHAOJIYING_KIND = '1004' # 验证码类型
session = requests.Session()
# 获取验证码图片captcha_url = 'https://example.com/captcha'response = session.get(captcha_url)image = Image.open(BytesIO(response.content))image.save('captcha.png')
# 使用超级鹰识别验证码def chaojiying_post(pic): url = 'http://upload.chaojiying.net/Upload/Processing.php' files = {'userfile': ('captcha.png', pic, 'image/png')} data = { 'user': CHAOJIYING_USERNAME, 'pass': CHAOJIYING_PASSWORD, 'softid': CHAOJIYING_SOFT_ID, 'codetype': CHAOJIYING_KIND } result = requests.post(url, data=data, files=files).json() return result.get('pic_str')
with open('captcha.png', 'rb') as f: captcha_text = chaojiying_post(f.read())
print("识别的验证码:", captcha_text)
# 准备登录数据login_data = { 'username': 'your_username', 'password': 'your_password', 'captcha': captcha_text}
# 提交登录response = session.post('https://example.com/login', data=login_data)
if '欢迎' in response.text: print("登录成功!")else: print("登录失败!")

4.2 动态验证码(如滑动验证)

动态验证码通常需要模拟用户的交互行为,例如滑动、点击等。这类验证码可以使用 Selenium 库来模拟浏览器行为。

使用 Selenium 之前必须先安装:

pip install selenium

示例代码(以滑动验证码为例):

from selenium import webdriverfrom selenium.webdriver.common.action_chains import ActionChainsimport time
# 初始化WebDriverdriver = webdriver.Chrome(executable_path='path/to/chromedriver')
# 打开目标网页driver.get('https://example.com/captcha-page')
# 等待滑块元素加载完成slider = driver.find_element_by_id('slider') # 根据实际情况修改选择器track = driver.find_element_by_id('track') # 根据实际情况修改选择器gap = driver.find_element_by_id('gap') # 根据实际情况修改选择器
# 计算滑动距离(根据实际情况可能需要调整)slider_width = slider.size['width']track_width = track.size['width'] - slider_widthgap_x = gap.location['x'] + (gap.size['width'] / 2) - (slider_width / 2)distance = gap_x / (track_width / 100) # 转换为百分比距离
# 模拟滑动操作ActionChains(driver).click_and_hold(slider).move_by_offset(distance, 0).release().perform()
# 等待验证完成(根据实际情况可能需要调整)time.sleep(2)
# 关闭浏览器driver.quit()

4.3 补充:短信验证码

短信验证码一般需要将验证码发送至手机。处理此类验证码通常涉及手动输入验证码或配合自动化服务。如果要完成这种任务,通常需要爬虫脚本暂停执行,等待用户手动输入验证码,输入后继续进行登录。


本篇我们学习了如何实现需要登录的网页的抓取,以及验证码如何处理,大家下去可以找一些网站先分析登录过程,再动手写代码验证。
记住,技术是一把双刃剑。在享受爬虫带来的便利的同时,我们应当遵守法律法规和道德准则,合理合法地使用这些技术。


下篇预告:下篇我们将学习如何爬取动态网页,并结合实例代码演示。


感谢你的阅读!如果觉得这篇文章有帮助,欢迎点赞或分享给更多想学 Python 的朋友。我们下次见!


长按识别二维码,关注【人人学Python】

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表