urllib模块

一、urllib介绍

  urllib是python中自带的一个基于爬虫的模块,

  作用:urllib 模块是一个高级的 web 交流库,其核心功能就是模仿web浏览器等客户端,去请求相应的资源,并返回一个类文件对象。可以使用代码模拟浏览器发起请求

  详见官网资料:2.7.5:urllib — Open arbitrary resources by URL

         3.7.1:urllib — URL handling modules

1、包含模块

  urllib模块包括以下子模块:
  (1)urllib.request 请求模块
  (2)urllib.error 异常处理模块
  (3)urllib.parse url解析模块
  (4)urllib.robotparser robots.txt解析模块

  其中最常用的两个子模块是:request、parse。

2、使用流程

  (1)指定url

  (2)发起请求:针对指定的url发起一个请求

  (3)获取页面数据:获取服务器响应回来的页面数据

  (4)持久化存储

二、urllib使用示例

1、需求:爬取搜狗首页的页面数据(ssl证书报错)

import urllib.request
import ssl
import os

ssl._create_default_https_context = ssl._create_unverified_context

# 1.指定url
url = "https://www.sogou.com/"

# 2.发起请求:urlopen()可以根据指定的url发起请求,且发回一个响应对象
# 出现报错:urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)>
response = urllib.request.urlopen(url=url)

# 3.获取页面数据:read函数返回的就是响应对象中存储的数据
page_text = response.read()

# 4.持久化存储
# print(page_text)
file_path = os.path.join('first_Jupyter', "sougou.html")
with open(file_path, "wb") as fp:
    fp.write(page_text)
    print("写入数据成功")

注意:

(1)引入ssl解决urllib.urlopen报错

  不添加ssl执行会报错,SSL: CERTIFICATE_VERIFY_FAILED。Python 升级到 2.7.9 之后引入了一个新特性,当使用urllib.urlopen打开一个 https 链接时,会验证一次 SSL 证书。而当目标网站使用的是自签名的证书时就会抛出此异常。

  解决方案有如下两种

# 1)使用ssl创建未经验证的上下文,在urlopen中传入上下文参数
import ssl

context = ssl._create_unverified_context()
webPage = urllib.request.urlopen(req,context=context)

# 2)全局取消证书验证
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

  另外,如果用的是requests模块的get方法,里面有一个verify参数,将其设成False就可以了。

(2)持久化存储将爬取的html数据保存在sougou.html中

  

  浏览器打开显示效果如下:

  

2、需求:爬取指定词条所对应的页面数据(涉及url编码处理)

import urllib.request
import urllib.parse
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

# 指定url
# url = "https://www.sogou.com/web?query=人民币"
url = 'https://www.sogou.com/web?query='

# url特性:url不可以存在非ASCII编码的字符数据
word = urllib.parse.quote("人民币")   # 用quote对非ascii的字符进行转码
url += word   # 转码结果再拼接出有效的url

# 发请求
response = urllib.request.urlopen(url=url)

# 获取页面数据
page_text = response.read()

with open('renminbi.html','wb') as fp:
    fp.write(page_text)

注意:

(1)url编码处理

  url特性:url不可以存在非ASCII编码的字符数据。如果存在则该url无效。如果对其发起请求,则会报如下错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 15-17: ordinal not in range

  所以必须对url中的非ascii的数据进行ascii的编码,则该url方可被发起请求。

  解决方法如下所示:

# 指定url
# url = "https://www.sogou.com/web?query=人民币"
url = 'https://www.sogou.com/web?query='

# url特性:url不可以存在非ASCII编码的字符数据
word = urllib.parse.quote("人民币")   # 用quote对非ascii的字符进行转码
url += word   # 转码结果再拼接出有效的url

(2)打开renminbi.html文件显示如下

  

3、反爬机制

  网站检查请求的UA,如果发现UA是爬虫程序,则拒绝提供网站数据。

  User-Agent参数,简称UA:当前请求所对应的请求载体的身份标识

  如果我们通过浏览器发起的请求,则该请求的载体为当前浏览器,则UA参数的值表明的是当前浏览器的身份标识表示的一串数据。如果我们使用爬虫程序发起的一个请求,则该请求的载体为爬虫程序,那么该请求的UA为爬虫程序的身份标识表示的一串数据。有些网站会通过辨别请求的UA来判别该请求的载体是否为爬虫程序,如果为爬虫程序,则不会给该请求返回响应,那么我们的爬虫程序则也无法通过请求爬取到该网站中的数据值,这也是反爬虫的一种初级技术手段。那么为了防止该问题的出现,则我们可以给爬虫程序的UA进行伪装,伪装成某款浏览器的身份标识。

(1)Network(当前浏览器的抓包工具)

  该工具用于抓取当前浏览器发起的任意请求。

  查看某一个请求的user-agent请求头信息所对应的键值数据(代表了当前请求载体的身份标识):

  

(2)Network抓包工具选项卡

  Headers选项卡包含了Response Headers(响应头信息)、Request Headers(本次请求携带的请求头信息)。  

  Response选项卡包含了服务器端响应给客户端的一些页面数据。

4、反反爬机制(ua身份伪装)

  将爬虫程序请求的UA伪装为任意一款浏览器的UA。

  上述案例中,我们是通过request模块中的urlopen发起的请求,该请求对象为urllib中内置的默认请求对象,我们无法对其进行UA进行更改操作。urllib还为我们提供了一种自定义请求对象的方式,我们可以通过自定义请求对象的方式,给该请求对象中的UA进行伪装(更改)操作。  

(1)自定义请求对象实现UA伪装

import urllib.request

url = 'https://www.baidu.com/'

# UA伪装
# 1.自制定一个请求对象
headers = {
    # 自定制请求头:存储任意的请求头信息
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36'
}

# 该请求对象的UA进行了成功的伪装
# Request()会返回一个自制定的请求对象,url指定url,headers表示自定制请求头信息
request = urllib.request.Request(url=url,headers=headers)

# 2.针对自制定的请求对象发起请求
response = urllib.request.urlopen(request)

print(response.read())

(2)封装自定义的请求头信息的字典

  将浏览器的UA数据获取,封装到一个字典中。该UA值可以通过抓包工具或者浏览器自带的开发者工具中获取某请求,从中获取UA的值。

  headers字典中可以封装任意的请求头信息

三、urlib模块发起的POST请求(带参数)

1、需求:爬取百度翻译的翻译结果

import urllib.request
import urllib.parse

# 1.指定url
url = 'https://fanyi.baidu.com/sug'

# post请求携带的参数进行处理  流程:
# (1)将post请求参数封装到字典
data = {
    'kw':'西瓜'
}
# (2)使用parse模块中的urlencode(返回值类型为str)进行编码处理
data = urllib.parse.urlencode(data)
# (3)将步骤2的编码结果转换成byte类型
data = data.encode()

# 2.发起post请求
# urlopen函数data参数:表示的就是经过处理之后的post请求携带的参数
response = urllib.request.urlopen(url=url,data=data)  # 响应对象

response.read()

2、基于ajax的异步请求url获取

  url对应的是针对词条发起的ajax请求对应的url。

  XHR选项卡显示的是基于AJAX的POST请求。找到这些请求中携带参数是“西瓜”的那一个。

  

  由此找到POST请求对应的url地址:

  

3、post请求携带的参数进行处理

# 流程:
# (1)将post请求参数封装到字典
data = {
    'kw':'西瓜'
}

# (2)使用parse模块中的urlencode(返回值类型为str)进行编码处理
data = urllib.parse.urlencode(data)

# (3)将步骤2的编码结果转换成byte类型
data = data.encode()

4、response.read()查看响应的数据

  

  将上述数据,json格式化显示如下:

  

 四、urllib模块的高级操作

  一般不会使用基于urllib的代理和cookie操作,使用流程比较繁琐,效率也比较低。一般还是使用requests模块和scrapy框架。

1、代理操作

(1)什么是代理?

  代理就是第三方代替本体处理相关事务。例如:生活中的代理:代购,中介,微商......

(2)爬虫中为什么需要使用代理?

  一些网站会有相应的反爬虫措施,例如很多网站会检测某一段时间某个IP的访问次数,如果访问频率太快以至于看起来不像正常访客,它可能就会会禁止这个IP的访问。所以我们需要设置一些代理IP,每隔一段时间换一个代理IP,就算IP被禁止,依然可以换个IP继续爬取。

(3)代理的分类

  正向代理:代理客户端获取数据。正向代理是为了保护客户端防止被追求责任。

  反向代理:代理服务器提供数据。反向代理是为了保护服务器或负责负载均衡。

import urllib.request
import urllib.parse

# 1.创建处理器对象,在其内部封装代理ip和端口
handler=urllib.request.ProxyHandler(proxies={'http':'95.172.58.224:52608'})

# 2.创建opener对象,然后使用该对象发起一个请求
opener=urllib.request.build_opener(handler)

url='http://www.baidu.com/s?ie=UTF-8&wd=ip'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
}
# 自制定请求对象
request = urllib.request.Request(url, headers=headers) 

# 3.使用opener对象发起请求,该请求对应的ip即为我们设置的代理ip
response = opener.open(request)

with open('./daili.html','wb') as fp:
    fp.write(response.read())

2、cookie操作

(1)cookie的相关概念及作用

  cookie概念:当用户通过浏览器首次访问一个域名时,访问的web服务器会给客户端发送数据,以保持web服务器与客户端之间的状态保持,这些数据就是cookie。

  cookie作用:我们在浏览器中,经常涉及到数据的交换,比如你登录邮箱,登录一个页面。我们经常会在此时设置30天内记住我,或者自动登录选项。那么它们是怎么记录信息的呢,答案就是今天的主角cookie了,Cookie是由HTTP服务器设置的,保存在浏览器中,但HTTP协议是一种无状态协议,在数据交换完毕后,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接。就像我们去超市买东西,没有积分卡的情况下,我们买完东西之后,超市没有我们的任何消费信息,但我们办了积分卡之后,超市就有了我们的消费信息。cookie就像是积分卡,可以保存积分,商品就是我们的信息,超市的系统就像服务器后台,http协议就是交易的过程。 

(2)cookiejar对象及使用流程

  cookiejar对象

  • 作用:自动保存请求中的cookie数据信息
  • 注意:必须和handler和opener一起使用

  cookiejar使用流程

  • 创建一个cookiejar对象
    import http.cookiejar 
    cj = http.cookiejar.CookieJar() 
  • 通过cookiejar创建一个handler
    handler = urllib.request.HTTPCookieProcessor(cj)
  • 根据handler创建一个opener
    opener = urllib.request.build_opener(handler)
  • 使用opener.open方法去发送请求,且将响应中的cookie存储到openner对象中,后续的请求如果使用openner发起,则请求中就会携带了cookie

(3)使用cookiejar实现爬取人人网个人主页页面数据

  思路:

    1.我们需要使用爬虫程序对人人网的登录时的请求进行一次抓取,获取请求中的cookie数据

    2.在使用个人信息页的url进行请求时,该请求需要携带 1 中的cookie,只有携带了cookie后,服务器才可识别这次请求的用户信息,方可响应回指定的用户信息页数据

#使用cookiejar实现人人网的登陆
import urllib.request
import urllib.parse
import http.cookiejar
cj = http.cookiejar.CookieJar() #请求中的cookie会自动存储到cj对象中
#创建处理器对象(携带cookiejar对象的)
handler=urllib.request.HTTPCookieProcessor(cj)
#创建opener对象 (携带cookiejar对象)
opener=urllib.request.build_opener(handler)

#要让cookiejar获取请求中的cookie数据值
url='http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=201873958471'
#自定义一个请求对象,让该对象作为opener的open函数中的参数
data={
    "email":"www.zhangbowudi@qq.com",
    "icode":"",
    "origURL":"http://www.renren.com/home",
    "domain":"renren.com",
    "key_id":"1",
    "captcha_type":"web_login",
    "password":"40dc65b82edd06d064b54a0fc6d202d8a58c4cb3d2942062f0f7dd128511fb9b",
    "rkey":"41b44b0d062d3ca23119bc8b58983104",
  
 'f':"https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DpPKf2680yRLbbZMVdntJpyPGwrSk2BtpKlEaAuKFTsW%26wd%3D%26eqid%3Deee20f380002988c000000025b7cbb80"
}
data=urllib.parse.urlencode(data).encode()
request=urllib.request.Request(url,data=data)
opener.open(request)

#获取当前用户的二级子页面
s_url='http://www.renren.com/289676607/profile'
#该次请求中就携带了cookie
resonse=opener.open(s_url)

with open('./renren.html','wb') as fp:
    fp.write(resonse.read())

  

 

posted @ 2018-11-01 16:43  休耕  阅读(800)  评论(0编辑  收藏  举报