静态网页作为早期互联网的主要形式,它的数据直接内嵌于HTML源代码中,是网络爬虫最基础且最易处理的抓取对象。尽管静态网页的结构相对简单,但在实际抓取过程中仍会面临诸多挑战,包括但不限于网站防爬虫、网络请求异常以及数据解析困难等问题。针对这些常见问题,需要采取系统化的解决方案来确保爬虫程序的稳定性。本章将系统性地介绍静态网页数据抓取的完整流程,从基础的请求发起,到复杂的请求参数配置,再到各类防爬虫策略的应对措施。
3.1 抓取静态网页的技术
静态网页是由服务器预先生成的完整HTML文档,这种网页的内容在服务器端已经完全确定,不会因用户的请求而产生变化。在静态网页中,所有的数据都直接内嵌在HTML源代码中,无需依赖一些前端技术进行渲染即可完整呈现。因此,抓取静态网页的数据本质上就是获取静态网页的源代码的过程。网络爬虫通过模仿浏览器的行为,向Web服务器发送HTTP请求并接收响应,即可完整获取静态网页的全部数据。
为帮助开发者实现静态网页抓取,Python提供了专门用于发送和接收HTTP请求的编程工具库,包括 urllib、httpx和Requests。其中,urllib是Python内置库,无须安装便可以直接在程序中使用;其他都是第三方库,需要另行安装后才可以在程序中使用。
1.urllib
urllib是Python标准库提供的原生HTTP客户端库,主要由urllib.request、urllib.error、urllib.parse和urllib.robotparser共4个核心模块组成,实现完整的网络请求解决方案。作为内置库,urllib无需额外安装,特别适合轻量级网络爬虫的需求或运行环境受限的场景。不过其API设计偏向底层,开发者需要手动处理连接管理、编码转换和Cookies维护等细节,这使得它在实际项目中通常作为备选方案。
2.Requests
Requests是Python生态中非常流行的HTTP客户端库,以简洁优雅的API设计著称。它基于urllib3库实现,提供了高度封装的GET或POST请求方法,能够自动处理URL编码、会话保持和连接复用等复杂细节,全面支持Cookies管理、代理设置和超时控制等核心功能,极大简化了HTTP交互的复杂度,使其成为静态网页数据抓取场景下的标准解决方案。不过,Requests目前仅支持同步请求模式,这是其在异步编程场景中的主要局限。
3.httpx
httpx是新一代高性能HTTP客户端库,在保留与 Requests相似API设计的同时,实现了多项重要突破。作为现代化多协议支持库,它不仅完美兼容HTTP/1.1,还原生支持HTTP/2协议,并提供了同步或异步双模式请求能力。该库通过智能编码处理、强类型提示系统以及优化的连接池管理等特性,显著提升了开发体验和运行效率。其内置的超时控制机制和网络适应性调整功能,使其在复杂网络环境下表现出色,特别适合需要协议升级或追求更高性能的项目场景,堪称Requests库的现代化继任者。
综上所述,Python提供了多个各具特色的HTTP客户端库,其中urllib库偏向底层,新兴的httpx库技术支持更多现代特性,但Requests凭借其广泛的应用基础和成熟的生态,已经成为静态网页数据抓取的标准。基于教学示范的普适性考量,本书后续将选择用Requests库进行开发。
值得一提的是,Requests是第三方库,需要通过pip工具进行安装,如此便可以在导入程 序后直接使用。例如,在当前的开发环境中安装指定版本的Requests库,具体命令如下。
pip install requests==2.32.3
3.2 发送基本请求
3.2.1 发送GET请求
当用户在浏览器的地址栏中输入某个URL地址或者单击网页上的某个超链接时,浏览器默认会使用GET方法 向 服 务 器 发 送 请 求 。 例 如 , 在 浏 览 器 的 地 址栏中分别输入百度一下,你就知道和 python_百度搜索,访问百度首页和python关键词的查询结果页面时,浏览器实际上发送了GET请求。GET请求是常用的HTTP请求方法,它主要用于从服务器获取资源,会将请求参数以明文形式附加在URL之后,适合获取不需要敏感信息的公开数据。
在requests库中,get()函数用于向服务器发送GET请求,并获取服务器返回的响应内容。该函数执行时,首先会根据传入的URL自动构建符合标准的请求(每个请求都是Request对象),然后将该请求发送至目标服务器,最后返回结构完整的响应(每个响应都是Response对象)。
get(url, params=None, headers=None, cookies=None,
verify=True, proxies=None, timeout=None, **kwargs)
url:必选参数,表示请求的URL。 params:可选参数,用于指定目标URL的查询字符串。该参数有 3 种类型的取值,分别为字典、元组列表和字节序列。如果取值是一个字典,则字典的键为 URL 查询参数,字典的值为 URL 查询参数对应的值,例如{"ie": "utf-8","wd": "python"}会被自动编码为?ie=utf-8&wd=python。 headers:可选参数,表示请求的请求头,该参数只支持字典类型的值。 cookies:可选参数,表示请求的Cookie信息,该参数支持字典或CookieJar类对象。 verify:可选参数,表示是否启用SSL证书,默认值为True。 proxies:可选参数,用于设置代理服务器,该参数只支持字典类型的值。 timeout:可选参数,表示请求网页时设定的超时时长,以秒为单位。
1.不携带URL查询参数的GET请求
若GET请求的URL中不需要携带查询参数,则调用get()函数发送GET请求时只需要向url参数传递目标URL。
下面以访问百度首页演示如何使用get()函数发送不携带URL查询参数
python
import requests
# 准备目标URL
base_url = 'https://www.baidu.com/'
# 根据目标URL向服务器发送GET请求,接收服务器返回的响应信息
response = requests.get(url=base_url)
# 查看响应码
print(response.status_code)
2.携带URL查询参数的GET请求
get()函数会返回Response对象,该对象封装了服务器返回的所有信息,包括响应状态码、响应内容以及响应头。
如果GET请求的URL中需要携带查询参数,那么调用get()函数时可以采用两种方式发送GET请求。第1种方式是将查询参数以"参数名1=值 1&参数名 2=值 2..."的形式拼接到URL的? 后面 , 进 而 手 动 构 建 完 整 的URL,例如 图书-人邮教育社区之后将完整的URL传入url参数;第2种方式是将查询参数转换为字典,之后将该字典传入params参数。
下面以访问人民邮电出版社的结果页面为例,演示如何使用get()函数发送携带URL查询参数的GET请求。
python
import requests
# 准备基本URL
base_url = 'https://www.ryjiaoyu.com/book'
# 定义请求参数
params = 'tab=book&sort=new&category=13'
# 根据基本URL和参数构建完整URL
full_url = base_url + '?' + params
# 根据完整URL构建请求,发送GET请求,接收服务器返回的响应信息
response = requests.get(full_url, params=params)
print(response.status_code)
写法二
python
import requests
# 准备基本 URL
base_url = 'https://www.ryjiaoyu.com/book'
# 定义查询参数
params = {'tab': 'book', 'sort': 'new', 'category': '13'}
# 根据 URL 和查询参数发送 GET 请求,接收服务器返回的响应信息
response = requests.get(base_url, params=params)
print(response.status_code)
3.2.2 发送POST请求
如果网页中form表单的method属性设置为POST,用户提交表单时,浏览器会通过POST请求将表单内的所有元素及其对应的数据,作为HTTP请求信息中的请求数据发送至服务器,实现提交数据的功能。例如,登录黑马头条网站时发送的请求是POST请求,使用开发者工具捕获该请求,在标头面板和载荷面板中可以看到该请求相关的内容,具体如图所示。

在requests中,post()函数用于向服务器发送POST请求,主要用于向服务器提交数据,比如表单、JSON等。该函数执行时,首先根据目标URL构建请求对象,然后自动处理数据,最后将该请求与数据一并发送给服务器,并返回封装了响应细信息的响应对象。post()函数的声明如下。
post(url, data=None, headers=None, cookies=None, verify=True, proxies=None, timeout=None, json=None, **kwargs)
data:可选参数,用于指定请求发送的表单数据或原始数据。该参数可以接收 3 种类型的值,分别为字典、字节序列和文件对象。当参数值是一个字典时,字典的键为请求数据的字段,字典的值为请求数据中该字段对应的值,例如 {"code": "246810","mobile":"12011111111"}。 json:可选参数,用于指定JSON格式的数据,该参数接收字典或列表,并能自动将它们转换成JSON数据,而不需要再手动调用json.dumps()来转换。
3.2.3 处理响应
当服务器返回的响应状态码为200或201时,说明本次HTTP请求成功,此时可以接收到由服务器返回的响应信息。在Requests库中,Response类的对象中封装了服务器返回的响应信息,这些响应信息包括响应头和响应内容等。除了前面介绍的status_code属性之外,Response类还提供了一些其他属性。
| 属性 | 说明 |
|---|---|
| status_code | 获取服务器返回的状态码 |
| text | 获取字符串形式的响应内容 |
| content | 获取二进制形式的响应内容 |
| url | 获取最终请求的实际URL |
| request | 获取对应的请求对象 |
| headers | 获取响应头 |
| encoding | 设置或获取响应内容的编码格式,与text属性搭配使用 |
| cookies | 获取服务器返回的Cookie |
虽然text和content属性都能用于获取响应内容,但两者在数据类型和处理方式上存在本质区别。text属性会根据 Requests响应头中的Content-Type字段自动进行字符解码,返回处理后的字符串内容,如果未声明编码格式,则会尝试推测,但可能不准确;content属性始终返回原始的二进制字节数据,保留最完整的响应信息,不做任何转换。在实际应用中,text属性适用于处理HTML、JSON等文本数据,而content属性则适用于下载图片、PDF文档等二进制资源。开发者应根据响应内容的类型选择合适的属性,必要时可通过encoding属性手动指定编码格式。
1.获取网页源代码
通过访问Response类的对象的text属性可以获取字符串形式的响应内容,比如网页源代码。例如,在3.2.1节请求百度首页的示例中,通过text属性获取百度首页的源代码,具体代码如加粗部分所示。
python
import requests
# 准备目标URL
base_url = 'https://www.baidu.com/'
# 根据目标URL向服务器发送GET请求,接收服务器返回的响应信息
response = requests.get(url=base_url)
# 设置响应内容的编码格式
response.encoding = 'utf-8'
# 获取响应内容
print(response.text)
按照HTML标准格式调整后的结果如下。
<html>
<head>
<script>
location.replace(location.href.replace("https://","http://"));
</script>
</head>
<body>
<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>
2.获取图片
百度首页上除了文字信息之外,还包含一个百度标志(Logo)图片。若希望获取百度Logo的图片,则需要先根据该图片对应的请求URL发送请求,再使用content属性获取该图片对应的二进制数据,并将数据写入本地文件中,具体代码如下。
python
import requests
base_url = 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
response = requests.get(base_url)
# 获取百度Logo图片对应的二进制数据
print(response.content)
# 将二进制数据写入程序所在目录下的baidu_logo.png文件中
with open('baidu_logo.png', 'wb') as file:
file.write(response.content)
3.3 处理复杂请求
3.3.1 定制请求头
在抓取网页数据的过程中,开发者常常要面临网站防爬虫和各类业务需求的双重挑战,这时仅仅发送基本请求往往难以获取目标数据,很有可能出现禁止访问、数据获取失败等问题。为有效解决这些问题,我们必须根据目标网站的具体要求来完善请求配置,例如,通过登录后的Cookies管理会话状态,以访问登录后才能打开的页面内容,定制请求头信息模拟真实浏览器行为等,从而构建普适性强的请求方案,确保在不同场景下都能稳定获取目标数据。
当网络爬虫发送请求抓取网页数据(如豆瓣读书网站标签分类是历史的页面)时,可能会遇到请求被重定向至验证页面、返回虚假数据或完全无响应等情况。之所以遇到这种情况,其实是因为这些网站为防止网络爬虫恶意抓取网页数据加入了防爬虫措施。它们会检查本次请求中请求头包含哪些关键字段,如果发现缺失关键字段,就会判定发送本次请求的客户端不是浏览器,而可能是一个网络爬虫。
为了解决这个问题,需要为网络爬虫发送的请求定制完整的请求头,使该请求伪装成一个由浏览器发起的请求。请求头主要包括以下几个关键字段。 Referer:用于标识当前请求的来源页面URL,是网站实现防盗链机制的重要手段。许多网站会严格校验这个字段,要求访问必须遵循站内正常的页面跳转逻辑,以确保访问逻辑链的完整性。以豆瓣读书为例,要访问历史标签页,合理的访问流程可以是"豆瓣读书首页→历史标签页",而不能是直接访问历史标签页。 User-Agent:用于标识客户端的身份,包括类型、操作系统、浏览器版本等信息。
定制请求头分为两步,即查看请求头和设置请求头。下面以豆瓣读书的历史标签页面为例,为大家演示如何查看由浏览器发送请求的请求头信息,并根据该请求头信息设置网络爬虫的请求头。
1.查看请求头
打开Chrome浏览器加载豆瓣读书首页,在首页右侧热门标签中选择"历史"跳转到历史标签页面,打开开发者工具后重新加载该页面。从开发者工具的请求列表中选中刚刚发送的请求,并且在右侧即可以查看该请求对应的请求头信息,具体如图所示。

字段Referer的值为豆瓣读书,说明当前请求的来源页面是豆瓣读书首页;字段User-Agent的值是一长串内容,包含浏览器类型、版本等一些信息。
2.设置请求头
在Requests中,设置请求头的方式非常简单,只需要在调用请求函数时将定制好的请求头传入headers参数即可。headers参数只能接收字典类型的数据,其中字典的键为请求头中的使用的字段,字典的值为请求头中字段对应的值。例如,使用Requests请求豆瓣读书的历史标签页面,并按照要求设置请求头,具体代码如下。
python
import requests
base_url = 'https://book.douban.com/tag/历史'
# 定义请求头,用于标识客户端身份和来源页面URL
header = {'User-Agent': 'Mozilla/5.0 (X11; Linux aarch64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/134.0.0.0 Safari/537.36 CrKey/1.54.250320',
'Referer':'https://book.douban.com/'}
# 根据URL向服务器发送GET请求,设置定义好的请求头,接收服务器返回的响应
response = requests.get(base_url, headers=header)
response.encoding = 'utf-8'
print(response.text)
运行代码,控制台输出了一段HTML代码,按照HTML标准格式调整后的结果如下。

对比从浏览器中查看的源代码可知,程序成功抓取了豆瓣读书历史标签页的源代码。
需要注意的是,如果程序使用同一个User-Agent字段访问网站的频率过高,那么程序也有可能会被网站识别成网络爬虫,并被查封。为解决这个问题,可以收集所有可用的User-Agent,在向服务器发送请求时每隔一段时间便随机选择一个User-Agent,设置动态的请求头。除此之外,还可以使用能够自动生成User-Agent的第三方模块 fake-useragent。
3.3.2 验证Cookie
当用户首次登录一个网站时,网站往往会要求用户输入用户名和密码,还会提供自动登录选项供用户勾选。如果用户勾选了自动登录选项并成功登录,那么在下一次访问该网站时,不用重复输入用户名和密码便可以进入用户个人主页,这是因为第一次登录时服务器会生成包含加密登录凭证的Cookie,通过响应头发送至浏览器,浏览器会将该 Cookie存储到本地硬盘,第二次登录时浏览器会自动在请求头中携带该Cookie,服务器只需要验证Cookie中的加密凭证信息就能确认用户的身份,从而实现免密登录。
Cookie是指网站服务器为了辨别用户身份和维持会话状态而存储在浏览器中的小型文本数据,通常不超过4kB。通俗来讲,Cookie是网站用于维持会话状态的小型数据包,由服务器生成并存储在浏览器或用户硬盘中,与普通缓存不同,Cookie专门用于记录用户身份、偏好等状态信息。一个完整的 Cookie由一个名称(Name)、一个值(Value)和多个用于控制Cookie有效期、安全性、使用范围的可选属性组成。
一个完整的Cookie由一个名称(Name)、一个值(Value)和其它多个用于控制Cookie有效期、安全性、使用范围的可选属性组成,这些属性具体如下。 Name和Value属性:Cookie的名称及对应的值,其中名称用于标识Cookie的用途,值通常是加密的会话标识或用户凭证 。 Expires属性:用于设置Cookie的有效期。Cookie的有效期主要有会话性与持久性共两种类型,未设置该属性时为会话性Cookie,会话性Cookie仅仅保存在用户浏览器中,并在关闭浏览器时失效;持久性Cookie会保存在用户的硬盘中,直至生存期到才会失效 。 Path属性:用于定义了Web站点可以访问Cookie的目录。 Domain属性:用于指定可以访问Cookie的Web站点或域。 Secure属性:用于指定是否使用安全协议HTTPS发送Cookie。使用安全协议HTTPS,可以保护Cookie在浏览器和服务器间的传输过程中不被窃取和篡改。
在Requests库中,发送请求时可以通过两种方式携带Cookie,一种方式是直接将包含Cookie信息的请求头传入请求函数的headers参数;另一种方式是将Cookie信息传入请求函数的cookies参数。不过,cookies参数需要接收一个RequestsCookieJar类的对象,该对象类似于一个字典,会以名称(Name)与值(Value)的形式存储Cookie。
3.3.3 保持会话
在访问拼多多网站时,用户只要登录成功一次,就能以登录状态在多个标签页自由浏览商品,执行查看个人信息、加入购物车、提交订单等一些操作,甚至中途短暂离开拼多多网站后仍然保持登录状态,这正是保持会话的典型应用。保持会话通过在多个请求间持续维护身份凭证和服务器交互状态,给用户提供了不间断的操作体验。
会话是Web开发中用于维持用户状态的技术,指用户从登录到退出期间与服务器的完整交互过程,这个过程可以是连续的,也可以是时断时续的。它的核心原理是,服务器为每个用户创建唯一的会话ID(通常由Cookie存储),后续请求通过该ID将用户的多个操作关联起来,从而维持在多个操作之间能够保持连贯性。
传统开发若要通过Cookie保持会话,开发者需要手动管理完整的Cookie生命周期:从登录响应头中解析Set-Cookie字段,本地存储Cookie值,在后续请求中手动携带Cookie。这种方式存在明显的问题: 一是手动处理容易导致Cookie遗漏或格式错误; 二是无法自动感知和处理服务器的Cookie更新; 三是每次请求都需要建立新的TCP连接,造成额外的性能开销。这些问题使得手动Cookie管理方式在复杂的会话保持场景中既低效又不可靠。
为了能有效解决这些问题,Request库提供Session类来管理会话,它会自动管理几个关键环节,包括自动保存登录后的Cookie并持久化存储;后续请求中智能附加所需的 Cookie;通过连接池复用TCP连接提升性能。这种设计使得会话管理变得简单可靠,开发者只需关注业务逻辑,而无需处理底层细节。
使用Session类管理会话时,首先需要使用Session()函数创建会话对象,然后通过该对象调用get()或post()方法来发起请求,这些请求会自动携带会话的配置信息,例如已设置的Cookie、默认请求头等,最后在会话使用完毕后,建议使用close()方法来关闭会话,以释放底层连接池占用的资源,避免资源泄漏。
3.3.4 SSL证书验证
大多数网站中都加入了SSL证书,以实现数据信息在浏览器和服务器之间的加密传输,保证双方传递信息的安全性。SSL证书是一种数字证书,类似于驾驶证、护照和营业执照的电子副本,由受信任的数字证书颁发机构 CA在验证服务器身份后颁发,具有服务器身份验证和数据传输加密功能。
使用Requests调用请求函数发送请求时,由于请求函数的verify参数的默认值为True,所以每次请求网站默认都会进行SSL证书的验证。不过,有些网站可能没有购买SSL证书,或者SSL证书失效。程序访问这类网站时会因为找不到SSL证书而抛出SSLError异常。
3.4 设置代理服务器
3.4.1 代理服务器简介
设置代理服务器是网络爬虫应对防爬虫的核心策略之一,这种策略会为网络爬虫指定一个代理服务器,将原本由本地主机发起的请求转发至代理服务器,借用其IP地址访问目标网站,从而隐藏网络爬虫所在主机的真实IP地址。
网络爬虫在抓取网页的数据时,可能会出现这样的情况:起初可以正常抓取网页的数据,一段时间后便不能继续抓取了,可能会收到403错误及提示信息"您的IP访问频率过高"。之所以出现这种现象是因为网站采取了防爬虫措施,该网站会检测某个IP地址在单位时间内访问的次数,如果超过其设定的阈值,就会直接拒绝为拥有该IP地址的客户端服务,这种情况称为封IP。
为避免网络爬虫被封IP,我们可以利用某种技术伪装IP地址,使服务器无法追踪请求的真实设备来源。代理服务器(Proxy Server)是介于客户端与目标服务器之间的中间 服务器,其核心功能是代替客户端向目标服务器发起请求,并将获取的响应结果返回给客户端。为帮助大家更好地进行理解。
代理服务器如同客户端和Web服务器之间的"中转站"。没有代理服务器之前,客户端会直接将请求发送给Web 服务器,Web服务器将响应信息返回给客户端;有了代理服务器之后,客户端先将请求发送到代理服务器,再由代理服务器转发给Web服务器,同时将收到的响应信息返回给客户端。这样一来,网站识别的IP地址是代理服务器的IP地址,而不是客户端的真实IP地址。此外,通过定期更换代理服务器,可进一步降低因单一IP高频访问触发防爬虫的风险。

值得一提的是,并非所有的代理服务器都适合网络爬虫。我们在使用代理服务器时,主要考虑代理服务器的匿名程度。根据代理服务器的匿名程度,代理服务器可以分为高度匿名代理服务器、普通匿名代理服务器、透明代理服务器3类。

综上所述,免费代理IP是比较容易获取的,不过这类代理IP的质量不高,高度匿名代理IP比较少,有的代理IP很快会失效。如果大家对代理IP的质量要求比较高,或者需要大量稳定的代理IP,那么建议选择一些正规的代理商进行购买。
3.5 处理异常
任何程序在运行过程中都可能会遇到各种各样的问题,网络爬虫自然也不例外。作为依赖网络环境的程序,网络爬虫的抓取操作高度依赖稳定的网络连接,而复杂多变的网络环境(如 DNS解析失败、服务器拒绝连接、网络超时等)具有天然的不可控性,这导致网络爬虫每次请求未必能成功获取服务器响应数据。一旦在访问过程中遭遇网络异常,程序往往会触发异常报错并中断运行。
requests.exceptions模块中定义了很多异常类型,常见的异常类型如下表。
| 异常类型 | 说明 |
|---|---|
| RequestException | 异常基类,表示请求过程中的通用异常 |
| ConnectionError | 网络连接失败时抛出 |
| HTTPError | 当HTTP请求返回错误状态码(如 4xx、5xx)时抛出 |
| URLRequired | 请求未提供有效的 URL 地址时抛出 |
| TooManyRedirects | 请求中重定向次数超过最大限制时抛出 |
| ConnectTimeout | 建立网络连接超过指定超时时间时抛出 |
| ReadTimeout | 从服务器读取响应数据超过指定超时时间时抛出 |
| Timeout | 请求整体执行时间超过设置的超时时间时抛出 |
Timeout继承自RequestException,而ConnectTimeout和ReadTimeout又继承自Timeout。
为确保网络爬虫程序能够优雅地处理异常并正常终止,可以通过try-except语句捕获请求过程中可能抛出的异常,并针对不同异常类型执行相应的处理逻辑,比如重试、记录日志或跳过当前请求。这种异常处理机制能有效提升程序的健壮性,避免因未预期的错误导致程序崩溃。
由于网络环境、政策限制等原因,直接请求部分境外网站(如谷歌)可能会因网络连接问题导致网络爬虫程序抛出异常。下面以请求百度网站为例,为大家演示如何使用try-except语句捕获 RequestException异常,具体代码如下。
python
import time
import requests
# 记录请求的发起时间
print(time.strftime('开始时间:%Y-%m-%d %H:%M:%S'))
# 捕获RequestException异常
try:
# 发送GET请求,设置超时时长
html_str = requests.get('https://www.baidu.com', timeout=5).text
print('访问成功')
except requests.exceptions.RequestException as error:
print(error)
# 记录请求的终止时间
print(time.strftime('结束时间:%Y-%m-%d %H:%M:%S'))
3.6 实践项目:抓取人民教育社区的数据
查看人民教育社区网站: 图书-人邮教育社区
https://www.ryjiaoyu.com/book?tab=book&sort=new&mode=List&page=1


(1)在编写爬虫的相关功能之前,需要导入requests库。 (2)定义一个用于抓取网页数据的函数load_page(),该函数会根据指定的目标URL构建并发送GET请求,然后获取从服务器返回的响应内容。 (3)定义一个保存响应内容的函数save_file(),该函数会将网络爬虫程序每次抓取的响应内容写入到指定的文件中,并指定编码格式为UTF-8。 (4)定义一个控制抓取流程的函数heima_forum(),该函数会按照前面分析的URL规律,通过页码拼接所有页面的URL,之后根据这些URL依次发送GET请求,并将服务器返回的网页数据写入HTML文件中。 (5)在main语句中调用heima_forum()函数,并根据输入的起始页码和结束页码抓取指定页码范围的网页数据。
python
import requests
def load_page(url):
'''
作用:根据URL向黑马论坛服务器发送请求,并获取返回的响应内容
url:待抓取的URL
'''
try:
headers = {'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident / 5.0;'}
# 发送GET请求,设置请求头和超时时长
response = requests.get(url, headers=headers, timeout=10)
return response.text
except requests.exceptions.RequestException as error:
print(f'抛出异常:{error}')
def save_file(html, filename):
'''
作用:将响应内容写入本地文件
html:服务器返回的响应内容
'''
print('正在保存' + filename)
with open(filename, 'w', encoding='utf-8') as file:
file.write(html)
def heima_forum(begin_page, end_page):
'''
作用:爬虫调度器,控制爬虫抓取指定页码范围网页数据的流程
begin_page:起始页码
end_page:结束页码
'''
# 遍历从起始页码到结束页码的所有页码
for page in range(begin_page, end_page + 1):
# 根据当前页码生成目标URL
url = f'https://www.ryjiaoyu.com/book?tab=book&sort=new&mode=List&page={page}'
# 根据目标URL向服务器发送请求,获取响应内容
html = load_page(url)
# 根据当前页码生成文件名
file_name = '第' + str(page) + '页.html'
# 将响应内容保存到本地文件
save_file(html, file_name)
if __name__ == '__main__':
begin_page = int(input('请输入起始页码:'))
end_page = int(input('请输入结束页码:'))
heima_forum(begin_page, end_page)
本章小结
在本章中,主要介绍了抓取静态网页数据的相关内容,包括抓取静态网页的技术、发送基本请求、处理复杂请求、设置代理服务器和处理异常,并开发了一个抓取黑马程序员论坛数据的项目。通过本章内容的学习,读者能够熟练地使用Requests库抓取静态网页数据,为后续解析网页数据做好准备工作。