【Python爬虫学习笔记2】urllib库
urllib库是python内置的实现HTTP请求的基本库,通过它可以模拟浏览器的行为,向指定的服务器发送一个请求,并保存服务器返回的数据。
urlopen函数
函数原型:urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,*, cafile=None, capath=None, cadefault=False, context=None)
此函数位于request模块中,可以用来发送请求并获取服务器的响应,其中常用的参数有url(必须指定的参数,HTTP请求地址)、data(可选参数,用于POST请求传递数据,但内容需要进行字节流编码)、timeout(可选参数,用于设置超时时间,单位为秒,当超时后还未得到响应就会抛出异常)。其返回的是一个<http.client.HTTPResponse>响应对象,具有read(size)、readline、readlines以及getcode等方法。
## 示例1——使用urlopen函数发送请求并获取响应
# 导入request模块 from urlib import request # 设置url url = 'http://www.baidu.com' # 使用urlopen发送HTTP请求 response = request.urlopen(url,timeout=3) # 返回html webpage_html = response.read().decode('utf-8') print(webpage_html) # 返回请求状态码 webpage_status = response.getcode() # 或webpage_status=response.status print(webpage_status)
urlretrieve函数
函数原型:urlretrieve(url, filename=None, reporthook=None, data=None)
该函数位于request模块中,可以用于文件的下载,如html代码、image图片等。其中参数url和data含义与urlopen函数一样;filename为所保存文件的文件名;reporthook 为回调函数,当连接服务器并传输完数据块后会自动触发,可以利用这个回调函数来显示当前的下载进度。
## 示例2——使用urlretrieve函数下载文件 from urllib import request # 下载html文件 weburl = 'http://www.baidu.com' request.urlretrieve(weburl, 'baidu.html') # 下载jpg文件 jpgurl = 'http://pic33.nipic.com/20130918/8952533_114903002000_2.jpg' request.urlretrieve(jpgurl,'nipic.jpg')
urlencode函数和parse_qs函数
函数原型:urlencode(query, doseq=False, safe='', encoding=None, errors=None,quote_via=quote_plus)
由于浏览器url编码规则,我们使用代码发送请求时如果有中文和其他字符时,必须进行一定的编码,这时可使用urlencode函数来帮助我们实现数据的URL编码转换。该函数位于parse模块中,其有多个参数,在爬虫应用中只需要掌握query参数(待编码的数据)。
## 示例3——使用urlencode实现百度中文搜索 from urllib import request from urllib import parse # 设置url,此处url的构造法则可参看学习笔记——网络协议与请求基础 url = 'http://www.baidu.com/s' # 设置请求的数据参数 parameters = {'wd': '博客园'} # 编码查询字符串并重定义url querystring = parse.urlencode(parameters) # querystring = 'wd=%E5%8D%9A%E5%AE%A2%E5%9B%AD' url = url + '?' + querystring # 发送请求并返回信息 response = request.urlopen(url) print(response.read().decode('utf-8'))
同样,有编码亦有解码,在parse模块中解码函数为parse_qs,使用方法也比较简单,传入参数待解码字符串即可。
##示例4——使用parse_qs函数解码 # 对url传递的参数进行格式化解码 scoreparam = parse.parse_qs(querystring) print(scoreparam) # {'wd': ['博客园']}
urlsplit函数和urlparse函数
urlparse函数和urlsplit函数均可以用于实现对url地址字符串的格式化分割,即将url分为几个不同的部分。这两个函数均位于pasre模块中,使用时其参数均只需要传入一个编码后的url即可,返回值为一个保存了url各部分的字典数据。其中,二者唯一的区别是urlparse函数的返回对象比urlsplit函数的多了params属性。
## 示例5——使用urlsplit函数和urlparse函数解析url from urllib import parse # 设置url并解析字符串 url = 'http://www.baidu.com/s;hello?wd=python&username=UnikFox#3' result_parse = parse.urlparse(url) result_split = parse.urlsplit(url) # 获取url解析数据 print(result_parse) #ParseResult(scheme='http', netloc='www.baidu.com', path='/s', params='hello', query='wd=python&username=UnikFox', fragment='3') print(result_split) #SplitResult(scheme='http', netloc='www.baidu.com', path='/s;hello', query='wd=python&username=UnikFox', fragment='3') print('netloc',result_parse.netloc) #netloc www.baidu.com print('query',result_parse.query) #query wd=python&username=UnikFox
request.Request类
在我们发送HTTP请求时,如果仅靠urlopen几个参数是不足以构建一个完整的请求,特别是在一些反爬虫机制中常常通过请求头来判断是否为合法用户,因此我们爬虫代码中常常需要添加请求头和一些附加数据来反-反爬虫,这时候便可利用Request类来实现这些设置。
类原型:request.Request(url, data=None, headers={},origin_req_host=None, unverifiable=False,method=None)
其中,参数url为请求URL,data为字节流bytes型数据,headers为请求头字典,origin_req_host为请求方域名或IP地址,unverifiable表示请求是否是无法验证的,method表示请求方法字符串。
##示例6——使用Request类发送请求 from urllib import request,parse # 设置url为拉勾网数据源 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/69.0.3497.92 Safari/537.36', 'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=' } # 设置 data = { 'first': 'true', 'pn': '1', 'kd': 'python' } # 实例化Request类 res = request.Request(url, headers=headers, data=parse.urlencode(data).encode('utf-8'), method='POST') # 发送请求 response = request.urlopen(res) print(response.read().decode('utf-8'))
ProxyHandler处理器(代理设置)
在实际中,很多网站常常检测IP访问量等信息来判断请求是否为爬虫所发,当访问量过于异常(如1s内发送数百次请求)时服务器就会将此IP加入黑名单以拒绝访问。这种反爬虫机制对与爬虫来说是非常不友好的,特别是当我们主机IP被封的时候,因此我们在编写爬虫时很有必要使用代理。
那么,什么是代理?其实,代理就是不直接通过主机而是通过第三方中转渠道访问目标服务器,其过程大概是这样:主机(爬虫)——代理服务器——目标服务器。使用代理后目标服务器则只会标识代理服务器IP,而不知道爬虫的IP,因此不用担心爬虫IP被封,当然代理服务器的IP仍然会被封,这时候换一个代理IP便可以了。另外,返回的响应也是一个逆过程,即目标服务器——代理服务器——主机(爬虫),这里要注意的是,由于代理的中转使用,数据的传输可能会比较慢。
在urllib库中,代理依赖request模块,其通过ProxyHandler类和opener对象来设置并使用代理服务器。
##示例7——使用ProxyHandler类设置代理 # 设置url——用于IP检查 url = 'http://httpbin.org/ip' # Step1:实例化ProxyHandler类,传入参数代理的字典数据 handler = request.ProxyHandler({'http':'223.241.78.43:8010'}) # Step2:生成opener对象,传入参数handler opener = request.build_opener(handler) # Step3:使用opener发送请求 response = opener.open(url) print(response.read().decode('utf-8'))
另外,关于代理服务器,可以自行查阅网络资料。
使用Cookie模拟登陆
在前一篇博客中已经介绍,Cookie 是网站服务器用于识别用户身份和数据追踪而储存在本地的文本文件,使用Cookie后可以保持登录信息以方便与服务器的会话。这也是常用的反爬虫机制数据,如果要反-反爬虫,我们可以直接在请求头header中设置Cookie。
Cookie设置格式:Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
其中,NAME为cookie名,VALUE为cookie值,Expires为过期时间,Path为cookie作用路径,Domain为作用的域名,SECURE为是否设置只在https协议下起作用。
通常来说,在爬虫里我们可以直接设置复制正常访问下获取的Cookie就行,在此不进行演示。
虽然这种复制Cookie方法可行,但过于繁琐,因此,我们可以借助http.cookiejar模块和urllib模块的HTTPCookieProcessor处理器类来处理Cookie。http.cookiejar模块主要是提供用于存储cookie的对象。而HTTPCookieProcessor处理器主要是处理cookie对象,并构建handler对象。
##示例8——使用cookieJar自动登陆 from urllib import request,parse from http.cookiejar import CookieJar # 构建opener对象 # Step1:实例化CookieJar类对象 cookiejar = CookieJar() # Step2:生成handler对象,传入参数cookiejar handler = request.HTTPCookieProcessor(cookiejar) # Step3:生成opener对象,传入参数handler opener = request.build_opener(handler) # 设置headers和data(具体数据名可从HTML文件的id获取) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36' } data = { 'input1':'UnikFox', 'input2':'123456' } # 设置登陆url并实例化Request类,再通过opener发送http请求(即可为登陆状态) Login_url = 'https://passport.cnblogs.com/user/signin' req = request.Request(Login_url,headers=headers,data=parse.urlencode(data).encode('utf-8')) opener.open(req) # 此后同样设置url实例化对象,再通过同一个opener发送请求即可利用源Cookie访问页面 dapeng_url = 'http://www.example.com' req = request.Request(dapeng_url,headers=headers) response = opener.open(req) print(response.read().decode('utf-8'))
Cookie本地化保存与读取
在爬虫中,如果每次都设置cookie是一个很费劲的事,因此我们可以将某次的Cookie保存在本地以便下次需要时读取便可。实现这一功能的是http.cookiejar模块中的MozillaCookieJar,其是一个满足火狐协议用于管理cookie保存与读取的类。
保存cookie到本地,可以使用cookiejar.save方法,而从本地加载cookie,则需要使用cookiejar.load方法,这两种方法均需要指定文件名。
##示例9——Cookie本地化保存与读取 from urllib import request from http.cookiejar import CookieJar,MozillaCookieJar #保存 # 构建opener对象 cookiejar = MozillaCookieJar('cookie.txt') #在此指定文件名后save可以不用再次指定文件名 handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) # 发送请求 response = opener.open('https://cn.bing.com/') # 使用cookiejar保存cookie(同时参数ignore_discard表示也保存一些过期的cookie) cookiejar.save(ignore_discard=True) #读取 cookiejar = MozillaCookieJar('cookie.txt') #在此指定文件名后load可以不用再次指定文件名 cookiejar.load(ignore_discard=True) for cookie in cookiejar: print(cookie)
如下为cookie.txt文件内容: