上一篇:7.爬虫基本原理
下一篇:9.Requests库基本使用
Urllib讲解:
Python内置的请求库
1 .urllib.requests:请求模块
2 .urlib.error:异常处理模块
3 .urllib.parse:url解析模块
4 .urllib.robotparser :robots.txt解析模块
在Python2和Pyhton3下Urllib库是有区别的
'''pyhton2''''
import urllib2
response = urllib2.urlopen("http://www.baidu.com")
'''Pyhtno3'''
import urllib.request
response = urllib.request.urlopen("http://www.baidu.com")
一、urlopen
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
- 前三个参数
- url:read()获取response的内容,格式为base,所以用decode()转码为字符串
import urllib.request
response = urllib.request.urlopen('http://www.baidu.com')
print(response.read().decode('utf-8'))
- data:述的例子是通过请求百度的get请求获得百度,下面使用urllib的post请求
import urllib.parse
import urllib.request
data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')
print(data)
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())
这里就用到urllib.parse,通过bytes(urllib.parse.urlencode())可以将post数据进行转换放到urllib.request.urlopen的data参数中。这样就完成了一次post请求。
所以如果我们添加data参数的时候就是以post请求方式请求,如果没有data参数就是get请求方式。
import urllib.request
response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)
print(response.read())
运行之后我们看到可以正常的返回结果,接着我们将timeout时间设置为0.1,则会抛出异常
所以我们需要对异常进行抓取,代码更改为
import socket
import urllib.request
import urllib.error
try:
response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
print('TIME OUT')
响应
import urllib.request
response = urllib.request.urlopen('https://www.python.org')
print(type(response)) #响应类型
print(response.status) #状态码
print(response.getheaders()) #头部信息
print(response.getheader("server")) #nginx
print(response.read().decode('utf-8')) #响应体的内容
当然上述的urlopen只能用于一些简单的请求,因为它无法添加一些header信息,如果后面写爬虫我们可以知道,很多情况下我们是需要添加头部信息去访问目标站的,这个时候就用到了urllib.request
二、Request
response = urllib.request.urlopen('https://www.python.org')
变为:
req = urllib.request.Request(url)
response = urllib.request.urlopen(req)
可以添加报头信息
设置Headers
有很多网站为了防止程序爬虫爬网站造成网站瘫痪,会需要携带一些headers头部信息才能访问,最长见的有user-agent参数
- 补充urllib.request.Request的用法
我们可以利用urlopen()方法可以实现最基本请求的发起,但这几个简单的参数并不足以构建一个完整的请求,如果请求中需要加入headers(请求头)等信息,我们就可以利用 更强大的Request类来构建一个请求。也许这就是一下两个方式的区别吧:
import urllib.request
'''最基本的urlopen方法请求'''
respponse = urllib.request.urlopen(url)
import urllib.request
'''用Request类构建了一个完整的请求,增加了headers等一些信息'''
req = urllib.request.Request(url)
response = urllib.request.urlopen(req)
import urllib.request
import urllib.parse
url = 'http://httpbin.org/post'
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
headers['Host'] = 'httpbin.org'
dict = {'name':'Germey'}
data = urllib.parse.urlencode(dict).encode('utf-8')
'''data参数如果要传必须传bytes(字节流)类型的,如果是一个字典,先用urllib.parse.urlencode()编码。'''
request = urllib.request.Request(url = url,data = data,headers = headers,method = 'POST')
response = urllib.request.urlopen(request)
html = response.read().decode('utf-8')
print(html)
x
写一个简单的例子:
import urllib.request
req= urllib.request.Request('https://python.org')
response = urllib.request.urlopen(req)
print(response.read().decode('utf-8'))
给请求添加头部信息,从而定制自己请求网站是时的头部信息
from urllib import request, parse
url = 'http://httpbin.org/post'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
'Host': 'httpbin.org'
}
dict = {
'name': 'lsy'
}
#data
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, headers=headers, method='POST')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
添加请求头的第二种方式
from urllib import request, parse
url = 'http://httpbin.org/post'
dict = {
'name': 'Germey'
}
data = bytes(parse.urlencode(dict), encoding='utf8')
req = request.Request(url=url, data=data, method='POST')
req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')
response = request.urlopen(req)
print(response.read().decode('utf-8'))
这种添加方式有个好处是自己可以定义一个请求头字典,然后循环进行添加
代理--ProxyHandler
通过rulllib.request.ProxyHandler()可以设置代理,网站它会检测某一段时间某个IP 的访问次数,如果访问次数过多,它会禁止你的访问,所以这个时候需要通过设置代理来爬取数据
urlopen=>build_opener
从
response = urllib.reqeust.urlopen("http://www.baidu.com")
变为
opener = urllib.request.build_opener(proxy_handler)
response = opener.open('http://www.baidu.com')
加深记忆....
import urllib.request
proxy_handler = urllib.request.ProxyHandler({
'http': 'http://119.28.194.66:8888',
'https': 'https://119.28.194.66:8888',
})
opener = urllib.request.build_opener(proxy_handler)
response = opener.open('http://www.baidu.com')
print(response.read())
- build_opener ()返回的对象具有open()方法,与urlopen()函数的功能相同。
Cookie,HTTPCookiProcessor
维持登录状态
cookie中保存中我们常见的登录信息,有时候爬取网站需要携带cookie信息访问,这里用到了http.cookijar,用于获取cookie以及存储cookie
import http.cookiejar,urllib.request
# cookieJar()类来构建一个cookieJar()对象,用来保存cookie的值
cookie = http.cookiejar.CookieJar(),
# 通过HTTPCookeieProcessor处理器类构造一个处理器对象,用来处理cookie
# 参数就是构建的CookieJar的对象,至此,cookieJar()使命完成
handler = urllib.request.HTTPCookieProcessor(cookie)
# 构建一个自定义的opener
opener = urllib.request.build_opener(handler)
response = opener.open("http://www.baidu.com")
#执行open后,cookie会自动赋值
for i in cookie:
print(i.name+"="+i.value)
同时cookie可以写入到文件中保存,有两种方式http.cookiejar.MozillaCookieJar和http.cookiejar.LWPCookieJar(),两者都有一个save方法,保存的格式不同而已。
http.cookiejar.MozillaCookieJar()方式
import http.cookiejar, urllib.request
filename = "cookie.txt"
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
http.cookiejar.LWPCookieJar()方式
import http.cookiejar, urllib.request
filename = 'cookie.txt'
cookie = http.cookiejar.LWPCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
同样的如果想要通过获取文件中的cookie获取的话可以通过load方式,当然用哪种方式写入的,就用哪种方式读取。
import http.cookiejar, urllib.request
cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))
异常处理
在很多时候我们通过程序访问页面的时候,有的页面可能会出现错误,类似404,500等错误
这个时候就需要我们捕捉异常,下面先写一个简单的例子
from urllib import request,error
try:
response = request.urlopen("http://pythonsite.com/1111.html")
except error.URLError as e:
print(e.reason)
上述代码访问的是一个不存在的页面,通过捕捉异常,我们可以打印异常错误
这里我们需要知道的是在urllb异常这里有两个个异常错误:
URLError,HTTPError,HTTPError是URLError的子类
URLError里只有一个属性:reason,即抓异常的时候只能打印错误信息,类似上面的例子
HTTPError里有三个属性:code,reason,headers,即抓异常的时候可以获得code,reson,headers三个信息,例子如下
from urllib import request,error
try:
response = request.urlopen("http://pythonsite.com/1111.html")
#先获取子类异常
except error.HTTPError as e:
print(e.reason)
print(e.code)
print(e.headers)
#再获取父类异常
except error.URLError as e:
print(e.reason)
else:
print("reqeust successfully")
同时,e.reason其实也可以在做深入的判断,例子如下:
import socket
from urllib import error,request
try:
response = request.urlopen("http://www.pythonsite.com/",timeout=0.001)
except error.URLError as e:
print(type(e.reason))
if isinstance(e.reason,socket.timeout):
print("time out")
URL解析
urlparse:传入URL,然后对url分割
from urllib.parse import urlparse
result = urlparse("http://www.baidu.com/index.html;user?id=5#comment")
print(result)
可以通过scheme="https"指定协议类型
rom urllib.parse import urlparse
result = urlparse("www.baidu.com/index.html;user?id=5#comment",scheme="https")
print(result)
但是如果url已经指定了协议,scheme指定就无效了
urlunpars
与urlparse的功能相反,它是用于拼接,例子如下:
from urllib.parse import urlunparse
data = ['http','www.baidu.com','index.html','user','a=123','commit']
print(urlunparse(data))
urljoin
拼接url
from urllib.parse import urljoin
print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com', 'https://pythonsite.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://pythonsite.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://pythonsite.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://pythonsite.com/index.php'))
print(urljoin('http://www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com', '?category=2#comment'))
print(urljoin('www.baidu.com#comment', '?category=2'))
结果为
http://www.baidu.com/FAQ.html
https://pythonsite.com/FAQ.html
https://pythonsite.com/FAQ.html
https://pythonsite.com/FAQ.html?question=2
https://pythonsite.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2
[Finished in 0.2s]
可以看出,后面的可以覆盖前面的
urlencode
这个方法可以将字典转换为urlget请求参数,例子如下
from urllib.parse import urlencode
params = {
"name":"lsy",
"age":100,
}
base_url = "http://www.baidu.com?"
url = base_url+urlencode(params)
print(url)
输出:http://www.baidu.com?name=lsy&age=100
上一篇:7.爬虫基本原理
下一篇:9.Requests库基本使用