前言
这是python自带的爬虫相关模块,但市面上有更好的BeautifulSoup模块和requests模块.如果是速成爬虫直接学习那两个模块用法即可,但requests模块是使用urllib搭建而成,如果时间不急,可以从底层看起.
urllib的使用
基本模块:
- request:HTTP请求模块
- error:异常处理模块
- parse:工具模块,提供url处理方法
- robotparser:识别网站的robot.txt文件
requset模块
urlopen
参数解释import urllib.requset response = urlib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)
- url: 网页地址
- data:
bytes
类型的字节流编码data = bytes(urllib.parse.urlencode({'username':'admin'}),encoding = "utf-8")
- timeout:超时时间设置,单位秒.
- 其他参数:
context:接受ssl.SSLContext类,用来设置SSL
cafile/capath:设置CA证书和其路径,请求https链接有用
cadefault:已经弃用
Request
import urllib.request
request = urllib.request.Request(url)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
Request
使用Request
对象传给urlopen
,可读性更高,封装更好.
Request构造
request = urllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)
- url:同urlopen
- data:同urlopen
- headers:传一个字典参数,作为请求头
- origin_req_host:请求方的host名称或者IP地址
- unverifiable:表示请求是否是无法验证的,默认为
False
,表示用户没有足够的权限来接受这个请求的结果 - method:字符串参数,表示请求方法,如GET,POST,PUT,DELETE
高级用法
request的高级用法依托Handler
实现.
首先是所有Handler
的父类BaseHandler
,其提供了基本方法,如default_open,protocol_request等
其几个子类如下- HTTPDefaultErrorHandler:用于处理
HTTP
响应错误,所有错误都会抛出HTTPError
类型的异常 - HTTPRedirectHandler:用于处理重定向
- HTTPCookieProcessor:用于处理Cookie
- ProxyHandler:用于设置代理,代理默认为空
- HTTPPasswordMgr:用于密码管理,维护者用户名密码对照表
- HTTPBasicAuthHandler:用于管理认证,如果一个链接在打开的时候需要认证,那么可以用这个解决认证问题.
- HTTPDefaultErrorHandler:用于处理
另外一个比较重要的类是OpenerDirector
,简称Opener.之前的urlopen
方法就是一个Opener
.Request
类和urlopen
类都是已经封装好的常用请求方法,如果需要高级用法则需要使用更加底层的实例来完成操作.Opener
类提供Open
方法,该方法的返回的响应类型和urlopen
方法一致.Opener
类需要使用Handler
类来构建.
验证
在访问一些服务器的时候,有些网页需要用户输入账号密码进行身份验证.这就是HTTP Basic Access Authentication
.
爬虫借助HTTPBasicAuthHandler
模块就能完成身份验证.
from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
import urllib.error
username = 'admin'
password = 'password'
url = ''
p = HTTPPasswordMgrWithDefaultRealm()
p.addpassword(None,url,username,password) ##这个类是构建 用户名和密码 对一个地址的映射,这个映射可以是 url 也可以是 proxy
auth_handler = HTTPBasicAuthHandler(p) ## HTTPBasicAuthHandler的构造方法需要提供一个HTTPPasswordMgr(密码管理 Password Management Object) 对象 如果不知道域/对域不需要关心,就使用 HTTPPasswordMgrwithDefaultRealm 对象,使用None作为构造参数,知道的话就使用realm代替None
opener = build_opener(auth_handler) ## 构建了一个opener,可以使用这个opener去open url.如果这个opener是 网页验证,那么就是open url,如果是 代理验证,那么访问的时候,就是使用代理ip帮你访问(相当于Request封装再更底层)
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
代理
代理的逻辑同验证一样,先使用ProxyHandler建立代理,再使用build_opener方法建立opener,再使用这个opener打开你需要的web
from urllib.requset import ProxyHandler, build_opener,
from urllib.error import URLError
proxy_Handler = ProxyHandler({'http':'http://',
'https':'https://'}) ## ProxyHandler类的构造需要一个字典
opener = build_opener(proxy_Handler)
try:
response = opener.open(url)
print(response.read().decode('utf-8'))
except URLError as e:
print(e.reason)
但是如果碰到了代理验证的话,那么还是需要使用HTTPBasicAuthHandler
from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
import urllib.error
username = 'admin'
password = 'password'
proxyserver = "61.158.163.130:16816" // 此时代理地址直接使用IP地址的字符串
url = ''
p = HTTPPasswordMgrWithDefaultRealm()
p.addpassword(None,proxyserver,username,password) ##这个类是构建 用户名和密码 对代理地址的映射
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
Cookie
获取网站的Cookie,就是根据网站的响应头里面的 Set_Cookie的值来设置Cookie.
思路是构建CookieJar对象,再用这个对象创建opener,用这个opener打开网站,其响应的cookie会自动给CookieJar对象,通过直接访问CookieJar对象来获得Cookie.
from urlib.request import HTTPCookieProcessor,build_opener
from http.cookiejar import CookieJar
cookie = CookieJar()
handler = HTTPCookieProcessor(cookie)
opener = build_opener(handler)
response = opener.open(url)
for items in cookie:
print(item.name + ':' + item.value)
如果需要保存cookie的话,那么需要使用MozillaCookieJar.它是CookieJar的子类,专门用于处理Cookie,比如Cookie的读取和保存,其将Cookie保存为Mozilla浏览器类型的Cookie,也就是在请求头中看到的格式.
from urlib.request import HTTPCookieProcessor,build_opener
from http.cookiejar import MozillaCookieJar
filename = 'cookie.txt'
cookie = MozillaCookieJar(filename)
handler = HTTPCookieProcessor(cookie)
opener = build_opener(handler)
response = opener.open(url)
cookie.save(ignore_discard = True,ignore_expires = True) ## ignore_discard 及时被弃用也将其保存下来,ignore_expires 及时已经过期也将其保存
同样的,如果是LWP(libwww-perl
)格式,则使用
cookie = LWPCookieJar(filename)
那么,如何读取利用cookie?.下面是代码
from urllib.request import HTTPCookieProcessor,build_opener
from http.cookiejar import MozillaCookieJar
cookie = CookieJar()
cookie.load("cookie.txt",ignore_discard = True,ignore_expires = True)
handler = HTTPCookieProcessor(cookie)
opener = build_opener(handler)
response = opener.open(url)
print(response.read().decode('utf-8'))
异常处理
urllib.error
定义了urllib.request
库产生的异常
URLError
URLError
来自urllib.error
库,继承于OSError
,是urllib.error
异常模块的基类.它具有一个reason属性,返回错误原因.
import urllib.error
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except URLError as e:
print(e.reason)
HTTPError
HTTPError
是URLError
的子类,专门用来处理HTTP
请求错误,例如认证请求失败.
import urllib.error
try:
result = opener.open(url)
html = result.read().decode('utf-8')
print(html)
except HTTPError as e:
print(e.reason,e.code,e.headers)
except URLError as e: ##如果不是HTTPError,则进入URLError捕获
print(e.reason)
解析链接
urllib.parse
块定义了处理URL的标准接口,例如实现URL各部分的抽取,合并已经连接转换.
urlparse
该方法实现URL
的识别和分段
from urllib.parse import urlparse
result = urlparse('https://www.baidu.com/index.html;user?id=5#commemt')
print(type(result)) ##<class 'urllib.parse.ParseResult'>,是一个元组,可以使用索引或者序列号访问其中的元素
print(result) ## scheme,netloc,path,params,query fragment
可得标准链接格式:
scheme://netloc/path;params?query#fragment
urlparse
含有三个参数,下面是解释
- urlstring:待解析的url
- scheme:默认的协议,如果url没有提供协议则会用这个代替
- allow_fragment:是否忽略
fragment
urlunparse
此方法用于构造url.参数必须是一个可迭代对象,长度必须为6,否则会抛出异常.
from urllib.parse import urlunparse
string = ["https","www.baidu.com","index.html","user","id=5","commemt"]
urlsplit
和urlparse
类似,只不过params
不会单独出现,划分为path的一部分,返回结果是SplitResult
,和ParseResult
类似,既能索引,也可以序列访问.
urlunsplit
和urlunparse
类似,使用长度为5的可迭代对象.
urljoin
该方法需要两个参数,一个是base_url
,一个是待修改的链接.该方法会分析base_url
中的scheme
,netloc
和path
.如果待修改的链接不含这三个部分中的一个,则补充上去.
urlencode
这个方法在GET
方法中特别实用
from urllib.parse import urlencode
query = {
'tn':'monline_3_dg',
'ie':'utf-8',
'wd':'python'
}
base_url = 'https://www.baidu.com?'
url = base_url + urlencode(query)
print(url) ## https://www.baidu.com?tn=monline_3_dg&ie=utf-8&wd=python
其作用就是把字典参数链接在url后面
parse_qs
反序列化方法,将query
参数返回为字典
from urllib.parse import parse_qs
query = "tn=monline_3_dg&ie=utf-8&wd=python"
print(parse_qs(query)) ## query = {
## 'tn':'monline_3_dg',
## 'ie':'utf-8',
## 'wd':'python'
## }
parse_qsl
将参数转化为元组组成的列表
from urllib.parse import parse_qsl
query = "tn=monline_3_dg&ie=utf-8&wd=python"
print(parse_qsl(query)) ## [('tn','monline_3_dg'),('ie','utf-8'),('wd','python')]
quote
将内容转化为URL
编码格式.如果URL
有中文参数,有可能乱码,所以需要quote
将其转化为 URL
编码
from url.parse import quote
keyword = "爬虫"
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)
unquote
将URL
编码转成中文
分析Robot协议
Robot
协议也叫机器人协议,全名网络爬虫排除标准(Robot Exclusion Protocal),用来告诉爬虫那些网页可以抓取,那些不行.通常命名为robot.txt
,放在网站根目录.
爬虫在实际爬取时,会先检查是否存在’robot.txt’,如果有则遵从,没有的话就随意爬取.
下面是一个robot.txt
的实例
User-Agent: * /对所有爬虫生效
Disallow: / #不允许爬取任何页面
Allow: /public/ #只能爬取public
robotparser
这个模块用于解析robot.txt
文件,来判断是由有权利爬取这个网页.
urllib.robotparser.RobotFileParser(url = '') ## 可以不设置url,之后用set_url添加
以下是RobotFileParset
常用方法
- set_url:设置
robot.txt
文件链接. - read:读取文件并进行分析.这个方法包含读取和分析,所以一定要使用.
- parse:解析文件,传入其中的参数是文件中某些行的内容.
- can_fetch:需要两个参数,一个是
User-Agent
,一个是URL
.判断是否能爬取. - mtime:返回上次抓取分析文件的时间,如果长时间爬取的话就需要获取最新的
robot.txt
文件来判断自己爬取的合法性. - modified:将当前时间设置为上次抓取分析文件的时间,在长时间爬取中很有用.
总结
这一节主要是urllib
的使用,使用略显复杂,后面的requesets
模块更加方便,但是对于自定义爬虫这很有用.
爬取逻辑分析:
判断是否需要验证和代理 -> 根据情况建立HTTPBasicAuthHandler(PasswordMgrWithDefaultRealm)或者ProxyHandler(字典) -> 根据Handler建立opener -> 爬取网页,同时记得捕获异常,根据异常修改爬虫. ->如果需要修改cookie,使用HTTPCookieProcessor(CookieJar类).