程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Python 基础

  • Python 进阶

  • Python爬虫

    • requests 库 - HTTP for Humans
      • 1. 安装 requests 库
      • 2. 发送你的第一个 GET 请求
        • 什么是 Response 对象?
      • 3. 在 URL 中传递参数
      • 4. 获取不同的响应内容
        • 4.1 下载图片(二进制内容)
        • 4.2 解析 JSON 数据(API 交互)
      • 5. 自定义请求头 (Headers)
      • 6. 发送 POST 请求
        • 6.1 提交表单数据 (data 参数)
        • 6.2 提交 JSON 数据 (json 参数)
      • 7. 超时 (Timeout)
      • 8. 异常处理
      • 9. 会话对象 (Session)
      • 10. 使用代理 (Proxies)
        • 10.1 HTTP 和 HTTPS 代理
        • 10.2 需要认证的代理
        • 10.3 SOCKS 代理
    • Beautiful Soup - HTML解析利器
    • Selenium - 动态网页抓取神器
    • Scrapy - 工业级爬虫框架
  • Scrapy 爬虫框架

  • Python
  • Python爬虫
scholar
2025-07-21
目录

requests 库 - HTTP for Humans

# requests 库 - HTTP for Humans

在爬虫的世界里,第一步就是模拟浏览器,向目标网站的服务器发送一个“请求”(Request),然后接收服务器返回的“响应”(Response)。Python 的 requests 库就是为此而生的神器。它极大地简化了发送 HTTP 请求的过程,让复杂的网络交互变得像调用一个普通函数一样简单。


# 1. 安装 requests 库

requests 是一个第三方库,需要通过 pip 进行安装。打开你的终端或命令行,输入以下命令:

pip install requests
1

如果你使用的是 conda 环境,也可以使用:

conda install requests
1

安装成功后,你就可以在 Python 脚本中通过 import requests 来使用它了。


# 2. 发送你的第一个 GET 请求

GET 是最常见的 HTTP 请求方法,通常用于向服务器索取数据。当你访问一个网页时,浏览器就是在发送 GET 请求。

import requests

# 1. 定义你要抓取的网页 URL
url = "https://www.baidu.com"

# 2. 使用 requests.get() 方法发送一个 GET 请求
#    这个调用会返回一个 Response 对象,我们通常用变量 response 来接收
response = requests.get(url)

# 3. response 对象包含了服务器返回的所有信息
#    我们来检查一下它的几个核心属性

# 3.1 状态码 (Status Code)
#     状态码是服务器对请求的响应结果的数字代码。
#     200 表示请求成功。404 表示未找到。500 表示服务器内部错误。
print(f"状态码: {response.status_code}")

# 3.2 响应内容的编码格式
#     requests 会猜测响应内容的编码格式,但有时会猜错,导致乱码。
print(f"推测的编码: {response.encoding}")

# 3.3 手动设置正确的编码 (防止乱码的关键)
#     如果发现 response.text 乱码,可以手动将其设置为服务器实际使用的编码,
#     通常是 'utf-8'。
response.encoding = 'utf-8'
print(f"手动设置编码后: {response.encoding}")

# 3.4 响应头 (Headers)
#     响应头是服务器返回的一些元数据,例如内容类型、服务器软件等。
#     它是一个类似字典的对象。
print(f"响应头: {response.headers}")
print(f"响应头中的内容类型: {response.headers['Content-Type']}")

# 3.5 响应体 (Response Body) - 网页的实际内容
#     .text 属性会以文本形式返回响应内容,requests 会根据 encoding 属性解码。
#     这通常就是我们看到的网页 HTML 源代码。
print(response.text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 什么是 Response 对象?

当你执行 requests.get() 或其他请求方法时,你得到的不是一个简单的字符串,而是一个功能强大的 Response 对象。这个对象就像一个包裹,里面装满了服务器返回的所有信息:

  • status_code: 数字状态码。
  • headers: 响应头,一个不区分大小写的字典。
  • encoding: 响应的编码格式。
  • text: 解码后的响应体文本。
  • content: 原始的、未解码的响应体(字节流)。
  • json(): 如果响应是 JSON 格式,可以用这个方法直接将其解码为 Python 字典。

# 3. 在 URL 中传递参数

很多时候,你需要向 URL 传递一些参数,例如搜索关键词、页码等。比如 https://www.baidu.com/s?wd=python。

虽然你可以手动拼接字符串,但 requests 提供了更优雅、更安全的方式:使用 params 参数。

import requests

# 基础 URL
base_url = "https://www.baidu.com/s"

# 1. 将所有 URL 参数组织成一个字典
#    requests 会自动帮你进行 URL 编码,无需担心特殊字符
params = {
    'wd': 'Python 爬虫',
    'ie': 'utf-8'
}

# 2. 在 get 请求中传入 params 字典
response = requests.get(base_url, params=params)

# 3. .url 属性可以查看 requests 最终拼接生成的完整 URL
print(f"最终请求的 URL: {response.url}")

# 4. 打印响应内容,这里会是百度搜索“Python 爬虫”的结果页面
# response.encoding = 'utf-8' # 百度页面可能需要设置
# print(response.text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

使用 params 的好处:

  • 代码更清晰: 将 URL 和参数分离,易于阅读和修改。
  • 自动编码: requests 会妥善处理各种特殊字符(如空格、中文等),避免了手动 URL 编码的麻烦和错误。

# 4. 获取不同的响应内容

根据服务器返回的数据类型,我们可以用不同的方式来获取响应体。

  • response.text: 获取文本内容。这是最常用的方式,适用于 HTML、XML、普通文本等。requests 会根据 response.encoding 来解码。
  • response.content: 获取字节内容。适用于需要下载图片、视频、PDF 等二进制文件。它返回的是原始的 bytes 数据。
  • response.json(): 获取 JSON 内容。如果服务器返回的是 JSON 格式的数据(这在 API 接口中非常常见),这个方法会直接将其解析成 Python 的字典或列表。

# 4.1 下载图片(二进制内容)

import requests

# 图片的 URL
image_url = "https://www.python.org/static/community_logos/python-logo-master-v3-TM.png"

response = requests.get(image_url)

# 1. 检查请求是否成功
if response.status_code == 200:
    # 2. 使用 .content 获取二进制数据
    image_data = response.content

    # 3. 以二进制写入('wb')模式打开一个文件,并将图片数据写入
    with open("python_logo.png", "wb") as f:
        f.write(image_data)
    print("图片下载成功!")
else:
    print(f"下载失败,状态码: {response.status_code}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 4.2 解析 JSON 数据(API 交互)

import requests

# 一个返回 JSON 数据的测试 API
api_url = "http://httpbin.org/get"

response = requests.get(api_url, params={'name': 'scholar', 'age': 18})

# 1. 检查响应头,确认内容是 JSON
print(f"Content-Type: {response.headers['Content-Type']}")

# 2. 如果是 JSON,直接调用 .json() 方法
if 'application/json' in response.headers.get('Content-Type', ''):
    # .json() 会自动解码并返回一个 Python 字典
    data = response.json()
    
    # 3. 像操作普通字典一样操作数据
    print(type(data))
    print(data)
    print(f"请求来源 IP: {data['origin']}")
    print(f"传递的参数: {data['args']}")
else:
    print("响应不是 JSON 格式")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 5. 自定义请求头 (Headers)

当你向网站发送请求时,你的请求中会包含一个“请求头”(Request Headers),它告诉服务器关于你的一些信息,比如你使用的浏览器类型、你接受什么样的数据等。

有些网站会检查请求头中的 User-Agent 字段,如果发现它不是来自一个正常的浏览器,就可能会拒绝你的请求。因此,伪装 User-Agent 是爬虫的基本功。

import requests

url = "https://www.zhihu.com" # 知乎对 User-Agent 有较强的校验

# 1. 定义一个字典来存放请求头
#    最关键的是 'User-Agent'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}

# 2. 在请求中通过 headers 参数传入
#    这样,requests 发送的请求就会带上你指定的 User-Agent
response = requests.get(url, headers=headers)

# 即使有 User-Agent,知乎也可能返回非 200 状态码,但至少请求是模仿浏览器发出的
print(f"状态码: {response.status_code}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 6. 发送 POST 请求

与 GET 请求(索取数据)不同,POST 请求通常用于向服务器提交数据,例如用户登录、提交表单等。

# 6.1 提交表单数据 (data 参数)

当你在网页上填写一个表单并点击“提交”时,浏览器通常会发送一个 POST 请求,并将表单中的数据放在请求体中。requests 使用 data 参数来模拟这个过程。

import requests

# httpbin.org 是一个很好的测试网站
post_url = "http://httpbin.org/post"

# 1. 准备要提交的表单数据,格式为字典
form_data = {
    'username': 'scholar',
    'password': 'mysecretpassword'
}

# 2. 使用 requests.post() 方法,并通过 data 参数提交
response = requests.post(post_url, data=form_data)

# 3. 查看响应结果,httpbin 会将你提交的数据原样返回
json_response = response.json()

print(f"提交的表单数据: {json_response['form']}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 6.2 提交 JSON 数据 (json 参数)

对于现代的 Web API,更常见的做法是直接在请求体中提交 JSON 格式的数据。requests 对此有专门的 json 参数支持。

import requests

post_url = "http://httpbin.org/post"

# 1. 准备要提交的 JSON 数据,也是一个 Python 字典
json_data = {
    'user_id': 123,
    'post_content': '这是我的第一篇帖子',
    'tags': ['python', 'requests']
}

# 2. 使用 json 参数提交
#    requests 会自动:
#    a. 将 Python 字典序列化为 JSON 字符串。
#    b. 设置请求头的 'Content-Type' 为 'application/json'。
response = requests.post(post_url, json=json_data)

# 3. 查看响应结果
json_response = response.json()

# 在响应的 'data' 字段可以看到序列化后的 JSON 字符串
print(f"提交的 JSON 原始数据: {json_response['data']}")
# 在响应的 'json' 字段可以看到被解析回来的 Python 字典
print(f"服务器解析后的 JSON 数据: {json_response['json']}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

data vs json 参数总结:

  • data: 用于提交传统的 application/x-www-form-urlencoded 表单数据。
  • json: 用于提交 application/json 数据,更现代、更常用。requests 会帮你自动处理序列化和请求头。

# 7. 超时 (Timeout)

网络请求有时会因为服务器响应慢或网络问题而卡住。为了防止你的程序无限期地等待下去,设置一个超时时间非常重要。

import requests
from requests.exceptions import Timeout

url = "http://httpbin.org/delay/5" # 这个 URL 会延迟 5 秒后才响应

try:
    # 设置超时为 3 秒。如果 3 秒内服务器没有响应,就会抛出 Timeout 异常
    response = requests.get(url, timeout=3)
    print("请求成功!")
except Timeout:
    print("请求超时!程序不会被卡住。")

1
2
3
4
5
6
7
8
9
10
11
12

timeout 参数可以是一个数字(连接和读取的总超时),也可以是一个元组 (connect_timeout, read_timeout) 分别设置。


# 8. 异常处理

健壮的爬虫必须能处理各种网络异常。requests 库的常见异常都继承自 requests.exceptions.RequestException。

import requests
from requests.exceptions import RequestException, ConnectionError, HTTPError, Timeout

urls_to_test = [
    'http://httpbin.org/status/404', # 一个会返回 404 的 URL
    'http://invalid.domain.that.does.not.exist', # 一个无效的域名
    'http://httpbin.org/delay/5' # 一个会超时的 URL
]

for url in urls_to_test:
    try:
        response = requests.get(url, timeout=3)

        # 检查 HTTP 错误状态码 (如 4xx 或 5xx)
        # 如果状态码不是 2xx,.raise_for_status() 会抛出 HTTPError
        response.raise_for_status() 

    except Timeout:
        print(f"请求 {url} 超时了。")
    except HTTPError as http_err:
        print(f"请求 {url} 发生 HTTP 错误: {http_err}")
    except ConnectionError as conn_err:
        print(f"请求 {url} 发生连接错误: {conn_err}")
    except RequestException as err:
        print(f"请求 {url} 发生未知错误: {err}")
    else:
        print(f"请求 {url} 成功!状态码: {response.status_code}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

核心实践:

  • 总是将你的请求代码放在 try...except 块中。
  • 至少捕获 requests.exceptions.RequestException 这个基类异常。
  • 使用 response.raise_for_status() 是一个检查请求是否“业务上”成功的好习惯。

# 9. 会话对象 (Session)

如果你需要向同一个网站发送多次请求(例如,先登录,再访问个人主页),使用 requests.Session() 对象会带来两个巨大的好处:

  1. 自动保持 Cookies: Session 对象会自动管理 Cookies。如果你通过 Session 登录了一个网站,后续通过同一个 Session 发出的所有请求都会自动带上登录后的 Cookie,无需你手动处理。
  2. 性能提升: Session 会保持底层的 TCP 连接,当你对同一个主机进行多次请求时,它会重用这个连接,而不是每次都重新建立,从而大大提高了效率。
import requests

# 1. 创建一个 Session 对象
session = requests.Session()

# 2. 伪装请求头,可以在 Session 级别设置
#    之后这个 Session 发出的所有请求都会使用这个头
session.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
})

# 3. 使用 Session 对象发出第一个请求
#    httpbin.org/cookies/set 会在响应中设置一个名为 'sample' 的 cookie
session.get('http://httpbin.org/cookies/set/sample/123456789')

# 4. 再次使用同一个 Session 发出请求
#    这次请求会自动带上之前服务器设置的 'sample' cookie
response = session.get('http://httpbin.org/cookies')

# 5. 查看响应,你会发现服务器收到了我们之前设置的 cookie
print(response.json()) # 输出: {'cookies': {'sample': '123456789'}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

结论: 当你需要和网站进行多次交互时(特别是需要登录的场景),始终优先使用 requests.Session 对象。


# 10. 使用代理 (Proxies)

当你在短时间内对同一个网站进行大量请求时,你的 IP 地址很容易被服务器识别并封禁。为了避免这种情况,以及隐藏自己的真实 IP,使用代理服务器是一个非常常见的反爬策略。

requests 库可以非常方便地配置代理。

# 10.1 HTTP 和 HTTPS 代理

你需要准备一个代理服务器的地址和端口,然后将其组织成一个字典,通过 proxies 参数传递给请求方法。

import requests

# 目标网站,httpbin.org/ip 会返回你请求的来源 IP 地址
url = "http://httpbin.org/ip"

# 1. 代理服务器的地址和端口
#    格式: '协议': 'http://IP地址:端口号'
#    注意:即使代理服务器本身是 HTTP 的,它也可以代理 HTTPS 请求。
proxy_ip = "127.0.0.1:8888" # 这是一个示例,请替换成你自己的有效代理 IP

proxies = {
   'http': f'http://{proxy_ip}',
   'https': f'http://{proxy_ip}', # 也可以是 https://IP:PORT
}

try:
    # 2. 在请求中传入 proxies 参数
    response = requests.get(url, proxies=proxies, timeout=5)
    
    # 3. 查看返回的 IP 地址,如果代理有效,这里应该是代理服务器的 IP
    print("使用了代理的响应:")
    print(response.json())

except requests.exceptions.ProxyError:
    print("代理连接失败!请检查代理服务器是否可用。")
except Exception as e:
    print(f"发生错误: {e}")

# 作为对比,我们再发一个不使用代理的请求
print("\n未使用代理的响应:")
response_no_proxy = requests.get(url)
print(response_no_proxy.json())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 10.2 需要认证的代理

很多付费代理服务需要提供用户名和密码进行认证。你可以将认证信息直接包含在代理 URL 中。

import requests

# 格式: http://用户名:密码@IP地址:端口
proxy_with_auth = "http://user:password@127.0.0.1:8888"

proxies = {
   'http': proxy_with_auth,
   'https': proxy_with_auth,
}

# response = requests.get("http://example.com", proxies=proxies)
1
2
3
4
5
6
7
8
9
10
11

# 10.3 SOCKS 代理

requests 默认不支持 SOCKS 协议的代理。但你可以通过安装一个额外的库 PySocks 来轻松启用它。

  1. 首先,安装 PySocks:

    pip install pysocks
    
    1
  2. 然后,在代理字典中使用 socks5 或 socks5h 作为协议:

    • socks5: 代理服务器在本地解析域名。
    • socks5h: 域名解析在代理服务器端进行(h 代表 hostname)。
import requests

# SOCKS5 代理地址
socks_proxy = "127.0.0.1:1080" # 示例 SOCKS5 代理

proxies = {
    'http': f'socks5h://{socks_proxy}',
    'https': f'socks5h://{socks_proxy}',
}

try:
    # 安装 PySocks 后,requests 会自动识别并使用 SOCKS 代理
    response = requests.get('https://httpbin.org/ip', proxies=proxies)
    print("通过 SOCKS5 代理的响应:")
    print(response.json())
except Exception as e:
    print(f"SOCKS 代理请求失败: {e}")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

通过合理使用代理,你可以大大提高爬虫的稳定性和成功率,是进阶爬虫工程师必备的技能。

编辑此页 (opens new window)
上次更新: 2025/07/27, 04:30:11
序列化与反序列化
Beautiful Soup - HTML解析利器

← 序列化与反序列化 Beautiful Soup - HTML解析利器→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式