urllib库
urllib库是Python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据。
urlopen函数
在Python3的urllib库中,所有和网络请求相关的方法,都被集中到urllib.request模块下面了。发送请求,需要使用urlopen函数,详解如下:
from urllib import request
# resp = urlopen(url,data=None)
resp = request.urlopen('http://www.baidu.com') # 发送访问百度请求
# 返回值是一个http.client.HTTPResponse对象,这个对象是一个类文件句柄对象。
# 有read(size)(不指定size时,默认全部读取)、readline、readlines以及getcode等方法。
print(resp.read())
print(resp.info()) # 远程服务器返回的头部信息(header)
print(resp.getcode()) # 获取访问状态吗
print(resp.geturl()) # 获取当前访问url
发送GET请求
不提交urlopen的data参数,默认是以get方法请求网页。示例代码:
from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read())
urlencode函数
用浏览器发送请求的时候,如果url中包含了中文或者其他特殊字符,那么浏览器会自动进行编码。而如果使用代码发送请求,那么就必须手动进行编码,这是需要使用urlencode函数。urlencode可以把字典数据转换为url编码的数据,示例代码:
from urllib import parse # parse是编解码相关模块
data = {'name':'爬虫','greet':'hello','age':100}
qs = parse.urlencode(data)
print(qs)
>> name=%E7%88%AC%E8%99%AB&greet=hello&age=100
案例:百度搜索刘德华
# url = 'http://www.baidu.com/?wd=刘德华' # 浏览器访问的url
# url中有汉字,直接urlopen会报错
url = 'http://www.baidu.com/s' # 不含中文部分url
params = {'wd':'刘德华'} # 查询字符串形式汉字参数
qs = parse.urlencode(params) # urlencode函数编码
url = url + "?" + qs # 组合完整收索url
resp = request.urlopen(url)
print(resp.read())
# url中含有汉字的时候,除了使用字典传参,也可以将带汉字拼接好的url进行转移
url = 'http://www.baidu.com/?wd=刘德华'
new_url = urllib.parse.quote(url,safe=string.printable)
print(new_url)
>> 'http://www.baidu.com/?wd=%E5%88%98%E5%BE%B7%E5%8D%8E'
发送POST请求
from urllib import request,parse
# resp = urlopen(url,data=None)
# 当传递了data参数,将采用post方法向服务器提交data数据
url = "http://httpbin.org/post"
data = {
'name':'wzy'
}
# data数据首先需要使用urlencode进行编码转换成str类型
# 然后在编码成utf-8格式的bytes类型进行参数传递。
resp = request.urlopen(url,data=parse.urlencode(data).encode('utf-8'))
print(resp.read().decode('utf-8'))
request.Request类
如果想要在请求的时候,增加一些请求头(header),那么就必须要使用request.Request类来实现,比如要增加一个User-Agent
。也可以使用request.Request类来发送POST
请求,传递data
参数,示例代码如下:
from urllib import request,parse
url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
}
data = {
'first': 'true',
'pn':1,
'kd':'python'
}
# 通过request.Request类创建一个请求对象。
req = request.Request(url,headers = headers,data=parse.urlencode(data).encode('utf-8'),method='POST'
# 发送请求对象,还是需要使用urlopen函数。
resp = request.urlopen(req)
print(resp.read())
使用代理
防止网站封锁ip阻止访问,需要设置代理。示例代码:
from urllib import request
# 直接访问,没有使用代理的。
resp = request.urlopen('http://httpbin.org/ip')
# 返回本机实际ip
print(resp.read().decode('utf-8'))
# 使用代理
# 1:创建handler
handler = request.ProxyHandler({'http':'111.177.166.110:9999'}) # 传入的是一个字典
# 使用本机vpn时
# proxy = {
'http':'127.0.0.1:1080',
'https':'127.0.0.1:1080'
}
# handler = request.ProxyHandler(proxy)
# 2:创建opener
opener = request.build_opener(handler)
# 3:创建请求
req = request.Request('http://httpbin.org/ip')
# 4:使用opener发送请求
resp = opener.open(req)
# 返回代理的ip
print(resp.read().decode('utf-8'))
发送网络请求的3步走:创建handler→创建opener→使用opener发送请求。urlopen函数相当于底层封装了以上3步骤。
Cookie
Cookie的格式及参数:
Set-Cookie:NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
# NAME:cookie的名字
# VALUE:cookie的值
# Expires:cookie的过期时间
# Path:cookie作用的路径
# Domain:cookie作用的域名
# SECURE:是否只在https协议下起作用
模拟Cookie登陆网站
通过创建opener,用opener发送登陆网站请求,然后再用opener访问其他页面时,会自动携带cookie信息。
手动(粗暴)方式:手动登陆账号
先用浏览器使用账号登陆网站后,访问需要登陆账号的页面,获取浏览器访问当前页面时发送的cookie信息,将这个cookie信息放在header中,发送请求。
自动方式:模拟登陆账号
from urllib import request,parse
from http.cookiejar import CookieJar
headers ={
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36"
}
# 创建opener,使用opener发送多个请求时,将共享cookie信息。
def get_opener():
# 创建cookiejar对象
cookiejar = CookieJar()
# 创建handler
handler = request.HTTPCookieProcessor(cookiejar)
# 创建opener
opener = request.build_opener(handler)
return opener
# 使用opener模拟登陆网站账号
def login_renren(opener):
data = {
'email':'134****8050',
'password':'111111'
}
login_url = "http://www.renren.com/PLogin.do"
# 使用request.Request创建请求对象
req = request.Request(login_url,data=parse.urlencode(data).encode('utf-8'),headers=headers)
# 使用opener发送请求
# 发送请求后,登陆网站后的cookie将被记录在opener中
opener.open(req)
# 测试访问需要登陆的页面
def visit_profile(opener):
dapeng_url = "http://www.renren.com/880151247/profile"
req = request.Request(dapeng_url,headers=headers)
# 使用opener发送请求
resp = opener.open(req)
# 保存网页,确认是否可以访问需要登陆的页面
with open('renren.html','w',encoding='utf-8') as fp:
fp.write(resp.read().decode('utf-8'))
if __name__ == '__main__':
opener = get_opener()
login_renren(opener)
visit_profile(opener)
保存cookie到本地
cookie需要多次重复使用的情况,可以把cookie信息保存在本地
from urllib import request
from http.cookiejar import MozillaCookieJar
# 创建cookiejar时,如何传递了文件名,则保存的时候不需要再次传入。
cookiejar = MozillaCookieJar('cookie.txt')
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)
resp = opener.open('http://www.baidu.com/')
cookiejar.save()
# 对于关闭浏览器即失效的cookie信息,默认情况是无法保存的。如想保存这种cookie信息,需要在save()函数中传入参数:ignore_discard=True。
读取本地cookie
from urllib import request
from http.cookiejar import MozillaCookieJar
cookiejar = MozillaCookieJar('cookie.txt')
cookiejar.load(ignore_discard=True)
handler = request.HTTPCookieProcessor(cookiejar)
opener = request.build_opener(handler)
resp = opener.open('http://httpbin.org/cookies)
for cookie in cookiejar:
print(cookie)
# 需要读取失效的cookie时,load()函数中需要传入参数:ignore_discard=True。
常用函数
urlretrieve函数
下载网页
from urllib import request
request.urlretrieve('http://www.baidu.com','baidu.html')
下载图片
from urllib import request
request.urlretrieve('https://www.baidu.com/img/bd_logo1.png','baidu.png')
parse_qs函数
可以将编码后的url参数进行解码,与urldecode()函数相反。示例代码:
from urllib import parse
qs = 'name=%E7%88%AC%E8%99%AB&greet=hello&age=100'
print(parse.parse_qs(qs))
>> {'name': ['爬虫'], 'greet': ['hello'], 'age': ['100']}
urlparse和urlsplit
需要对url进行分割时,可以使用urlparse或urlsplit进行分割。示例代码:
from urllib import parse
url = 'http://www.baidu.com/s?username=zhiliao'
result = parse.urlsplit(url)
print('scheme:',result.scheme) # >> scheme: http
print('netloc:',result.netloc) # >> netloc: www.baidu.com
print('path:',result.path) # >> path: /s
print('query:',result.query) # >> query: username=zhiliao
urlparse和urlsplit基本一致,urlparse分割url后,多一个params属性。比如url = 'http://www.baidu.com/s;hello?wd=python&username=abc#1'
,获取分号后面的hello,就需要使用到urlparse。使用比较少。