Bootstrap

Python网络爬虫 urllib3 入门这篇就够了

一、认识网络爬虫

1.1 网络爬虫概述

网络爬虫是一种自动化程序,用于按照规则从互联网上抓取信息。它从指定网页开始,读取内容,发现链接,并依次抓取这些链接指向的网页,循环往复,直至抓取完指定网站的所有网页。爬虫常用于搜索引擎、数据挖掘、网站测试和优化等领域。使用爬虫时,需遵守网站的robots.txt协议和法律法规,避免对网站造成过大压力或侵犯他人权益。网络爬虫的出现,极大地提高了人们获取和处理网络信息的效率。

        

1.2 网络爬虫分类

网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:

  1. 通用网络爬虫(General Purpose Web Crawler):又称全网爬虫,其爬行对象从一些种子URL扩充到整个Web,主要为门户站点搜索引擎和大型Web服务提供商采集数据。
  2. 聚焦网络爬虫(Focused Web Crawler):也称主题网络爬虫,是指按照预先定义好的主题有选择地进行网页爬取,爬取特定的资源。
  3. 增量式网络爬虫(Incremental Web Crawler):指对已下载网页采取增量式更新,只采集新产生的或者已经发生变化网页的爬虫。
  4. 深层网络爬虫(Deep Web Crawler):即Deep Web爬虫,指对大部分内容不能通过静态链接获取,只有用户提交表单信息才能获取Web页面的爬虫。

1.3 网络爬虫的原理

网络爬虫的原理可以简单地概括为以下几个步骤:

  1. 发送请求:爬虫首先向目标网站发送请求,请求的内容包括要获取的网页地址(URL)。
  2. 接收响应:目标网站接收到请求后,会返回一个响应,这个响应的内容就是网页的HTML代码。
  3. 解析网页:爬虫接收到HTML代码后,需要对其进行解析,提取出需要的数据。解析网页的方式有多种,常见的有正则表达式、XPath、BeautifulSoup等。
  4. 存储数据:提取出的数据需要进行存储,以便后续的分析和处理。存储的方式也有多种,可以将数据保存在本地文件中,也可以保存到数据库中。
  5. 循环遍历:爬虫通常会根据网页中的链接,继续向其他网页发送请求,获取数据,直到满足一定的停止条件(比如达到指定的爬取数量、爬取到特定的网页等)。

二、请求模块urlib3

2.1 urllib3的概述

urllib3是一个功能强大且易于使用的Python HTTP库,主要用于发送HTTP请求和处理HTTP响应。它是urllib和urllib2的后续版本,设计用于支持HTTP 1.1标准,并提供了许多高级功能和选项,使得在Python中进行HTTP通信变得更加简单和灵活。

urllib3的主要功能和特点包括:

  1. 支持HTTP和HTTPS协议:urllib3支持HTTP和HTTPS协议的请求,可以方便地发送GET、POST、PUT、DELETE等各种类型的请求。

  2. 自动管理连接池:urllib3提供了高效的连接池管理功能,可以自动管理连接,提高性能和效率。连接池可以重用已经建立的连接,避免了为每个请求都创建新的连接的开销。

  3. 支持连接重用和连接超时设置:urllib3支持连接重用,可以在多个请求之间共享同一个连接。同时,它还支持连接超时设置,可以避免因为连接问题导致的程序挂起。

  4. 支持代理和证书的配置:urllib3支持配置代理服务器和SSL证书,可以方便地通过代理发送请求,并保证请求的安全性。

  5. 提供灵活的请求头和请求体定制:urllib3允许你自定义请求头和请求体,可以方便地设置请求的各种参数,如Content-Type、User-Agent等。

  6. 自动处理重定向和重试:urllib3可以自动处理HTTP重定向,并在遇到某些类型的错误时自动重试请求,提高了请求的可靠性。

  7. 具有良好的线程安全性和并发性:urllib3的连接池是线程安全的,可以在多线程环境中安全使用。同时,它也支持并发请求,可以同时发送多个请求,提高了程序的执行效率。

相比于其他HTTP库,urllib3的主要优势在于它的连接池管理和复用功能,以及对HTTPS请求的良好支持。这使得urllib3成为Python中进行HTTP通信的一个非常优秀的选择。

2.2 安装urllib3

pip install urllib3

2.3 发送网络请求

使用urllib3发送网络请求,首先需要创建PoolManager对象,通过调用request()方法实现网络请求的发送

2.3.1 GET请求

2.3.1.1 PoolManager对象向单个服务器发送请求

示例:

import urllib3

# 创建一个PoolManager实例
http = urllib3.PoolManager()

# 发送GET请求
url = 'http://example.com'
response = http.request('GET', url)

# 检查响应状态
if response.status == 200:
    # 读取响应内容
    print(response.data.decode('utf-8'))
else:
    print(f'请求失败,状态码:{response.status}')

2.3.1.2 PoolManager对象向多个服务器发送请求

示例:

import urllib3

# 创建一个PoolManager实例
http = urllib3.PoolManager()

# 定义多个URL
urls = [
    'http://example.com',
    'http://example.org',
    'http://example.net'
]

# 发送GET请求到每个URL
for url in urls:
    response = http.request('GET', url)

    # 检查响应状态
    if response.status == 200:
        # 读取并打印响应内容
        print(f"URL: {url}, Status: {response.status}, Content: {response.data.decode('utf-8')}")
    else:
        print(f"URL: {url}, Request failed with status: {response.status}")

    # 关闭连接池(可选,urllib3通常会自动管理)
http.clear()

  

2.3.2 Post请求

示例:

# 导入urllib3库  
import urllib3
#导入json模块来处理JSON数据
import json

# 创建一个PoolManager实例,用于管理连接池和处理HTTP请求  
http = urllib3.PoolManager()

# 定义请求的URL  
url = "https://www.httpbin.org/post"

# 定义要发送的数据,这里是一个字典,它将被转换为JSON格式  
data = {
    "name": "suixiang",
    "age": "20",
}

# 将字典数据转换为JSON格式的字符串  
data_json = json.dumps(data)

# 定义请求头,指定内容类型为JSON  
headers = {'Content-Type': 'application/json'}

# 发送POST请求,传入URL、请求头和数据  
# 注意:在urllib3中,发送请求时使用`fields`参数传递表单数据,但在这里我们使用`body`参数传递JSON数据  
response = http.request('POST', url, headers=headers, body=data_json)

# 检查响应状态码,如果是200,则打印响应内容;否则打印错误信息  
if response.status == 200:
    # 响应内容是字节类型,我们使用decode方法将其转换为字符串  
    print(response.data.decode('utf-8'))
else:
    # 打印错误信息和状态码  
    print(f"Error: {response.status} {response.reason}")

2.3.3 重新尝试请求

通过retries参数设置重试请求

示例:

import urllib3
from urllib3.util import Retry

# 定义重试策略  
retries = Retry(
    total=5,  # 总重试次数  
    backoff_factor=0.1,  # 退避因子,用于计算等待时间  
    status_forcelist=[500, 502, 503, 504]  # 在这些状态码下重试  
)

# 创建一个PoolManager实例并设置重试策略  
http = urllib3.PoolManager(retries=retries)

# 定义请求的URL(注意:尽管这是httpbin.org的POST端点,但您可以用GET方法请求它进行测试)  
url = "https://www.httpbin.org/get"


# 发送GET请求
response = http.request('GET', url)

# 检查响应状态码
if response.status == 200:
    # 如果状态码是200,则打印响应内容
    print(response.data.decode('utf-8'))
else:
    # 如果状态码不是200,则打印错误信息
    print(f"Request failed with status code {response.status}: {response.reason}")

2.3.4 处理响应内容

2.3.4.1获取响应头

示例:

import urllib3  # 导入urllib3库  
  
# 创建一个HTTP连接池管理器  
http = urllib3.PoolManager()  
  
# 设置目标URL,这里使用了httpbin.org的服务,一个常用于测试HTTP请求的在线服务  
url = 'http://www.httpbin.org/get'  
  
# 使用连接池管理器发送GET请求  
response = http.request('GET', url)  
  
# 获取响应头信息  
response_header = response.info()  
  
# 遍历响应头的键并打印键和对应的值  
for key in response_header.keys():  
    print(key, ':', response_header.get(key))

2.3.4.2 Json信息

示例:

import urllib3  # 导入urllib3库,用于发送HTTP请求  
import json     # 导入json库,用于处理JSON数据  
  
# 创建一个HTTP连接池管理器  
http = urllib3.PoolManager()  
  
# 设置目标URL,这里使用了httpbin.org的服务,一个常用于测试HTTP请求的在线服务  
url = 'http://www.httpbin.org/post'  
  
# 准备POST请求的参数  
params = {'name':'suixiang','age':'20'}  
  
# 使用连接池管理器发送POST请求,并带上参数  
response = http.request('POST', url, fields=params)  
  
# 将响应的数据从字节串解码为字符串,并将字符串解析为JSON对象  
json_data = json.loads(response.data.decode('utf-8'))  
  
# 打印出JSON对象中的'form'字段,该字段包含了POST请求的参数  
print(json_data.get('form'))

2.3.4.3  二进制信息

示例:

# 导入urllib3库,用于发送HTTP请求
import urllib3

# 创建一个HTTP连接池管理器,用于复用HTTP连接
http = urllib3.PoolManager()

# 设置目标URL,这里指向placehold.it提供的200x200像素PNG图片的URL
url = 'https://placehold.it/200x200.png'

# 使用连接池管理器发送GET请求到指定的URL
response = http.request('GET', url)

# 检查响应状态码,确保请求成功
if response.status == 200:
    # 打开一个文件用于写入,文件名为'200x200.png',模式为二进制写入模式('wb+')
    # 注意:通常使用'wb'(二进制写入)就足够了,'b+'还允许读取,但在这里不是必需的
    file = open('200x200.png', 'wb+')

    # 将响应中的数据(图片内容)写入到文件中
    file.write(response.data)

    # 关闭文件,释放资源
    file.close()

    # 打印成功信息
    print("图片下载成功,并已保存到当前目录下的'200x200.png'文件中。")
else:
    # 如果响应状态码不是200,则打印错误信息
    print(f"请求失败,状态码为:{response.status}")

三、复杂请求发送

3.1 设置请求头

示例:

import urllib3

# 创建一个HTTP连接池对象
http = urllib3.PoolManager()

# 设置URL
url = 'https://www.httpbin.org/post'

# 设置请求头
headers = urllib3.util.make_headers(
    basic_auth='username:password',  # 如果需要基本认证,可以这样设置
    proxy_basic_auth='proxyuser:proxypass',  # 如果需要代理基本认证,可以这样设置
    accept_encoding=False,  # 禁用gzip, deflate等压缩
    user_agent='your-app/0.0.1',  # 设置用户代理
)

# 设置请求体(如果是POST或PUT请求)
body = '{"name": "suixiang", "age": "20"}'


response = http.request('POST', url, headers=headers, body=body)

# 检查响应状态码
if response.status == 200:
    # 请求成功,处理响应内容
    print(response.data.decode('utf-8'))  # 假设响应内容是UTF-8编码的文本
else:
    # 请求失败,处理错误
    print(f"Request failed with status code {response.status}")
    print(response.data.decode('utf-8'))  # 打印错误消息或其他响应内容

3.2 设置超时

urllib3中,你可以通过timeout参数来设置请求的超时时间。timeout参数接受一个浮点数或一个urllib3.Timeout对象,用于指定连接超时和读取超时的时间。

示例:

import urllib3

# 创建一个HTTP连接池对象
http = urllib3.PoolManager()

# 设置URL
url = 'https://www.httpbin.org/post'

# 设置请求头
headers = {
    'Content-Type': 'application/json',
    'Custom-Header': 'CustomValue'
}

# 设置请求体(如果是POST或PUT请求)
body = '{"key1": "value1", "key2": "value2"}'

# 设置超时时间(单位:秒)
timeout = 10.0  # 这里设置10秒的超时时间

# 发送请求
response = http.request('POST', url, headers=headers, body=body, timeout=timeout)

# 检查响应状态码
if response.status == 200:
    # 请求成功,处理响应内容
    print(response.data.decode('utf-8'))
else:
    # 请求失败,处理错误
    print(f"Request failed with status code {response.status}")
    print(response.data.decode('utf-8'))

3.3 设置代理

proxy_url = 'http://your-proxy-host:your-proxy-port'  # 请替换成你的代理地址和端口


proxy_headers = urllib3.make_headers(proxy_basic_auth='your-proxy-username:your-proxy-password')  # 如果需要代理认证,请提供用户名和密码

示例:

import urllib3

# 创建带有代理的PoolManager
proxy_url = 'http://your-proxy-host:your-proxy-port'  # 请替换成你的代理地址和端口
proxy_headers = urllib3.make_headers(proxy_basic_auth='your-proxy-username:your-proxy-password')  # 如果需要代理认证,请提供用户名和密码
proxy_manager = urllib3.ProxyManager(proxy_url, headers=proxy_headers)

# 创建一个HTTP客户端
http = urllib3.PoolManager()

# 要请求的URL
url = 'https://www.httpbin.org/post'

# 准备POST请求的数据
post_fields = {'key1': 'value1', 'key2': 'value2'}  # 这是一个示例,您可以根据需要修改或添加字段

# 使用代理管理器发送POST请求
response = proxy_manager.request('POST', url, fields=post_fields)

# 打印响应内容
print(response.data.decode('utf-8'))

3.4 上传文件

3.4.1 上传文本文件

示例:

import urllib3
import json

# 创建一个连接池管理器实例
http = urllib3.PoolManager()

# 目标URL
url = 'https://www.httpbin.org/post'

# 打开文件并读取内容
with open('text.txt', 'r', encoding='utf-8') as file:
    data = file.read()

    # 设置请求头,指定内容类型为纯文本
    headers = {
        'Content-Type': 'text/plain',
    }

    # 发送带有请求体的POST请求
    response = http.request('POST', url, headers=headers, body=data)

# 将响应的二进制数据解码为UTF-8字符串,并加载为JSON对象
result = json.loads(response.data.decode('utf-8'))

# 打印出整个JSON响应对象
print(result)

3.4.2 上传照片文件

示例:

import urllib3
# 创建一个连接池管理器实例
http = urllib3.PoolManager()

# 目标URL
url = 'https://www.httpbin.org/post'

# 打开图片文件并读取内容
with open('200x200.png', 'rb') as file:
    data = file.read()

# 发送带有请求体的POST请求
response = http.request('POST', url,body=data)

# 打印响应内容
print(response.data.decode())

;