Bootstrap

Python爬虫:使用Urllib3

一 、什么是爬虫

模拟客户端,访问网站服务器,爬虫从服务器响应给客户端的网页内容中解析有用信息并保存到本地。

二、爬虫执行的流程

(1)请求网页
(2)解析网页信息
(3)保存内容

三、Python爬虫所用到的库

1.请求网页的库

requests
urllib3
selenium(模拟浏览器)

2.解析网页信息的库

re(正则表达式)
BeautifulSoup:BS4
Xpath

3.保存内容到本地

csv txt
下载图片

四、urllib

urllib是python内置HTTP请求库
urllib.request 请求模块
urllib.error 异常处理模块
urllib.parse url解析模块
urllib.robotparser robots.txt解析模块

1.请求

直接使用urlopen()
import urllib.request

''''data字段为空,get请求'''
response = urllib.request.urlopen('http://www.baidu.com')
print(response.read().decode('utf-8'))
import urllib.parse
import urllib.request

"""指定data字段,为post请求"""
data = bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf8')
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read())
使用request对象

在这里插入图片描述

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': 'Germey'
}
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'))

Handler子类继承这个BaseHandler类,举例如下。

HTTPDefaultErrorHandler:用于处理HTTP响应错误,错误都会抛出HTTPError类型的异常。
HTTPRedirectHandler:用于处理重定向。
HTTPCookieProcessor:用于处理Cookies。
ProxyHandler:用于设置代理,默认代理为空。
HTTPPasswordMgr:用于管理密码,它维护了用户名和密码的表。
HTTPBasicAuthHandler:用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题。

另一个比较重要的类就是OpenerDirector,我们可以称为Opener
我们需要实现更高级的功能,所以需要深入一层进行配置,使用更底层的实例来完成操作,所以这里就用到了Opener

Opener可以使用open()方法,返回的类型和urlopen()如出一辙。那么,它和Handler有什么关系呢?简而言之,就是利用Handler来构建Opener

1.1 验证

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError

username = 'username'
password = 'password'
url = 'http://localhost:5000/'

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)#实例化HTTPBasicAuthHandler对象,其参数是HTTPPasswordMgrWithDefaultRealm对象
opener = build_opener(auth_handler)#利用这个Handler并使用build_opener()方法构建一个Opener

try:
    result = opener.open(url)#利用Opener的open()方法打开链接,就可以完成验证了
    html = result.read().decode('utf-8')
    print(html)
except URLError as e:
    print(e.reason)

1.2 代理

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener

#ProxyHandler,其参数是一个字典,键名是协议类型(比如HTTP或者HTTPS等),键值是代理链接,可以添加多个代理
proxy_handler = ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
opener = build_opener(proxy_handler)
try:
	#利用这个Handler及build_opener()方法构造一个Opener,之后发送请求即可。
    response = opener.open('https://www.baidu.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

1.3 cookies

获取网站上的cookie
import http.cookiejar, urllib.request

cookie = http.cookiejar.CookieJar()#声明一个CookieJar对象
handler = urllib.request.HTTPCookieProcessor(cookie)#利用HTTPCookieProcessor来构建一个Handler
opener = urllib.request.build_opener(handler)#build_opener()方法构建出Opener
response = opener.open('http://www.baidu.com')
for item in cookie:
    print(item.name+"="+item.value)

这段代码是输出文本,下面这段代码可以将cooike保存到文件

filename = 'cookies.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)

LWPCookieJar同样可以读取和保存Cookies,但是保存的格式和MozillaCookieJar不一样,它会保存成libwww-perl(LWP)格式的Cookies文件。

cookie = http.cookiejar.LWPCookieJar(filename)
读取本地cookie文件
cookie = http.cookiejar.LWPCookieJar()
#这里调用load()方法来读取本地的Cookies文件,获取到了Cookies的内容。不过前提是我们首先生成了LWPCookieJar格式的Cookies,并保存成文件
cookie.load('cookies.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'))

2.响应

状态码,响应头

import urllib.request

response = urllib.request.urlopen('http://www.baidu.com')
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))

3.处理异常

3.1 URLError

由request模块生的异常都可以通过捕获这个类来处理。

请求一个不存在的网页

from urllib import request, error
try:
    response = request.urlopen('http://www.nwu.edu.cn/index.htm')
except error.URLError as e:
    print(e.reason)

3.2 HTTPError

它是URLError的子类,专门用来处理HTTP请求错误,比如认证请求失败等。它有如下3个属性。

code:返回HTTP状态码,比如404表示网页不存在,500表示服务器内部错误等。
reason:同父类一样,用于返回错误的原因。
headers:返回请求头。
在这里插入图片描述

3.3 建议的异常处理方法

from urllib import request, error
 
try:
    response = request.urlopen('http://cuiqingcai.com/index.htm')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:
    print(e.reason)
else:
    print('Request Successfully')

这样就可以做到先捕获HTTPError,获取它的错误状态码、原因、headers等信息。如果不是HTTPError异常,就会捕获URLError异常,输出错误原因。最后,用else来处理正常的逻辑。

4.URL解析

urlparse,利用urlparse()方法可以将url拆分开来

urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)
from urllib.parse import urlparse
 
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)

<class ‘urllib.parse.ParseResult’> ParseResult(scheme=‘http’, netloc=‘www.baidu.com’, path=’/index.html’, params=‘user’, query=‘id=5’, fragment=‘comment’)

指定协议类型:

from urllib.parse import urlparse

result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)

ParseResult(scheme=‘https’, netloc=’’, path=‘www.baidu.com/index.html’, params=‘user’, query=‘id=5’, fragment=‘comment’)

最后一个参数:allow_fragments为是否允许使用锚点链接,返回值中的fragment为空,其值将被拼接至前一个非空字段。

5. urlunparse

将url进行拼接

from urllib.parse import urlunparse

data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))

http://www.baidu.com/index.html;user?a=6#comment

6. urljoin

from urllib.parse import urljoin

print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com', 'https://www.nwu.edu.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://www.nwu.edu.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://www.nwu.edu.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', 'https://www.nwu.edu.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://www.nwu.edu.com/FAQ.html
https://www.nwu.edu.com/FAQ.html
https://www.nwu.edu.com/FAQ.html?question=2
https://www.nwu.edu.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2

7.urlencode

将字典对象转换为get请求参数

from urllib.parse import urlencode

params={
    'name':"nwu",
    'age':'119'
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)

http://www.baidu.com?name=nwu&age=119

;