urllib库

urllib库是Python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据。

urlopen函数

在Python3的urllib库中,所有和网络请求相关的方法,都被集中到urllib.request模块下面了。发送请求,需要使用urlopen函数,详解如下:

  1. from urllib import request
  2. # resp = urlopen(url,data=None)
  3. resp = request.urlopen('http://www.baidu.com') # 发送访问百度请求
  4. # 返回值是一个http.client.HTTPResponse对象,这个对象是一个类文件句柄对象。
  5. # 有read(size)(不指定size时,默认全部读取)、readline、readlines以及getcode等方法。
  6. print(resp.read())
  7. print(resp.info()) # 远程服务器返回的头部信息(header)
  8. print(resp.getcode()) # 获取访问状态吗
  9. print(resp.geturl()) # 获取当前访问url

发送GET请求

不提交urlopen的data参数,默认是以get方法请求网页。示例代码:

  1. from urllib import request
  2. resp = request.urlopen('http://www.baidu.com')
  3. print(resp.read())

urlencode函数

用浏览器发送请求的时候,如果url中包含了中文或者其他特殊字符,那么浏览器会自动进行编码。而如果使用代码发送请求,那么就必须手动进行编码,这是需要使用urlencode函数。urlencode可以把字典数据转换为url编码的数据,示例代码:

  1. from urllib import parse # parse是编解码相关模块
  2. data = {'name':'爬虫','greet':'hello','age':100}
  3. qs = parse.urlencode(data)
  4. print(qs)
  5. >> name=%E7%88%AC%E8%99%AB&greet=hello&age=100

案例:百度搜索刘德华

  1. # url = 'http://www.baidu.com/?wd=刘德华' # 浏览器访问的url
  2. # url中有汉字,直接urlopen会报错
  3. url = 'http://www.baidu.com/s' # 不含中文部分url
  4. params = {'wd':'刘德华'} # 查询字符串形式汉字参数
  5. qs = parse.urlencode(params) # urlencode函数编码
  6. url = url + "?" + qs # 组合完整收索url
  7. resp = request.urlopen(url)
  8. print(resp.read())
  9. # url中含有汉字的时候,除了使用字典传参,也可以将带汉字拼接好的url进行转移
  10. url = 'http://www.baidu.com/?wd=刘德华'
  11. new_url = urllib.parse.quote(url,safe=string.printable)
  12. print(new_url)
  13. >> 'http://www.baidu.com/?wd=%E5%88%98%E5%BE%B7%E5%8D%8E'

发送POST请求

  1. from urllib import request,parse
  2. # resp = urlopen(url,data=None)
  3. # 当传递了data参数,将采用post方法向服务器提交data数据
  4. url = "http://httpbin.org/post"
  5. data = {
  6. 'name':'wzy'
  7. }
  8. # data数据首先需要使用urlencode进行编码转换成str类型
  9. # 然后在编码成utf-8格式的bytes类型进行参数传递。
  10. resp = request.urlopen(url,data=parse.urlencode(data).encode('utf-8'))
  11. print(resp.read().decode('utf-8'))

request.Request类

如果想要在请求的时候,增加一些请求头(header),那么就必须要使用request.Request类来实现,比如要增加一个User-Agent。也可以使用request.Request类来发送POST请求,传递data参数,示例代码如下:

  1. from urllib import request,parse
  2. url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
  3. headers = {
  4. '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'
  5. }
  6. data = {
  7. 'first': 'true',
  8. 'pn':1,
  9. 'kd':'python'
  10. }
  11. # 通过request.Request类创建一个请求对象。
  12. req = request.Request(url,headers = headers,data=parse.urlencode(data).encode('utf-8'),method='POST'
  13. # 发送请求对象,还是需要使用urlopen函数。
  14. resp = request.urlopen(req)
  15. print(resp.read())

使用代理

防止网站封锁ip阻止访问,需要设置代理。示例代码:

  1. from urllib import request
  2. # 直接访问,没有使用代理的。
  3. resp = request.urlopen('http://httpbin.org/ip')
  4. # 返回本机实际ip
  5. print(resp.read().decode('utf-8'))
  6. # 使用代理
  7. # 1:创建handler
  8. handler = request.ProxyHandler({'http':'111.177.166.110:9999'}) # 传入的是一个字典
  9. # 使用本机vpn时
  10. # proxy = {
  11. 'http':'127.0.0.1:1080'
  12. 'https':'127.0.0.1:1080'
  13. }
  14. # handler = request.ProxyHandler(proxy)
  15. # 2:创建opener
  16. opener = request.build_opener(handler)
  17. # 3:创建请求
  18. req = request.Request('http://httpbin.org/ip')
  19. # 4:使用opener发送请求
  20. resp = opener.open(req)
  21. # 返回代理的ip
  22. print(resp.read().decode('utf-8'))

发送网络请求的3步走:创建handler→创建opener→使用opener发送请求。urlopen函数相当于底层封装了以上3步骤。

Cookie

Cookie的格式及参数:
  1. Set-Cookie:NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
  2. # NAME:cookie的名字
  3. # VALUE:cookie的值
  4. # Expires:cookie的过期时间
  5. # Path:cookie作用的路径
  6. # Domain:cookie作用的域名
  7. # SECURE:是否只在https协议下起作用

模拟Cookie登陆网站

通过创建opener,用opener发送登陆网站请求,然后再用opener访问其他页面时,会自动携带cookie信息。

手动(粗暴)方式:手动登陆账号

先用浏览器使用账号登陆网站后,访问需要登陆账号的页面,获取浏览器访问当前页面时发送的cookie信息,将这个cookie信息放在header中,发送请求。

自动方式:模拟登陆账号
  1. from urllib import request,parse
  2. from http.cookiejar import CookieJar
  3. headers ={
  4. '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"
  5. }
  6. # 创建opener,使用opener发送多个请求时,将共享cookie信息。
  7. def get_opener():
  8. # 创建cookiejar对象
  9. cookiejar = CookieJar()
  10. # 创建handler
  11. handler = request.HTTPCookieProcessor(cookiejar)
  12. # 创建opener
  13. opener = request.build_opener(handler)
  14. return opener
  15. # 使用opener模拟登陆网站账号
  16. def login_renren(opener):
  17. data = {
  18. 'email':'134****8050',
  19. 'password':'111111'
  20. }
  21. login_url = "http://www.renren.com/PLogin.do"
  22. # 使用request.Request创建请求对象
  23. req = request.Request(login_url,data=parse.urlencode(data).encode('utf-8'),headers=headers)
  24. # 使用opener发送请求
  25. # 发送请求后,登陆网站后的cookie将被记录在opener中
  26. opener.open(req)
  27. # 测试访问需要登陆的页面
  28. def visit_profile(opener):
  29. dapeng_url = "http://www.renren.com/880151247/profile"
  30. req = request.Request(dapeng_url,headers=headers)
  31. # 使用opener发送请求
  32. resp = opener.open(req)
  33. # 保存网页,确认是否可以访问需要登陆的页面
  34. with open('renren.html','w',encoding='utf-8') as fp:
  35. fp.write(resp.read().decode('utf-8'))
  36. if __name__ == '__main__':
  37. opener = get_opener()
  38. login_renren(opener)
  39. visit_profile(opener)

保存cookie到本地

cookie需要多次重复使用的情况,可以把cookie信息保存在本地

  1. from urllib import request
  2. from http.cookiejar import MozillaCookieJar
  3. # 创建cookiejar时,如何传递了文件名,则保存的时候不需要再次传入。
  4. cookiejar = MozillaCookieJar('cookie.txt')
  5. handler = request.HTTPCookieProcessor(cookiejar)
  6. opener = request.build_opener(handler)
  7. resp = opener.open('http://www.baidu.com/')
  8. cookiejar.save()
  9. # 对于关闭浏览器即失效的cookie信息,默认情况是无法保存的。如想保存这种cookie信息,需要在save()函数中传入参数:ignore_discard=True。

读取本地cookie
  1. from urllib import request
  2. from http.cookiejar import MozillaCookieJar
  3. cookiejar = MozillaCookieJar('cookie.txt')
  4. cookiejar.load(ignore_discard=True)
  5. handler = request.HTTPCookieProcessor(cookiejar)
  6. opener = request.build_opener(handler)
  7. resp = opener.open('http://httpbin.org/cookies)
  8. for cookie in cookiejar:
  9. print(cookie)
  10. # 需要读取失效的cookie时,load()函数中需要传入参数:ignore_discard=True。

常用函数

urlretrieve函数

下载网页

  1. from urllib import request
  2. request.urlretrieve('http://www.baidu.com','baidu.html')

下载图片

  1. from urllib import request
  2. request.urlretrieve('https://www.baidu.com/img/bd_logo1.png','baidu.png')

parse_qs函数

可以将编码后的url参数进行解码,与urldecode()函数相反。示例代码:

  1. from urllib import parse
  2. qs = 'name=%E7%88%AC%E8%99%AB&greet=hello&age=100'
  3. print(parse.parse_qs(qs))
  4. >> {'name': ['爬虫'], 'greet': ['hello'], 'age': ['100']}

urlparse和urlsplit

需要对url进行分割时,可以使用urlparse或urlsplit进行分割。示例代码:

  1. from urllib import parse
  2. url = 'http://www.baidu.com/s?username=zhiliao'
  3. result = parse.urlsplit(url)
  4. print('scheme:',result.scheme) # >> scheme: http
  5. print('netloc:',result.netloc) # >> netloc: www.baidu.com
  6. print('path:',result.path) # >> path: /s
  7. 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。使用比较少。