一、认识网络爬虫
1.1 网络爬虫概述
网络爬虫是一种自动化程序,用于按照规则从互联网上抓取信息。它从指定网页开始,读取内容,发现链接,并依次抓取这些链接指向的网页,循环往复,直至抓取完指定网站的所有网页。爬虫常用于搜索引擎、数据挖掘、网站测试和优化等领域。使用爬虫时,需遵守网站的robots.txt协议和法律法规,避免对网站造成过大压力或侵犯他人权益。网络爬虫的出现,极大地提高了人们获取和处理网络信息的效率。
1.2 网络爬虫分类
网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:
- 通用网络爬虫(General Purpose Web Crawler):又称全网爬虫,其爬行对象从一些种子URL扩充到整个Web,主要为门户站点搜索引擎和大型Web服务提供商采集数据。
- 聚焦网络爬虫(Focused Web Crawler):也称主题网络爬虫,是指按照预先定义好的主题有选择地进行网页爬取,爬取特定的资源。
- 增量式网络爬虫(Incremental Web Crawler):指对已下载网页采取增量式更新,只采集新产生的或者已经发生变化网页的爬虫。
- 深层网络爬虫(Deep Web Crawler):即Deep Web爬虫,指对大部分内容不能通过静态链接获取,只有用户提交表单信息才能获取Web页面的爬虫。
1.3 网络爬虫的原理
网络爬虫的原理可以简单地概括为以下几个步骤:
- 发送请求:爬虫首先向目标网站发送请求,请求的内容包括要获取的网页地址(URL)。
- 接收响应:目标网站接收到请求后,会返回一个响应,这个响应的内容就是网页的HTML代码。
- 解析网页:爬虫接收到HTML代码后,需要对其进行解析,提取出需要的数据。解析网页的方式有多种,常见的有正则表达式、XPath、BeautifulSoup等。
- 存储数据:提取出的数据需要进行存储,以便后续的分析和处理。存储的方式也有多种,可以将数据保存在本地文件中,也可以保存到数据库中。
- 循环遍历:爬虫通常会根据网页中的链接,继续向其他网页发送请求,获取数据,直到满足一定的停止条件(比如达到指定的爬取数量、爬取到特定的网页等)。
二、请求模块urlib3
2.1 urllib3的概述
urllib3是一个功能强大且易于使用的Python HTTP库,主要用于发送HTTP请求和处理HTTP响应。它是urllib和urllib2的后续版本,设计用于支持HTTP 1.1标准,并提供了许多高级功能和选项,使得在Python中进行HTTP通信变得更加简单和灵活。
urllib3的主要功能和特点包括:
-
支持HTTP和HTTPS协议:urllib3支持HTTP和HTTPS协议的请求,可以方便地发送GET、POST、PUT、DELETE等各种类型的请求。
-
自动管理连接池:urllib3提供了高效的连接池管理功能,可以自动管理连接,提高性能和效率。连接池可以重用已经建立的连接,避免了为每个请求都创建新的连接的开销。
-
支持连接重用和连接超时设置:urllib3支持连接重用,可以在多个请求之间共享同一个连接。同时,它还支持连接超时设置,可以避免因为连接问题导致的程序挂起。
-
支持代理和证书的配置:urllib3支持配置代理服务器和SSL证书,可以方便地通过代理发送请求,并保证请求的安全性。
-
提供灵活的请求头和请求体定制:urllib3允许你自定义请求头和请求体,可以方便地设置请求的各种参数,如Content-Type、User-Agent等。
-
自动处理重定向和重试:urllib3可以自动处理HTTP重定向,并在遇到某些类型的错误时自动重试请求,提高了请求的可靠性。
-
具有良好的线程安全性和并发性: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())