urllib是python中请求url链接的标准库,主要包含以下几个模块
- urllib.request:用于打开和阅读URL
- urllib.error:包含由引发的异常urllib.request
- urllib.parse:用于解析URL
- urllib.robotparser:用于解析robot.txt文件
urllib.request.urlopen()
- 模块定义了有助于在复杂环境中打开URL(主要是HTTP)的函数和类-基本身份验证和摘要身份验证,重构定向,Cookie等。
- 语法结构
urllib.request.urlopen(url,data = None,[ timeout,] *,cafile = None,capath = None,cadefault = False,context = None)
- 语法详解
- url:传入的对象可以是url也可以是一个request的对象
#传入的对象是url # 设置一个url对象 url = "www.baidu.com" #发送请求,打开url urllib.request.urlopen(url) ``` ```puthon #传入的对象是request url = "www.baidu.com" #将url对象转换成request对象 req = urllib.request.Request(url) #发送请求,打开url urllib.request.urlopen(url)
- data:data必须是一个直接要发送搭服务器的其他数据的对象,如果没有data数据的话可以为None,也可以不写
- timeout:以秒为单位制定用于组织链接尝试之类的操作超时
- urllib.openurl:返回对象的方法
# 设置一个url对象 url = "www.baidu.com" #发送请求,打开url up = urllib.request.urlopen(url) print(type(up)) #返回对象 >>> <class 'http.client.HTTPResponse'>
上面我们可以看出返回的对象是HTTPResponse类型的,那我们就一起来看一下HTTPResponse类的方法
- HTTPResponse.read():读取并返回响应主体
- HTTPResponse.readinto(b ):将响应主体的下一个len(b)字节读取到缓冲区b中。返回读取的字节数。
- HTTPResponse.getheader(name,default = None ):返回标头名称的值;如果没有标头匹配名称,则返回默认值。如果有一个以上的标题名为名称,返回全部由加盟值“”。如果'default'是除单个字符串之外的任何可迭代对象,则类似地返回其元素并以逗号连接。
- HTTPResponse.getheaders():返回(头,值)元组的列表。
- HTTPResponse.fileno():返回fileno基础套接字的。
- HTTPResponse.status :服务器返回的状态码。
- HTTPResponse.closed():是True流是否关闭。
- info():返回返回HTTPMessage对象,表示远程服务器返回的头信息
- getcode():返回Http状态码。如果是http请求,200请求成功完成 ; 404网址未找到,与HTTPResponse.status功能一样
- geturl():返回请求的url
- 发送GET请求:
from urllib import request response = request.urlopen('https://www.baidu.com') print(response.read().decode())
- 发送post请求
from urllib import reuqest response = request.urlopen('http://httpbin.org/post', data=b'word=hello') print(response.read().decode()) #decode()解码
- 我们已经知道在讲urlopen中传入一个网址的时候他就会主动的去访问目标的网址,会返回一个HTTPResponse类型的对象,那么我们是怎么知道我们发送的get请求和post请求呢?下面我们一起来看一下
def get_method(self): """Return a string indicating the HTTP request method.""" default_method = "POST" if self.data is not None else "GET" return getattr(self, 'method', default_method)
- 这个是源码中的一个方法,根据代码我们得知如果data是不为空的话,就是post请求,否则就是get请求
- urllib.request.Request
- 上面的urllib是可对网页发起请求,在我们实际的爬虫应用中,如果频繁的访问一个网页,网站就会识别我们是不是爬虫,这个时候我们就要利用Request来伪装我们的请求头
urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
参数 解析 url 发起请求的url data data必须是一个直接要发送搭服务器的其他数据的对象,如果没有data数据的话可以为None,也可以不写 headers headers是一个字典类型,是请求头。可以在构造请求时通过headers参数直接构造,也可以通过调用请求实例的add_header()方法添加。可以通过请求头伪装浏览器,默认User-Agent是Python-urllib。要伪装火狐浏览器,可以设置User-Agent为Mozilla/5.0 (x11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11 origin_req_host 指定请求方的host名称或者ip地址 unverifiable 设置网页是否需要验证,默认是False,这个参数一般也不用设置。 method method是一个字符串,用来指定请求使用的方法,比如GET,POST和PUT等。 - 案例:静态添加请求头
#创建一个url
url = "www.baidu.com"
#创建一个请求头
headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"
}
#利用request.Request返回一个request对象
requ = request.Request(url,headers=header)
#向网站发出请求
res = request.urlopen(requ)
- 案例:动态添加请求头
#创建一个url
url = "www.baidu.com"
#利用request.Request返回一个request对象
requ = request.Request(url)
#利用add_header方法动态加入请求头
requ.add_header("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36")
res = request.urlopen(requ)
代理的使用:proxyHandle类
最常见的反扒技术之一就是通过客户端的IP来判断是否是爬虫,如果同一个IP在短时间内大量的访问服务器的不同界面,那么极有可能是爬虫,如果服务器认为是爬虫那么就会将IP封禁,这样爬虫就无法访问服务器的任何资源了
在urlopen()中并没有给我们定义设置ip的参数,我们观察urlopen的源码可以发现这个urlopen的方法体实际返回的是一个opener.open()
global _opener
if cafile or capath or cadefault:
import warnings
warnings.warn("cafile, capath and cadefault are deprecated, use a "
"custom context instead.", DeprecationWarning, 2)
if context is not None:
raise ValueError(
"You can't pass both context and any of cafile, capath, and "
"cadefault"
)
if not _have_ssl:
raise ValueError('SSL support not available')
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH,
cafile=cafile,
capath=capath)
https_handler = HTTPSHandler(context=context)
opener = build_opener(https_handler)
elif context:
https_handler = HTTPSHandler(context=context)
opener = build_opener(https_handler)
elif _opener is None:
_opener = opener = build_opener()
else:
opener = _opener
return opener.open(url, data, timeout)
观察上面的源码发现opener对象是由bulid_opener()创建的,而bulid_opener里面的参数是HTTPSHandler类型,那我们就可以得知open()对象是传入HTTPHandler类型构建出来的,那么我们也可以构建自己的opener,下面我们来详细看一下是怎么样构建可以加入ip的opener,创建加入ip的opener我们需要用到ProxyHandler()
#创建一个链接
url = "https://space.bilibili.com/"
#创建一个代理
proxy = {
"HTTP":"124.239.216.14:2060"
}
# 创建一个代理的处理器
proxy_handler = request.ProxyHandler(proxy)
#创建自己的opener
opener = request.build_opener(proxy_handler)
#使用我们自己的opener来请求网址
w = opener.open(url).read().decode("utf-8")
Cookie
我们再爬虫的过程中会碰到有登录的问题,那么cookie就是网站为了辨别用户身份,进行session跟踪而储存在用户本地终端上的数据,有些网站是必须登录之后才能爬取页面,那么我们就能运用我们的urlib库保存我们登录的cookie,然后再住区其他页面就达到目的了,接下来我们来看一下我们是怎么样利用cookie来发送请求的
from urllib import request,parse
from http import cookiejar
#创建一个方法登录药智网
def login_Yaozhi(username,pwd):
# 创建一个网址
url = "https://www.yaozh.com/login/"
# 创建一个请求头
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"
}
# 创建登录的cookie
cookie = {
"username": username,
"pwd" : pwd,
"formhash" : "35D0E251E2",
"backurl" : "https%3A%2F%2Fwww.yaozh.com%2F"
}
cook_str = parse.urlencode(cookie).encode("utf-8")
#创建cookjar
cook_cookiejar = cookiejar.CookieJar()
#创建一个cookie的处理器
cook_hander = request.HTTPCookieProcessor(cook_cookiejar)
#根据处理器生成opener
cook_opener = request.build_opener(cook_hander)
# 创建一个接受请求头的Request对下个
header_request = request.Request(url, headers=header,data=cook_str)
#利用opener向网站发起请求,如果请求成功就保存cookie
cook_opener.open(header_request,)
#带着cookie访问登录成功的页面
url_suss = "https://www.yaozh.com/"
#创建一个访问成功链接的reque
request_suss = request.Request(url_suss,headers=header)
#向成功的页面发起请求
result_suss = cook_opener.open(request_suss)
#将请求到的数据进行转码
decode_result_suss = result_suss.read().decode("utf-8")
with open("login_suss.html","w",encoding="utf-8")as f:
f.write(decode_result_suss)
if __name__ == '__main__':
#让用户输入账号
username = input("请输入账号:")
#让用户输入密码
pwd = input("请输入密码:")
#调用函数
login_Yaozhi(username,pwd)