urllib库 HTTP请求库

urllib 是一个用来处理网络请求的python标准库,它包含4个模块。
 urllib.requests 请求模块,用于发起网络请求
 urllib.parse 解析模块,用于解析URL
 urllib.error 异常处理模块,用于处理request引起的异常
 urllib.robotparse 用于解析robots.txt文件

一. request模块

1.urlopen方法 最基本的发送请求的方法,不支持添加请求头部

第一个参数时url 第二个参数时data 第三个参数是超时时间 !没有请求头headers参数

 import re
 import json
 import urllib3
 from urllib import request
 
 
 url = "http://httpbin.org/post"
 resp = request.urlopen(url=url, data=b"name=YeLan&age=20")
 print(resp.read().decode())    # 读取响应返回的数据,并且响应的数据只能读取一次
 print(readline()) # 读取一行,可以用循环读取全部
 print(resp.info())      # 获取响应头信息
 print(resp.geturl())    # 获取访问的url
 print(resp.getcode())   # 返回状态码
 
 # urlopen默认会发送get请求,当传入data参数时,则会发起POST请求。data参数是字节类型、类文件对象或可迭代对象。
 # data参数传输的是bytes类型的数据(一般以键值对的形式),以form表单的形式返回
 

 

Request对象

urlopen()方法不能添加请求头的参数headers因此需要更强大的Request对象

1.请求头添加

通过urllib发送的请求会有一个默认的Headers: “User-Agent”:“Python-urllib/3.6”,指明请求是由urllib发送的。所以遇到一些验证User-Agent的网站时,需要我们自定义Headers把自己伪装起来。

 from urllib import request
 
 
 url = 'http://www.jianshu.com'
 headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
 Chrome/73.0.3683.86 Safari/537.36",
     "User-Agent": "Python-urllib/3.6" 默认的UA
 }
 referer = {"Referer": "http://httpbin.org"}
 # 如果请求头需要携带referer、content-type等,只需要将其更新至请求头即可
 headers.update(referer)
 
 req = request.Request(url, headers=headers) # 实例
 resp = request.urlopen(req) # 这里的urlopen() 接收一个Request对象也是可以的
 

 

Handler不同子类处理不同的需求

ProxyHandler 用于设置代理,默认代理为空

HTTPCookieProcessor 用于处理cookies

HTTPRedirectHandler 用于处理重定向

HTTPBasicAuthHandler 用于管理认证,若一个连接打开时需要认证,那么可以用他来解决认证问题

 

2.cookie操作

urlopen() 不支持代理、Cookie、https认证(auth); 因此我们需要借助底层的 Handler 处理器对象

 from urllib import request
 from http import cookiejar
 
 # 1.创建一个cookie对象
 cookie = cookiejar.CookieJar()
 
 # 2.创建一个cookie处理器
 handler = request.HTTPCookieProcessor(cookie)
 
 # 3.创建Opener对象, 将handler绑定到该对象
 opener = request.build_opener(handler)
 
 # 4.使用这个opener来发送请求(其实就是携带cookie)
 url = 'http://www.baidu.com'
 resp = opener.open(url)
 print(resp.info()) # 第一次请求时返回的响应头包含set-cookie
 resp = opener.open(url)
 print(resp.info()) # 第二次请求时返回的响应头不包含set-cookie;因为第二次请求时已经绑定了上一次请求的cookie了, 相当于浏览器已经认识你了
 
 resp = urlopen(url) # 而用urlopen()无论请求多少次,每次响应的头部都会有set-cookie,说明每次请求都没有携带上次的cookie
 print(resp.info) # 与opener.open()方法对比
3.设置代理

理解: 原理其实都是通过opener的open()方法发起请求

 from urllib.error import URLError
 
 url = 'http://httpbin.org/ip'
 # print(request.urlopen(url).read().decode()) # 该测试网址可以返回我们本机的网址
 # {"origin": "123.169.20.111, 123.169.20.111"}
 
 # 1.代理地址
 proxy = {
     'http': '221.6.32.206:41816',
     'https': '221.6.32.206:41816'
 }
 # 2.创建代理处理器
 proxy_handler = request.ProxyHandler(proxy)
 # 3.创建opener对象 # 实质都是通过opener发起请求
 opener = request.build_opener(proxies)
 # 4.发送请求(如果代理ip被封,请求会出现异常)
 try:
     resp = opener.open(url)
     print(resp.read().decode()) # 返回代理ip
 except URLError as e:
  print('请求错误的原因:%s' % e.reason)
 

 

二、parse模块

parse模块是一个工具模块,提供了需要对url处理的方法,用于解析url。

parse模块常用方法: quote unquote urlencode parse_qs

url中只能包含ascii字符,在实际操作过程中,get请求通过url传递的参数中会有大量的特殊字符,例如汉字,那么就需要进行url编码。

 from urllib import parse, error, robotparser
 
 result = parse.quote("ie=UTF-8&wd=爬虫") # quote()只接受str类型 将url进行编码
 print(result)
 print(parse.unquote("%E7%88%AC%E8%99%AB")) # unquote 对url进行解码(反编码)
 
 params = {
     "wd": "爬虫",
     "username": "YeLan"
 }
 url = "https://www.baidu.com/s?"
 print(url + parse.urlencode(params)) # urlencode()接受字典;对url[url参数]进行编码
 param = parse.urlencode(params)
 print(parse.parse_qs(param)) # parse_qs()接收字典; 对url进行解码
 print(parse.parse_qs('wd=%E7%88%AC%E8%99%AB'))
 
url = urljoin('https:', '//ke.qq.com/course') # 该方法用来拼接url
===> url = "https://ke.qq.com/course"

三、urllib.error模块

error模块主要负责处理异常,如果请求出现错误,我们可以用error模块进行处理

主要包含URLError和HTTPError

 URLError:是error异常模块的基类,由request模块产生的异常都可以用这个类来处理
 该异常常用属性: reason 错误的原因
 
 HTTPError:是URLError的子类,主要包含三个属性:
 Code:请求的状态码
 reason:错误的原因
 headers:响应的报头
 

 

四、urllib.robotparse模块

该模块的 RobotFileparser(url='www.baidu.com/robot.txt')用来解析robot文件(了解就行)

 Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots Exclusion Protocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
 
 https://www.baidu.com/robots.txt
 https://www.taobao.com/robots.txt
 
 robots.txt文件是一个文本文件, robots.txt是一个协议,而不是一个命令.

 

urllib3 第三方HTTP库

安装: pip install urllib3

urllib3.disable_warnings() 禁用警告信息

一、基本使用

import urllib3

url = 'http://image.baidu.com'
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/73.0.3683.86 Safari/537.36",
    "Referer":"https://www.baidu.com"
} 

# 实例一个PoolManager对象构造请求。该对象处理了连接池和线程安全的所有细节,所以我们不用自行处理
http = urllib3.PoolManager()		

# 1. 发送get请求
resp = http.request('GET', url, headers=headers)
print(resp.data.decode("utf-8"))	# 解码为文本html
# 响应属性
print(resp.data)			# 返回的是二进制数据
print(resp.status)			# 响应状态码
print(resp.headers)			# 响应头

print(resp.getheaders())	# 方法:获取响应头部信息
print(resp.info())			# 方法:响应头部信息

# 2. 发送post请求
form_data = {
    'username': 'yelan',
    'password': 'wwxxxx'
}
resp = http.request('post', 'http://httpbin.org/post', fields=form_data)	# fields参数就是post请求提交的数据(form表单)

# 3. 大文件下载	# 修改可选参数preload_content=False 以流的形式下载
http = urllib3.PoolManager(headers=headers)		# 创建该对象时,就指定headers后续请求都会携带请求头
resp = http.request('get', http://httpbin.org/bytes/102400, preload_content=False)
for chunk in resp.stream(128):		# 每次读取128字节
	print(chunk)
    
# 4. 文件上传(注意上传文件是二进制数据,使用body参数接收,与提交数据区分)
with open(r"../img/img_1.jpg","rb") as fb:
    binary_data = fb.read()
    
headers.update({'Content-Type':'image/jpeg'})	# 上传文件|携带json等需要指定类型
response = http.request("POST", 'http://httpbin.org/post', body=binary_data, headers=headers)
print(json.loads(response.data.decode("utf-8")))

 

request参数:
method: <str> 请求方法
url:	<str> 请求url
headers	<dict> 请求头
fields	<dict> 发送get请求时该参数就是url的参数, 而当发送post请求时,该参数就是提交的数据(如form表单)
body	<bytes> 发送post请求携带的二进制数据;如请求时携带json数据或者上传文件。
preload_content	<bool>	默认为True, 修改为False时以流的形式接收数据。

 

import urllib3

# 若我们会发送多个请求,那么给每个请求都去写headers=headers这样太重复了;所以可以在创建该对象时,就指定headers,则后续请求都会携带请求头。
http = urllib3.PoolManager(headers=headers)	

# 1.如果我们GET请求要发送URL参数, 那么怎么发送呢? 那么给fields参数传入包含了URL参数数据的字典即可.
resp = http.request("GET", url="https://httpbin.org/get", fields={"name": "jack", "age": "18"})
print(resp.data.decode())

# 2.若POST请求也要携带URL参数, 怎么办呢? 也是fields? 不是!要通过构造URL才发送URL参数.而fields参数是以字典的形式携带的表单数据
url = "https://httpbin.org/post?name=jack&age=18"
resp = http.request("POST", url=url, fields=form_data)
print(resp.data.decode())       		# str类型的键值对即json数据类型
print(json.loads(resp.data.decode()))   # json转python字典

 

http代理
url = 'http://httpbin.org/get'
pro_host = "http://221.6.32.206:41816"
# 1. 创建一个代理对象
proxy = urllib3.ProxyManager(proxy_url=pro_host, headers=headers, proxy_headers=None)
# 2. 基于该代理对象发送请求
resp = proxy.request("get", url=url, headers=headers)
print(resp.data.decode())

 

对于post和put请求,如果需要查询参数,需要通过url编码将参数编码成正确格式然后拼接到url中
import urllib3
from urllib import parse

args = {
    "user": "YeLan",
    "key": "value",
}
form_data = {
    "user": "yelan",
    "pwd": "123456"
}
args_encoded = parse.urlencode(args)
url = 'http://httpbin.org/post?' + args_encoded
http = urllib3.PoolManager(headers=headers)

resp = http.request("POST", url)
print(json.loads(resp.data.decode())["args"])   # 返回的字典是无序的

# Form data :对于put和post请求,需要提供字典类型的参数field来传递form表单数据。
resp = http.request("POST", url=url, fields=form_data)
print(json.loads(resp.data.decode())["form"])

 

请求时携带json数据; 通过body参数携带二进制的json数据,并指定请求头的content_type
data = {
    "user":"YeLan",
    "key":"value",
    "age":"22"
}
json_data_encoded = json.dumps(data).encode("utf-8") # 将dict转化为json数据再编码
content_type = {
    'Content-Type': 'application/json'
}
headers = header.update(content_type)     # 更新头部信息

# JSON 当我们需要发送json数据时,我们需要在request中传入编码后的二进制数据类型的body参数,并指定Content—Type的请求头
url = "http://httpbin.org/post"
http = urllib3.PoolManager()
resp = http.request("POST", url=url, body=json_data_encoded, headers=headers)
print(json.loads(resp.data.decode()))

 

 

爬虫开发流程

1.找到目标数据
2.分析请求流程
3.构造http请求
4.提取清洗数据
5.数据持久化