Python爬虫3.urllib库最详细
书名《Python3 网络爬虫开发实战》,笔记这个都是我自己测试和网上找文章,书里面有的没有测试到位的我也补充了很多,先声明我是菜鸡
Python 的强大之处就是提供了功能齐全的类库来帮助我们完成这些请求。最基础的 HTTP 库有 urllib、httplib2、requests、treq 等
他有4个模块
urllib库的模块 | 作用 |
---|---|
request 模块 |
可以用来模拟发送请求 |
error 模块 |
如果出现请求错误,我们可以捕获这些异常 |
parse 模块 |
一个工具模块,提供了许多 URL 处理方法 |
robotparser 模块 |
识别网站robots.txt 文件,判断哪些可以爬 |
看一下他的文件里面的库模块
模块在/usr/lib/python3/dist-packages/jedi/third_party/typeshed/stdlib/3/urllib/
请求request
模块请求
request模块 | 作用 |
---|---|
urlopen() 函数 |
urlopen()方法只能构建一个简单请求 |
Request() 类 |
Request()类可以构建一个完整的请求 |
BaseHandler 类 |
它提供了最基本的方法,比如用于设置代理 |
OpenerDirector 类 |
更高级的功能更底层功能 |
request模块模块在urllib文件夹里面.
请求方法urlopen()函数
urlopen()方法只能构建一个简单请求
request文件里面可以看一下文件有一个urlopen()方法
get方式请求
这个函数发送一个请求下面的请求是get方式请求
1 | import urllib.request |
分析一下上面的代码
用type()
函数查看一下上面的response
变量的类型代码如下
1 | import urllib.request |
下面有介绍
read()
方法可以得到返回的网页内容
decode()
就是里面的编码
比如我们调用status属性,status属性是查看网站的状态码的
代码
1 | import urllib.request |
post方式请求
urlopen()函数的data
参数
data
参数是可选的,如果用data
参数就是post请求了
测试
1 | import urllib.parse # 一个工具模块,提供了许多 URL 处理方法 |
结果
1 | { |
上面的代码讲解
第一行导入了
import urllib.parse
,导入urllib库的parse模块,parse模块一个工具模块,提供了许多 URL 处理方法
第五行
data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')
用到
bytes()
函数是bytes是字节流bytes对象,字符串是字符串str 对象encoding
是指定的编码格式我们随便测试一下
1
2'utf-8') b= bytes(a, encoding=
b'\xe4\xbd\xa0\xe5\xa5\xbd'bytes()
函数里面的第一个测试urllib.parse.urlencode({'word': 'hello'})
是键值对就是word=hello
的意思看看
1
2>>> urllib.parse.urlencode({'word': 'hello'})
'word=hello'
请求超时设置
urlopen()函数的timeout
参数
如果多长时间没有相应就会抛出异常
下面的代码设置的是0.1
1 | import urllib.request |
结果
1 | raceback (most recent call last): |
我们可以利用异常捕获
代码
1 | import urllib.request |
结果
1 | 时间超时了! |
其他参数
context
参数,类型必须是ssl.SSLContext
类型。
cafile
和capath
这两个参数分别指定CA证书和它的路径,在请求HTTPS链接时候有用
HTTPResposne
类型对象
看一下他的全部的属性和方法用dir
函数查看
1 | from urllib.request import urlopen |
结果
1 | ['__abstractmethods__', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_abc_impl', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_check_close', '_close_conn', '_get_chunk_left', '_method', '_peek_chunked', '_read1_chunked', '_read_and_discard_trailer', '_read_next_chunk_size', '_read_status', '_readall_chunked', '_readinto_chunked', '_safe_read', '_safe_readinto', 'begin', 'chunk_left', 'chunked', 'close', 'closed', 'code', 'debuglevel', 'detach', 'fileno', 'flush', 'fp', 'getcode', 'getheader', 'getheaders', 'geturl', 'headers', 'info', 'isatty', 'isclosed', 'length', 'msg', 'peek', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'reason', 'seek', 'seekable', 'status', 'tell', 'truncate', 'url', 'version', 'will_close', 'writable', 'write', 'writelines'] |
构建请求内容Request()类
request文件里面可以看一下文件有一个Request()类
urlopen()方法只能构建一个简单请求,Request()类可以构建一个完整的请求
比如
1 | import urllib.parse # 一个工具模块,提供了许多 URL 处理方法 |
结果
可以看见下面的User-Agent
字段是Python-urllib/3.9
不是我们的浏览器,我们就可以用Request()类添加了
1 | { |
Request()类的参数
1 | urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None) |
上面的参数
参数 | 作用 |
---|---|
url | 用于请求 URL,这是必传参数,其他都是可选参数 |
data | 必须传 bytes (字节流)类型的,这个就是POST的数据内容 |
headers | headers 是一个字典,它就是请求头 |
origin_req_host | 指的是请求方的 host 名称或者 IP 地址 |
unverifiable | 没有抓取图像的权限就是True,他默认是False |
method | 用来指示请求使用的方法,比如 GET、POST 和 PUT 等 |
创建制定请求内容测试
1 | import urllib.parse # 一个工具模块,提供了许多 URL 处理方法 |
结果
可以看见请求头的User-Agent
字段和Host
字段都被我修改成我制定的了
1 | { |
高级用法
但是对于一些更高级的操作(比如 Cookies 处理、代理设置等)就可以用下面的request
模块的类了
BaseHandler
类
request文件里面可以看一下文件有一个BaseHandler类
urllib.request
模块里的 BaseHandler
类,它是所有其他 Handler
的父类,它提供了最基本的方法,例如 default_open()
、protocol_request()
等
举例如下
类名 | 作用 |
---|---|
HTTPDefaultErrorHandler |
处理 HTTP 响应错误,错误会抛出 HTTPError 类型的异常 |
HTTPRedirectHandler |
用于处理重定向 |
HTTPCookieProcessor |
用于处理 Cookies |
ProxyHandler |
用于设置代理,默认代理为空 |
HTTPPasswordMgr |
用于管理密码,它维护了用户名和密码的表 |
HTTPBasicAuthHandler |
管理认证,链接打开时需要认证,可以用它来解决认证问题 |
还有其他的https://docs.python.org/3/library/urllib.request.html#urllib.request.BaseHandler
OpenerDirector
类
request文件里面可以看一下文件有一个OpenerDirector
类
OpenerDirector我们成为Opener
上面使用的 Request
和 urlopen()
类相当于给你封装好了常用的请求方法,完成基本的操作
更高级的功能更底层功能就用到了 Opener
登录验证
应为我没有环境我就不测试是了就叫书上的给已过来了
下面是验证代码
1 | from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener |
上面的类的作用可以查看官方文档很详细的https://docs.python.org/3/library/urllib.request.html#basehandler-objects
添加代理
1 | from urllib.error import URLError |
上面的代码的意思
ProxyHandler
对象该方法将通过调用来修改要通过代理的请求
build_opener()
对象默认提供许多处理程序
结果 我用的是机场
上面的类的作用可以查看官方文档很详细的https://docs.python.org/3/library/urllib.request.html#basehandler-objects
Cookies
1 | import http.cookiejar, urllib.request |
结果
1 | BAIDUID=2E65A683F8A8BA3DF521469DF8EFF1E1:FG=1 |
保持文件MozillaCookieJar格式
1 | import http.cookiejar, urllib.request |
结果 cookies.txt 文件内容
1 | # Netscape HTTP Cookie File |
保持文件LWP格式
1 | import http.cookiejar, urllib.request |
结果 cookies.txt 文件内容
1 | #LWP-Cookies-2.0 |
读取并利用
error模块处理异常
但是在网络不好的情况下,如果出现了异常,就可以用error模块处理异常
error模块 | 作用 |
---|---|
URLError 类 |
request 模块异常都可以通过捕获这个类来处理 |
HTTPError 类 |
它是 URLError 的子类,可以返回更多信息 |
request模块模块在urllib文件夹里面.
URLError类
在error文件里面
URLError类由 request 模块生的异常都可以通过捕获这个类来处理
测试
1 | from urllib import request, error |
结果
1 | Not Found |
HTTPError类
在error文件里面
它是 URLError
的子类,请求错误用的,比如认证请求失败等。它有如下 3 个属性。
code
:返回 HTTP 状态码,比如 404 表示网页不存在,500 表示服务器内部错误等。reason
:同父类一样,用于返回错误的原因。headers
:返回请求头。
下面我们用几个实例来看看:
1 | # 导入urllib库里面的request模块和error模块 |
结果
1 | 状态码:404 |
parse模块解析链接
error模块 | 作用 |
---|---|
urlencode 函数 |
用于url编码操作 |
unquote 函数 |
用于url解码操作 |
urlparse() 函数 |
叫一个url拆分6部分 |
urlunparse()函数 | 组合6部url组合成一个完整的url |
urlsplit()函数 | 叫一个拆分5部分 |
urlunsplit()函数 | 组合5部url组合成一个完整的url |
urlencode()函数 | 字典变成url的参数 |
parse_qs()函数 | url的参数变成字典 |
parse_qsl()函数 | url的参数变成元素 |
urljoin()函数 | 目标地址加参数拼接完整url |
request模块模块在urllib文件夹里面
编码操作
1 | import urllib.parse # 导入prase模块 |
结果
1 | a=%E6%97%A0%E6%95%8C |
解码操作
1 | import urllib.parse # 导入prase模块 |
结果
1 | a=无敌 |
urlparse()函数拆分6部分
基本演示
1 | from urllib.parse import urlparse |
结果
1 | <class 'urllib.parse.ParseResult'> |
结果是一个 ParseResult
类型的对象,它包含 6 部分,分别是 scheme
、netloc
、path
、params
、query
和 fragment
他就是一个URL组合后:http://www.baidu.com/index.html;user?id=5#comment
他其他是一个元组
代码
1 | from urllib.parse import urlparse |
结果
1 | http |
也可以指定属性来输出结果但是一样的
1 | from urllib.parse import urlparse |
结果
1 | http |
详细介绍
urlparse(url,scheme,allow_fragments)
它有 3 个参数
url这是必填项即待解析的 URL
scheme默认的协议http
或
https,如果url里面有http://他就按url里面的allow_fragments是否忽略 fragment部分设置为
False
输出的结果fragment就什么都没有了看一下结果
1
2
3
4
5
6from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False)
print(result)
result = urlparse('http://www.baidu.com/index.html#comment')
print(result)结果
1
2ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html#comment', params='', query='', fragment='')
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='', query='', fragment='comment')
urlunparse()函数组合6部分
urlunparse()函数他和上面的urlparse()函数是对立的
urlunparse()函数参数必须是 6 个不然就报错
演示
1 | from urllib.parse import urlunparse |
结果实现了 URL 的构造
1 | http://www.baidu.com/index.html;user?a=6#comment |
urlsplit()函数拆分5部分
这个方法和 urlparse()
方法非常相似,只不过它不再单独解析 params
就是参数的部分,只返回 5 个结果
测试
1 | from urllib.parse import urlsplit,urlparse,urlunsplit |
结果
1 | SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment') |
urlsplit函数和urlparse函数看一下他的对比结果
代码
1 | from urllib.parse import urlsplit,urlparse |
结果
1 | SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment') |
这个urlsplit()函数元组和属性
1 | from urllib.parse import urlsplit |
结果
1 | http |
urlunsplit()函数组合5部分
urlunsplit()函数与 urlunparse()函数 类似,唯一的区别是长度必须为 5,不然就报错
示例如下
1 | from urllib.parse import urlunsplit |
结果
1 | http://www.baidu.com/index.html?a=6#comment |
urlencode()函数字典变成参数
urlencode()函数用来构建GET 请求参数
测试
1 | from urllib.parse import urlencode |
结果
1 | http://www.baidu.com?name=germey&age=22 |
parse_qs()函数参数变成字典
parse_qs()函数和urlencode()函数是对立的
利用 parse_qs()
参就可以将它转回字典
测试
1 | from urllib.parse import parse_qs |
结果
1 | {'name': ['germey'], 'age': ['22']} |
parse_qsl()函数参数变成元素
它用于将参数转化为元组组成的列表
测试
1 | from urllib.parse import parse_qsl |
结果
1 | [('name', 'germey'), ('age', '22')] |
urljoin()函数拼接完整url
urljoin()函数是用来做拼接用的可以叫不完整的url拼接成一个完整的
测试
1 | from urllib.parse import urljoin |
结果
1 | http://www.baidu.com/FAQ.html |
如果第二个参数是完整的url他就会抛弃第一个参数
他的判断方式:scheme
、netloc
和 path
。如果这 3 项在新的链接就是第二个参数里面,就抛弃第一个参数
测试
1 | from urllib.parse import urljoin |
结果可以看见第四行第一个参数http://www.baidu.com
被抛弃了
1 | http://www.baidu.com/FAQ.html |
robotparser 模块
利用 urllib 的 robotparser
模块,我们可以实现网站 Robots 协议的分析
request模块模块在urllib文件夹里面.
Robots 协议
可以看我的这个文章Robots 协议
RobotFileParser类
robotparser文件里面就这个一个类
RobotFileParser类的方法
可以看见一眼就能看我就这几个方法
robotparser的方法 | 作用 |
---|---|
set_url() |
设置 robots.txt 文件的链接,如果robotparser他传入url就不需要再使用这个方法设置了 |
read() |
读取 robots.txt 文件并进行分析,不调用这个方法接下来的判断都会为 False |
parse() |
解析 robots.txt 文件传入参数是 robots.txt 某些行的内容,会按照 robots.txt 语法来分析内容 |
can_fetch() |
有两参数一个是 User-agent ,二个是要抓取的 URL,判断是否可以爬,返回结果 True 或 False |
mtime() |
返回上次抓取和分析 robots.txt 的时间,对长时间抓取一个网址很有用 |
modified() |
将当前时间设置为上次抓取和分析 robots.txt 的时间,对长时间抓取一个网址很有用 |
测试就用我最喜欢的B站来测试嘻嘻
我们看一下B站那个网页下面这个几个路径不能爬
我找一个能爬URL:https://www.bilibili.com/v/popular/all
这个可以爬
我用python来判断那个可以爬
代码
1 | from urllib.robotparser import RobotFileParser |
结果
1 | True |
也可以去掉set_url()
方法设置了 robots.txt 的链接
代码
1 | from urllib.robotparser import RobotFileParser |
结果一样的
1 | True |
可以使用 parse()
方法执行读取和分析
1 | from urllib.robotparser import RobotFileParser |
结果一样
1 | True |
上面的代码分析,其实就是这样
代码
1 | from urllib.robotparser import RobotFileParser |
结果一样的
1 | True |