python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python抓取静态网页数据

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

作者:embrace飞行日记

静态网页是指网页的内容在服务器上被创建和存储时就已经完全确定好了,本文将和大家详细讲讲如何使用Python抓取静态网页数据,感兴趣的小伙伴可以了解下

一.什么是静态网页

1.静态网页的含义

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

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

2.静态网页的特点

1.内容固定不变

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

2.服务器处理简单

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

3.加载速度快

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

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

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

5.安全性高

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

3.静态网页的技术构成

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

4.静态网页 vs. 动态 网页

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

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

5.现代静态网站的演进

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

Jamstack 的核心思想是:

例如:一个新闻网站。

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

现代Jamstack

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

二.抓取静态网页的技术

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

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

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

1.urllib

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

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

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

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

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

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

2.urllib3

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

3.requests

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

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

三.发送基本请求

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

GET和POST请求核心区别总结

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

1.发送GET请求

不携带URL参数的GET请求

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

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

url参数是必需的

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

发送携带参数的URL的GET请求

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的参数值为字典这种使用最常用

2.发送POST请求

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

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

基本使用方法:

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

主要参数:

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和请求方式:

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

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

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

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

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

如何识别

重点关注

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

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

url组成部分分解

关于URL编码

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

可以在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}")  # 输出: 苏轼

判断正确URL的方法

时间顺序法

URL特征法

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

大小和类型判断

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

3.处理复杂的请求

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

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

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

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

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

使用session保持会话

SSL证书验证

设置代理服务器

四.对Cookie、Session、Token的一些理解

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

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

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

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

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

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

Cookie

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

核心特点

主要用途

Session

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

核心特点

工作流程简述

Token

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

核心特点

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

三者的联系

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

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

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

核心区别(重点)

特性CookieSessionToken (以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),检票处用特定灯光(验证算法)一照,就能辨别真伪,无需再回总台查名单。

如何选择?

五.用户的真实账号和密码被存在了哪里

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

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

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

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

正确的认证流程

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

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

总结

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

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

六.requests模块中cookies和session的作用

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

data参数接受一个字典

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

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

a. 创建一个Session对象。

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

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

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

requests.Session() 的作用

不是用来存储密码的,而是用来自动管理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 参数的作用

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抓取静态网页数据的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文