Python抓取静态网页数据的完整指南

作者:

文章目录
  • 静态网页是HTML格式的网页,这种网页在浏览器中呈现的内容都会体现在源代码中。如果我们要抓取静态网页的数据,只需要获得网页的源代码即可。 网络爬虫抓取静态网页数据的过程是获得网页原代码的过程,这个过程也就是模拟用户通过浏览器访问网页的过程,包括向Web服务器发送HTTP请求、服务器对HTTP请求作出相应并返回网页源代码 ulrlib、urllib3、requests是Python提供的可以抓取静态网页的库
  • GET和POST是HTTP协议中最常用的两种请求方法,它们在设计理念和使用场景上有本质区别。 GET和POST请求核心区别总结 特性 GET POST 语义 获取数据 提交数据 参数位置 URL查询字符串 请求体 参数可见性 明文显示在URL中 隐藏在请求体中 数据长度 有限制(浏览器不同) 理论上无限制 安全性 较低(参数在URL中) 相对较高 缓存 可被缓存 通常不被缓存 幂等性 幂等(多次请求结果相同) 非幂等 书签 可收藏为书签 不可收藏
  • 当用户首次登入一个网站时,网站往往需要用户输入用户名称和用户密码,并给出自动登入选项供用户勾选。用户如果勾选了自动登入选项,那么在下一次访问该网站时,不用输入用户名和密码就能自动登入。这是因为第一次登入时服务器发送了包含登入凭证的Cookie到用户硬盘上,第二次登入时浏览器发送了Cookie,服务器验证了Cookie后就识别了用户的身份,用户便无需用户名和密码就可以登入该网站 Cookie(有时候也称Cookies)是指某些网站为了辨别用户身份、进行会话跟踪而暂时存储在客户端的一段文本数据(通常经过加密) 我们可以打开浏览器来看一下我们的浏览器保存了哪些Cookie: 打开浏览器的设置  →   点击“隐私、搜索和服务”   →    在弹出来的界面中点击Cookie 这相当于说把用户名和密码发在Cookie里是不够安全的,电脑被黑,存储在浏览器中的Cookie信息就会被盗取 浏览器访问服务器就是会话的开始,但是会话的结束就相对来说模糊一点,当你不小心关闭了这个网页,算不算会话的结束?因此不同的网站会给用户的会话设置了时间和一个唯一的ID,这个ID也就是Session ID,时间是会话的时间。这些数据由服务器设置,一般都保存在数据库里面
  • 我们通常不会将用户的真实密码和账号保存在Cookie或Session中。这样做会带来严重的安全风险。下面分别说明: Cookie:如果将用户的账号和密码直接保存在Cookie中,那么这些敏感信息就会以明文形式存储在用户的浏览器中,并且每次请求都会自动发送给服务器。这极易导致信息泄露,例如: 如果Cookie被窃取(通过XSS攻击),攻击者就能拿到用户的账号和密码。 即使加密存储,也不安全,因为密钥同样需要存储在客户端,且加密可能被破解。 Session:在Session中,我们通常也不会保存用户的真实密码。Session中存储的是用户登录后的状态信息,例如用户ID、用户名、登录状态等。用户的密码在登录验证通过后,就不应该再被保留在Session中。 那么,正确的做法是怎样的呢? 正确的认证流程: 用户登录:用户提交账号和密码。 服务器验证:服务器在数据库中查找该账号,并验证密码(通常数据库中的密码是经过哈希加密的,不会存储明文密码)。 创建Session:验证通过后,服务器创建一个Session,在Session中存储一些不敏感的用户信息(如用户ID、用户名等)和登录状态。 设置Cookie:服务器将Session ID通过Cookie返回给浏览器,浏览器后续请求会携带这个Session ID。 后续请求:服务器通过Session ID找到对应的Session,从而知道是哪个用户。 另外,使用Token(如JWT)的方式: 用户登录:用户提交账号和密码。 服务器验证:验证通过后,服务器生成一个Token(如JWT),Token中包含一些用户信息(如用户ID)和过期时间,并用服务器密钥签名。 返回Token:服务器将Token返回给客户端,客户端保存(通常放在localStorage或Cookie中)。 后续请求:客户端在请求头中携带Token,服务器验证Token的签名和有效性,从而识别用户。 在Token方式中,密码同样不会存储在Token中,Token中只包含必要的信息(如用户ID)和签名。 总结: 绝对不要将用户的真实密码存储在Cookie或Session中。 在Session中只存储必要的用户标识和状态,而不是敏感信息。 在认证过程中,密码应该通过安全通道(如HTTPS)传输,并且在服务器端与存储的哈希值进行验证,验证后立即“忘记”密码(不保存)。 所以,用户的真实密码既不应该保存在Cookie里,也不应该保存在Session里。 绝对不要将用户的真实密码和账号保存在Cookie或Session中! 这是Web安全的基本原则。
  • 在 requests 进行登录时,账户和密码是通过 POST 请求的 data 参数发送的。 data参数接受一个字典 我们之前讨论过,Cookie和Session不是用来存储密码的,而是用来维护会话状态的。在requests库中,Cookie和Session的作用如下: Session对象:在requests库中,Session对象允许你跨请求保持某些参数,比如Cookie、头部信息等。它最常用的功能就是保持登录状态(通过自动处理Cookie)。 Cookie:在HTTP请求中,Cookie是服务器发送到浏览器并保存在本地的一小段数据,浏览器会在后续的请求中自动携带这些数据。在requests中,你可以手动为请求添加Cookie,但更常见的做法是使用Session对象自动管理。 在爬虫中,我们通常使用Session来模拟登录后的会话,步骤如下: a. 创建一个Session对象。 b. 发送登录请求(POST请求,包含用户名和密码),这个请求会返回一个包含Cookie的响应,Session会自动保存这个Cookie。 c. 使用同一个Session对象发送后续请求,Session会自动在请求中携带之前保存的Cookie,这样服务器就认为你已经登录了。 注意:我们不会将密码存储在Cookie或Session中,而是通过登录请求将密码(通常是加密的)发送给服务器,服务器验证后返回一个会话标识(例如Session ID),这个标识会保存在Cookie中,后续请求就靠这个标识来维持登录状态。
  • 目录
    • 一.什么是静态网页
      • 1.静态网页的含义
      • 2.静态网页的特点
      • 3.静态网页的技术构成
      • 4.静态网页 vs. 动态 网页
      • 5.现代静态网站的演进
    • 二.抓取静态网页的技术
      • 1.urllib
      • 2.urllib3
      • 3.requests
    • 三.发送基本请求
      • 1.发送GET请求
        • 不携带URL参数的GET请求
        • 发送携带参数的URL的GET请求
      • 2.发送POST请求
        • url组成部分分解
        • 关于URL编码
      • 判断正确URL的方法
        • 时间顺序法
        • URL特征法
        • 大小和类型判断
        • Headers信息验证
      • 3.处理复杂的请求
      • 四.对Cookie、Session、Token的一些理解
        • Cookie
          • Session
            • Token
              • 三者的联系
                • 核心区别(重点)
                • 五.用户的真实账号和密码被存在了哪里
                  • 六.requests模块中cookies和session的作用
                    • requests.Session() 的作用
                      • Cookies 参数的作用
                        • 完整的登录流程示例

                        静态网页是指网页的内容在服务器上被创建和存储时就已经完全确定好了。当用户通过浏览器请求这个网页时,服务器会原封不动地将这个预先制作好的文件(通常是.html、.css、.js文件),发送给用户的浏览器。网页的内容不会因用户的不同,时间的变化或用户的交互而改变。

                        可以想象成一本书的某一页,或者一张打印出来的宣传单页:它的内容在印刷完成的那一刻就已经固定了。

                        1.内容固定不变

                        网页上的所有文字、图片、布局和链接都是开发人员在编写代码时就已经确定好的,除非开发人员手动修改源代码并且重新上传到服务器,否则任何用户在任何时间、任何地点看到的网页内容都是一样的

                        2.服务器处理简单

                        服务器不需要处理任何额外的程序或查询数据库,它的任务仅仅是找到用户查询的文件,然后把它发送出去。这就像从一个文件柜里取出一个已经归档的文件。

                        3.加载速度快

                        因为服务器不需要进行任何动态数据处理,所以相应速度非常快。能极大提升用户体验和搜索引擎排名

                        4.开发成本低,易于部署

                        静态网页通常只由HTML、CSS、JavaScript这三种前端技术组成,开发简单,对服务器环境要求低,部署也非常方便

                        5.安全性高

                        由于没有与数据库的交互和执行服务器端脚本(如PHP、Python),它受黑客攻击的入口点更少,因此比动态 网页更安全

                        • HTML:负责网页的内容和结构,比如标题、段落、图片、链接等
                        • CSS:负责网页的样式和布局,比如颜色、字体、间距、相应式设计等
                        • JavaScript:负责网页的交互行为,比如下拉表单、图片轮播、表单验证等

                        重要提示:一个网页即使包含了复杂的JavaScript动画和交互,只要它的核心内容(如文章、产品、公司介绍)是预先写死在HTML里面的,它仍然属于静态网页

                        为了更好地理解,我们将其与动态 网页进行对比:

                        特性 静态网页 动态 网页
                        内容来源 预先编写好的HTML文件 服务器端脚本(PHP, Python, Node.js等)实时从数据库或其他数据源获取数据并生成HTML
                        内容变化 手动更新源代码 根据用户、时间、数据库状态等自动变化
                        服务器负载 低(主要是文件传输) 高(需要执行脚本和数据库查询)
                        开发复杂度
                        典型例子 公司官网、个人博客、产品介绍页、活动宣传页 社交媒体(如微博、微信)、电商网站(如淘宝)、在线邮箱(如Gmail)

                        传统的静态网页概念在今天有了一些新的发展,特别是 Jamstack 架构的流行。

                        Jamstack 的核心思想是:

                        • 预渲染:在部署之前,使用静态站点生成器(如 Gatsby, Next.js, Hugo, Jekyll)将网站的所有页面提前生成为静态文件。
                        • 解耦架构:通过 APIs 和 微服务 来处理动态功能。

                        例如:一个新闻网站。

                        传统静态:每篇新文章都需要手动写一个HTML文件。

                        现代Jamstack

                        • 编辑在内容管理系统(如WordPress + Headless插件,或Contentful)中写好文章。
                        • 当文章发布时,会触发一个构建流程。
                        • 静态站点生成器(如Gatsby)会从CMS的API获取这篇新文章的内容,自动生成一个新的静态HTML页面,并更新网站列表页。
                        • 最后将整个更新后的静态网站部署到服务器。

                        这样,它既保留了静态网站快速、安全的优点,又具备了易于内容更新的动态能力。

                        静态网页是HTML格式的网页,这种网页在浏览器中呈现的内容都会体现在源代码中。如果我们要抓取静态网页的数据,只需要获得网页的源代码即可。

                        网络爬虫抓取静态网页数据的过程是获得网页原代码的过程,这个过程也就是模拟用户通过浏览器访问网页的过程,包括向Web服务器发送HTTP请求、服务器对HTTP请求作出相应并返回网页源代码

                        ulrlib、urllib3、requests是Python提供的可以抓取静态网页的库

                        urllib是Python最早的内置的HTTP客户端库,涵盖了基础的网络请求功能

                        它主要包含了4个用于处理URL的模块:urllib.error模块、urllib.error模块、urllib.parse模块、urllib.robotparser模块

                        其中urllib.requests模块封装了构造和发送网络请求的功能

                        urllib.error模块封装了发送请求时出现的网络异常

                        urllib.parse模块封装了解析网页数据的功能

                        urllib.robotparser模块封装解析robots.txt文件的功能

                        它主要服务于升级的HTTP1.1标准,增加了一些urllib库中缺少了特性,如线程安全、连接池、客户端TLS/SSL验证、压缩编码

                        基于urllib3编写的库,该库自称HTTP for Humans,专门为人类设计的HTTP库

                        相比urllib,requests库会在请求网页数据后重复使用Socket套接字,并没有与服务器断开,而urllib库会在请求网页数据后断开与服务器的链接

                        GET和POST是HTTP协议中最常用的两种请求方法,它们在设计理念和使用场景上有本质区别。

                        GET和POST请求核心区别总结

                        特性 GET POST
                        语义 获取数据 提交数据
                        参数位置 URL查询字符串 请求体
                        参数可见性 明文显示在URL中 隐藏在请求体中
                        数据长度 有限制(浏览器不同) 理论上无限制
                        安全性 较低(参数在URL中) 相对较高
                        缓存 可被缓存 通常不被缓存
                        幂等性 幂等(多次请求结果相同) 非幂等
                        书签 可收藏为书签 不可收藏

                        import requests
                        base_url = 'https://www.baidu.com/'
                        response = requests.get(base_url)
                        print("响应码为:",response.status_code) #响应码为: 200

                        上面的代码中,GET请求中的URL没有携带参数,

                        url参数是必需的

                        params参数(param英文意思就是参数,paramter:界限,范围,参数)

                        params参数就是用于查询字符串的,它可以是一个字典,一个包含键值对的列表,或者一个字节字符串

                        import requests
                        base_url = 'https://www.baidu.com/'
                        param = 'wd=python'
                        full_url = base_url + '?' + param
                        # print(full_url) #https://www.baidu.com/?wd=python
                        response = requests.get(full_url)
                        print("响应码为:",response.status_code) # 响应码为: 200
                        import requests
                        base_url = 'https://www.baidu.com/'
                        wd_params = {'wd':'python'}
                        response = requests.get(base_url, params=wd_params)
                        print(response.status_code) #200

                        params的参数值为字典这种使用最常用

                        如果网页上form表单的method属性的值为post,那么当用户提交表单时,浏览器会用POST方法提交表单,并将各个表单元素及数据作为HTTP请求信息中的请求数据发送给服务器

                        POST请求方法用于发送HTTP POST请求,它比GET请求更安全,因为参数不会出现在URL中,而是放在请求体中,POST请求通常用于提交表单、上传文件、调用API等

                        基本使用方法:

                        response = requests.post(url, data=None, json=None, **kwargs)

                        主要参数:

                        • url: 请求的目标URL(必需)
                        • data: 字典、元组列表、字节或文件对象,用于作为表单数据发送
                        • json: 字典,用于作为JSON数据发送,会自动设置Content-Type为application/json
                        • **kwargs: 其他可选参数,如headers、cookies、auth、timeout等,与requests.get()相同
                        import requests
                        base_url = "https://www.gushiwen.cn/"
                        data = {
                            'username':'user_name',
                            'password':12345678,
                        }
                        response = requests.post(url=base_url, data=data)
                        print(response.status_code) # 200

                        爬取并保存古诗文网中苏轼的HTML数据:

                        import requests
                        base_url = 'https://www.gushiwen.cn/'
                        data = {
                            'wd':'苏轼'
                        }
                        # response = requests.post(base_url, data=data)
                        response = requests.get(base_url, params=data)
                        print(response.status_code)
                        with open("古诗文-苏轼.html", 'wb') as file:
                            file.write(response.content)
                        print(response.url)

                        这段代码可以正常地运行,正常地保存了.html文件,正常输出了url的最终形式:https://www.gushiwen.cn/?wd=%E8%8B%8F%E8%BD%BC

                        但是当我们用这个输出的url去浏览器中访问时,发现还是首页的页面,并不是查找苏轼后的有关苏轼古诗文的页面

                        原因在于:使用的是主页 URL https://www.gushiwen.cn/,而不是搜索页面的 URL

                        古诗文网的搜索功能通常有专门的搜索页面

                        我们需要查看古诗文网中搜索表单的实际参数名

                        注:搜索功能一般是GET方法,不是POST方法哦

                        我们通常可以通过以下方式找到正确的搜索URL和请求方式:

                        • 浏览器的开发者工具(按F12打开),特别是网络(Network)选项卡。
                        • 观察网页的搜索表单(如果有的话)的HTML结构

                        步骤1:打开古诗文网,找到搜索框。

                        步骤2:打开浏览器的开发者工具,切换到网络(Network)选项卡,并清空当前记录。

                        步骤3:在搜索框中输入“苏轼”,然后执行搜索。

                        步骤4:在开发者工具的网络选项卡中,会看到浏览器发送的请求,找到第一个搜索结果的请求,点击查看其详细信息。

                        主文档请求 – 这是最重要的

                        • 类型通常是 "document" 或 "xhr"(或者fatch类型的文档,这些一般都是接口数据)
                        • 名称通常包含 "search"、"so" 等关键词
                        • 这是实际返回搜索结果HTML页面的请求

                        如何识别

                        • 清空Network面板:在点击搜索按钮前,先点击Network面板上的 🚫 清除按钮
                        • 执行搜索:在网站上输入"苏轼"并点击搜索
                        • 观察新出现的请求:你会看到一堆新的请求出现

                        重点关注

                        • Name列排序,找包含 "search" 的请求
                        • Type列找 "document" 类型的请求
                        • Size列找较大的请求(通常主页面比较大)

                        我们在开发者工具的网络选项卡中发现了第一个文档,后缀名为.document

                        该文档中包含的url信息为:https://www.gushiwen.cn/search.aspx?value=%E8%8B%8F%E8%BD%BC

                        • https:// – 协议类型(安全超文本传输协议)
                        • www.gushiwen.cn – 域名(古诗文网)
                        • /search.aspx – 服务器上的搜索处理页面
                        • ?value= – 查询参数开始,参数名为value
                        • %E8%8B%8F%E8%BD%BC – "苏轼"的URL编码形式

                        URL编码(也叫百分号编码)是将特殊字符转换为%后跟两位十六进制数的形式。

                        • %E8%8B%8F = "苏"
                        • %E8%BD%BC = "轼"

                        可以在python中验证:

                        from urllib.parse import quote, unquote
                        
                        # 编码
                        encoded = quote('苏轼')
                        print(f"编码后: {encoded}")  # 输出: %E8%8B%8F%E8%BD%BC
                        
                        # 解码
                        decoded = unquote('%E8%8B%8F%E8%BD%BC')
                        print(f"解码后: {decoded}")  # 输出: 苏轼

                        • 在点击搜索按钮之前,先清空Network面板
                        • 点击搜索后,第一个出现的文档请求很可能就是搜索请求
                        • 因为搜索动作会触发页面跳转,这个跳转的请求应该是最先发起的

                        正确的搜索URL通常有这些特征:

                        • 包含 searchsoqueryfind 等关键词
                        • 参数中包含你的搜索词(编码后的)
                        • 通常是 .aspx.php/search/ 等动态页面

                        • 搜索结果的HTML页面通常比较大(几十KB到几百KB)
                        • 静态资源(CSS、JS、图片)通常较小或有特定类型

                        在开发者工具中,点击候选请求,查看:

                        • Response Headers 中的 Content-Type 应该是 text/html
                        • Request Headers 中可以看到完整的请求信息

                        正确的实现代码:

                        import requests
                        base_url = 'https://www.gushiwen.cn/search.aspx?'
                        params = {
                            'value':'苏轼',
                        }
                        response = requests.get(url=base_url, params=params)
                        response.raise_for_status()
                        print(response.url)
                        with open("古诗文-苏轼.html", 'wb') as f:
                            f.write(response.content)

                        输出的url:https://www.gushiwen.cn/search.aspx?value=%E8%8B%8F%E8%BD%BC

                        比如定制请求头,网络爬虫在发送请求抓取部分网页内容(如知乎首页)时,可能会遇到服务器返回403错误,即服务器有能力处理请求,但是拒绝处理该客户端发送的请求。之所以出现服务器拒绝访问的问题,是因为这些网页为防止网络爬虫恶意抓取网页信息加入防爬虫措施。

                        它们通过检查该请求头,判定发送的请求不是客户端,而可能是一个网络爬虫

                        所以为了解决这个问题,需要为网络爬虫的请求定制一个请求头,使得该请求伪装成一个由浏览器发送的请求

                        在请求头中添加User-Agent(用户代理)

                        在请求中添加Cookie值{
                                设置Cookie有两种方式{
                                1.将含有Cookie的信息的请求头传入请求函数的headers参数中(字典形式)
                                2.将Cookie信息的请求头传输cookies参数中,cookies参数接受一个RequestsCookieJar类的对象
                                }
                        }

                        使用session保持会话

                        SSL证书验证

                        设置代理服务器

                        当用户首次登入一个网站时,网站往往需要用户输入用户名称和用户密码,并给出自动登入选项供用户勾选。用户如果勾选了自动登入选项,那么在下一次访问该网站时,不用输入用户名和密码就能自动登入。这是因为第一次登入时服务器发送了包含登入凭证的Cookie到用户硬盘上,第二次登入时浏览器发送了Cookie,服务器验证了Cookie后就识别了用户的身份,用户便无需用户名和密码就可以登入该网站

                        Cookie(有时候也称Cookies)是指某些网站为了辨别用户身份、进行会话跟踪而暂时存储在客户端的一段文本数据(通常经过加密)

                        我们可以打开浏览器来看一下我们的浏览器保存了哪些Cookie:

                        打开浏览器的设置  →   点击“隐私、搜索和服务”   →    在弹出来的界面中点击Cookie

                        这相当于说把用户名和密码发在Cookie里是不够安全的,电脑被黑,存储在浏览器中的Cookie信息就会被盗取

                        浏览器访问服务器就是会话的开始,但是会话的结束就相对来说模糊一点,当你不小心关闭了这个网页,算不算会话的结束?
                        因此不同的网站会给用户的会话设置了时间和一个唯一的ID,这个ID也就是Session ID,时间是会话的时间。这些数据由服务器设置,一般都保存在数据库里面

                        是什么:Cookie是一小段数据(最大通常为4KB),由服务器通过HTTP响应头的 Set-Cookie 字段发送给客户端(通常是浏览器)。浏览器会将其保存起来,并在后续对同一域名的请求中,自动通过HTTP请求头的 Cookie 字段将其携带回服务器。

                        核心特点

                        • 存储在客户端:数据保存在浏览器端。
                        • 自动携带:浏览器会自动在符合条件的请求中附带上Cookie。
                        • 有域和路径限制:只能被创建它的域名或路径访问,遵循同源策略。
                        • 可设置过期时间:可以是会话级(浏览器关闭即失效),也可以是持久性的(直到设定的过期时间)。

                        主要用途

                        • 会话状态管理(如用户登录状态、购物车)
                        • 个性化设置(如主题、语言偏好)
                        • 浏览器行为跟踪(如用户行为分析)

                        是什么:Session代表的是一次用户与服务器的交互会话。它是一种在服务器端保存用户状态和信息的机制。每个Session都有一个唯一的标识符,称为 Session ID

                        核心特点

                        • 存储在服务器端:用户的真实数据(如用户ID、用户名、权限等)保存在服务器的内存、文件或数据库中。
                        • 依赖Cookie(或URL重写):服务器为了区分不同的客户端,会将 Session ID 通过Cookie(Set-Cookie: session_id=abc123...)发送给客户端。客户端后续请求时携带这个 Session ID,服务器根据这个ID找到对应的Session数据。
                        • 更安全:因为敏感数据都存在服务器,客户端只有一个无意义的ID。

                        工作流程简述

                        • 用户登录,服务器验证通过后,创建Session,并生成唯一 Session ID
                        • 服务器通过响应头 Set-Cookie 将 Session ID 发给浏览器。
                        • 浏览器保存这个Cookie,之后每次请求都会带上这个 Session ID
                        • 服务器收到请求,解析出 Session ID,并从存储中查找对应的Session数据,从而得知用户身份。

                        是什么:Token是一种身份凭证,是服务器生成的一串字符串,其中包含了用户信息和签名。最常见的Token是 JWT(JSON Web Token)

                        核心特点

                        • 自包含:Token本身(以JWT为例)就包含了所有需要的信息,如用户ID、过期时间等。服务器无需在服务端存储会话状态。
                        • 存储在客户端:由客户端保存,通常可以存储在Local Storage、Session Storage或Cookie中。
                        • 需要手动携带:客户端需要在每次请求时,手动地将其添加到请求头中(通常是 Authorization: Bearer <token>),浏览器不会像Cookie一样自动发送。
                        • 无状态:服务器验证Token的签名即可确认其有效性,不需要在服务器端存储任何会话信息。这使得服务器扩展非常容易。

                        工作流程简述(以JWT为例)

                        • 用户登录,服务器验证通过后,生成一个JWT(包含用户信息和签名),将其返回给客户端。
                        • 客户端保存这个JWT(例如在Local Storage中)。
                        • 客户端后续请求API时,在HTTP请求头的 Authorization 字段中携带这个JWT。
                        • 服务器收到请求,验证JWT的签名是否有效、是否过期。如果有效,就直接使用Token中包含的用户信息进行后续处理。

                        Cookie 和 Session 是“黄金搭档”:在传统的Session认证方案中,Cookie是Session ID的载体。Session机制解决了HTTP协议无状态的问题,而Cookie解决了Session ID的传递和存储问题。它们是相辅相成、密不可分的一对。

                        Token 可以作为 Cookie 的内容:Token也可以选择存储在Cookie中,由浏览器自动管理。这种方式结合了Cookie的自动携带和Token的无状态优点,但需要注意防范CSRF攻击。

                        共同目标:三者的终极目标都是为了在无状态的HTTP协议之上,实现有状态的用户身份认证和会话管理

                        特性 Cookie Session Token (以JWT为例)
                        存储位置 客户端(浏览器) 服务器端(内存、DB、Redis) 客户端(LocalStorage, Cookie等)
                        安全性 较低,易被XSS和CSRF攻击 较高,敏感信息在服务器 较高,但需防XSS。签名防篡改
                        扩展性 差,服务器集群间同步Session复杂 ,无状态,天然支持分布式
                        跨域支持 受同源策略限制,需额外配置CORS 受同源策略限制 容易,可在请求头中携带,支持CORS
                        传输方式 浏览器自动通过Cookie请求头携带 通过Cookie携带其ID 手动通过Authorization等请求头携带
                        数据容量 小(约4KB) 大(受服务器资源限制) 中等(不宜过大,影响传输效率)
                        服务器压力 大,需要存储所有用户的会话数据 小,只需验证签名,无需存储

                        为了帮助你更好地理解,我们可以用一个形象的比喻:

                        Cookie 就像 “会员卡”

                        你(浏览器)去健身房(服务器),前台(服务器)给你一张印有卡号(Session ID)的会员卡(Cookie)。你下次来,直接出示卡(自动携带Cookie),前台通过卡号查到你的档案(Session)。

                        Session 就像 “健身房前台的会员档案柜”

                        里面存着所有会员的详细资料(用户数据)。卡号(Session ID)是打开对应档案抽屉的钥匙。

                        Token (JWT) 就像 “一张加密的防伪门票”

                        你第一次验票进场后,检票处(服务器)给你一张特殊材质的门票(Token),上面用特殊工艺印着你的身份信息和防伪码(签名)。你去看每个场馆(访问每个API)时,都需要主动出示这张票(手动携带Token),检票处用特定灯光(验证算法)一照,就能辨别真伪,无需再回总台查名单。

                        如何选择?

                        • 传统Web应用(有服务端模板渲染,如JSP, PHP):使用 Cookie + Session 非常自然和方便。
                        • 前后端分离应用(如React/Vue + Node.js/Java API)、移动端APP或需要跨域认证的场景:使用 Token(尤其是JWT) 是更现代、更合适的选择,因为它无状态、扩展性好

                        我们通常不会将用户的真实密码和账号保存在Cookie或Session中。这样做会带来严重的安全风险。下面分别说明:

                        Cookie:如果将用户的账号和密码直接保存在Cookie中,那么这些敏感信息就会以明文形式存储在用户的浏览器中,并且每次请求都会自动发送给服务器。这极易导致信息泄露,例如:

                        • 如果Cookie被窃取(通过XSS攻击),攻击者就能拿到用户的账号和密码。
                        • 即使加密存储,也不安全,因为密钥同样需要存储在客户端,且加密可能被破解。

                        Session:在Session中,我们通常也不会保存用户的真实密码。Session中存储的是用户登录后的状态信息,例如用户ID、用户名、登录状态等。用户的密码在登录验证通过后,就不应该再被保留在Session中。

                        那么,正确的做法是怎样的呢?

                        正确的认证流程

                        • 用户登录:用户提交账号和密码。
                        • 服务器验证:服务器在数据库中查找该账号,并验证密码(通常数据库中的密码是经过哈希加密的,不会存储明文密码)。
                        • 创建Session:验证通过后,服务器创建一个Session,在Session中存储一些不敏感的用户信息(如用户ID、用户名等)和登录状态。
                        • 设置Cookie:服务器将Session ID通过Cookie返回给浏览器,浏览器后续请求会携带这个Session ID。
                        • 后续请求:服务器通过Session ID找到对应的Session,从而知道是哪个用户。

                        另外,使用Token(如JWT)的方式:

                        • 用户登录:用户提交账号和密码。
                        • 服务器验证:验证通过后,服务器生成一个Token(如JWT),Token中包含一些用户信息(如用户ID)和过期时间,并用服务器密钥签名。
                        • 返回Token:服务器将Token返回给客户端,客户端保存(通常放在localStorage或Cookie中)。
                        • 后续请求:客户端在请求头中携带Token,服务器验证Token的签名和有效性,从而识别用户。

                        在Token方式中,密码同样不会存储在Token中,Token中只包含必要的信息(如用户ID)和签名。

                        总结

                        • 绝对不要将用户的真实密码存储在Cookie或Session中。
                        • 在Session中只存储必要的用户标识和状态,而不是敏感信息。
                        • 在认证过程中,密码应该通过安全通道(如HTTPS)传输,并且在服务器端与存储的哈希值进行验证,验证后立即“忘记”密码(不保存)。

                        所以,用户的真实密码既不应该保存在Cookie里,也不应该保存在Session里。

                        绝对不要将用户的真实密码和账号保存在Cookie或Session中! 这是Web安全的基本原则。

                        在 requests 进行登录时,账户和密码是通过 POST 请求的 data 参数发送的

                        data参数接受一个字典

                        我们之前讨论过,Cookie和Session不是用来存储密码的,而是用来维护会话状态的。在requests库中,Cookie和Session的作用如下:

                        • Session对象:在requests库中,Session对象允许你跨请求保持某些参数,比如Cookie、头部信息等。它最常用的功能就是保持登录状态(通过自动处理Cookie)。
                        • Cookie:在HTTP请求中,Cookie是服务器发送到浏览器并保存在本地的一小段数据,浏览器会在后续的请求中自动携带这些数据。在requests中,你可以手动为请求添加Cookie,但更常见的做法是使用Session对象自动管理。

                        在爬虫中,我们通常使用Session来模拟登录后的会话,步骤如下:

                        a. 创建一个Session对象。

                        b. 发送登录请求(POST请求,包含用户名和密码),这个请求会返回一个包含Cookie的响应,Session会自动保存这个Cookie。

                        c. 使用同一个Session对象发送后续请求,Session会自动在请求中携带之前保存的Cookie,这样服务器就认为你已经登录了。

                        注意:我们不会将密码存储在Cookie或Session中,而是通过登录请求将密码(通常是加密的)发送给服务器,服务器验证后返回一个会话标识(例如Session ID),这个标识会保存在Cookie中,后续请求就靠这个标识来维持登录状态。

                        不是用来存储密码的,而是用来自动管理HTTP会话状态的:

                        import requests
                        
                        # 创建会话对象
                        session = requests.Session()
                        
                        # Session会自动:
                        # 1. 保持连接,提高性能
                        # 2. 自动管理Cookies(服务器返回的)
                        # 3. 保持请求头等信息的一致性

                        Session的实际工作方式:

                        # 第一次请求:登录
                        login_data = {'username': 'user', 'password': 'pass'}
                        response = session.post('https://example.com/login', data=login_data)
                        # 服务器返回 Set-Cookie: session_id=abc123
                        # Session对象会自动保存这个cookie
                        
                        # 第二次请求:访问个人页面
                        # Session会自动在请求头中添加: Cookie: session_id=abc123
                        profile_response = session.get('https://example.com/profile')
                        # 不需要手动处理cookies!

                        cookies 参数是用于手动设置请求中的Cookie,而不是存储密码:

                        # 方式1:使用字典
                        cookies_dict = {'session_id': 'abc123', 'user_token': 'xyz789'}
                        response = requests.get(url, cookies=cookies_dict)
                        
                        # 方式2:使用CookieJar
                        from http.cookies import SimpleCookie
                        
                        cookie = SimpleCookie()
                        cookie['session_id'] = 'abc123'
                        cookie['session_id']['domain'] = 'example.com'
                        response = requests.get(url, cookies=cookie)

                        课本上实现第二种方式使用的是requests.cookies.RequestsCookieJar()类

                        import requests
                        
                        # 创建会话
                        session = requests.Session()
                        
                        # 1. 首先可能需要获取登录页,获取CSRF token等
                        login_page = session.get('https://example.com/login')
                        # 这里可以解析页面获取CSRF token
                        
                        # 2. 准备登录数据(密码只在这里短暂使用)
                        login_data = {
                            'username': 'your_username', 
                            'password': 'your_password',  # 密码只在这里出现一次
                            'csrf_token': '从登录页面获取的token'
                        }
                        
                        # 3. 发送登录请求
                        login_response = session.post(
                            'https://example.com/login', 
                            data=login_data
                        )
                        
                        # 登录成功后,session自动保存了服务器返回的认证cookie
                        # 后续请求都会自动携带这个cookie
                        
                        # 4. 访问需要登录的页面(自动携带cookies)
                        dashboard = session.get('https://example.com/dashboard')
                        profile = session.get('https://example.com/profile')
                        
                        # 密码变量现在可以清除了(虽然Python会自动回收)
                        del login_data['password']

                        以上就是Python抓取静态网页数据的完整指南的详细内容,更多关于Python抓取静态网页数据的资料请关注风君子博客其它相关文章!

                        您可能感兴趣的文章:

                        • Python使用PyQuery快速解析网页数据的实战指南
                        • Python通过BeautifulSoup抓取网页数据并解析
                        • python实现抓取网页数据并生成excel的实例
                        • Python实现快速抓取网页数据的5种高效方法
                        • 一文教你Python如何快速精准抓取网页数据
                        • 利用Python抓取网页数据的多种方式与示例详解
                        • Python获取网页数据的五种方法

                        站内搜索