鱼C论坛

 找回密码
 立即注册
查看: 2597|回复: 9

[技术交流] 爬虫基础篇-02:请求库---urllib库

[复制链接]
发表于 2019-2-12 16:53:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Stubborn 于 2019-2-16 00:37 编辑

有大神可以告诉我,这个请求模块有什么优点嘛?书本后面介绍的requests模块秒杀几条街,而且没有这么繁琐。
Urllib库包含4个模块
  • request:是最基本的HTTP请求模块,可以模拟发送请求。
  • error:异常处理模块。
  • parse:工具模块,提供许多的URL处理方法,比如拆分,解析,合并等等。
  • robotparser:识别网站的robots.txt文件

request模块:
1.urlopen():

  1. urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
复制代码
 
  • url:目标资源在网路中的位置。可以是一个表示URL的字符串(如:https://www.baidu.com/
  • data:data用来指明发往服务器请求中的额外的参数信息(如:在线翻译,在线答题等提交的内容),data默认是None,此时以GET方式发送请求;当用户给出data参数的时候,改为POST方式发送请求。
  • timeout:设置参数超时,单位为秒,如果访问网页超出设定时间,它会抛出一个URLError的异常,属于urllib.error模块,错误原因是超时,因此我们可以配合try来跳过当前访问超时的网页      
  • cafile、capath、cadefault 参数:用于实现可信任的CA证书的HTTP请求。(基本上很少用)
  • context参数:实现SSL加密传输。(基本上很少用)

使用实例:
  1. import urllib.request
  2. response = urllib.request.urlopen("url")#url具体的网址
  3. print(response.read().decode("utf-8")
复制代码

如上面最简单的三行代码即可抓取网页的源代码。然后进行解析得到需要的数据。
同时response是一个HTTPResponse类型的对象,主要包含:
        read(),readinto(),getheader(name),getheaders(),fileno()等方法以及msg,version,status,reason,debuglevel,closed等属性
        通过response变量,可以调用这些方法和属性。得到返回结果的一些列信息。
2.Request():
  1. urllib.request.Request(url=url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)
复制代码

  • url是必选参数,用于请求URL,其他都是可选参数。
  • data如果要传,必须传bytes(字节流)类型的。如果是字典,可以先用urllib.parse模块里面的urlencode()编码
  • headers是一个字典,他就是请求头,用来伪装模拟。
  • origin_req_host指的是请求方的host名称或者IP地址
  • unverifiable表示这个请求时无法验证的,默认为False,意思就是说用户没有足够的权限来选择这个接收是请求的结果,例如,我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,这是unverifiable的值为Ture
  • method是一个字符串,用来指示请求使用的方法,比如GET,POST和PUT等

使用实例:
  1. from urllib import request, parse
  2. url = "http://httpbin.org/post"
  3. headers = {
  4.     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
  5.     "Host": "httpbin.org"
  6. }
  7. dict = {
  8.     "name": "Stubbron"
  9. }
  10. data = bytes(parse.urlencode(dict), encoding="utf-8")
  11. req = request.Request(url=url, data=data, headers=headers, method="POST")
  12. response = request.urlopen(req)
  13. print(response.read().decode("utf-8"))
复制代码

req中,我们通过了4个参数构造了一个请求,其中url为请求的网页,headers中指定了User-Agent和Host,参数data用urlencode()和bytes()方法转换成节流,指定了请求方法为POST。
另外headers(请求头)也可以用add_header这个来进行添加。
  1. req = request.Request(url=url, data=data, method="POST")
  2. req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
复制代码


error模块

URLError类都来自urllib库的error模块,它继承OSerror类,由request模块所产生的异常都会捕捉到
HTTPError是URLError的子类,专门用来处理HTTP的请求错误。它有如下三个属性。
  • code:返回HTTP的状态码
  • reson:用于返回错误的原因
  • headers:返回请求头

以下例子:
  1. from urllib import request, error
  2. try:
  3.     response = request.urlopen("https://cuiqingcai.com/index.html")
  4. except error.HTTPError as e:
  5.     print(e.reason, e.code, e.headers)
  6. except error.URLError as e:
  7.         print(e.reason)
  8. else:
  9.         print("Resquest")
复制代码

返回结果:
  1. Not Found 404 Server: nginx/1.10.3 (Ubuntu)
  2. Date: Tue, 12 Feb 2019 14:22:03 GMT
  3. Content-Type: text/html; charset=UTF-8
  4. Transfer-Encoding: chunked
  5. Connection: close
  6. Vary: Cookie
  7. Expires: Wed, 11 Jan 1984 05:00:00 GMT
  8. Cache-Control: no-cache, must-revalidate, max-age=0
  9. Link: <https://cuiqingcai.com/wp-json/>; rel="https://api.w.org/"
复制代码

由于HTTPError是URLError的子类,所以建议先捕获HTTPError,获取它的错误状态码,原因,headers等,如果不是HTTPError异常,就会捕获URLError异常,输出错误原因,最后用else来处理处理正常逻辑。

parse()模块:
urlparse()用于URL的识别与分段:
  1. urlparse(url=url,scheme="",allow_fragments=False)
复制代码

  • url代表需要解析的网址
  • scheme代表默认协议
  • allow_fragments:代表是否忽略锚点(fragments)

最后注意ParseResult返回的是一个元祖,所以可以通过索引顺序来获取。
以下例子:
  1. from urllib.parse import urlparse
  2. result = urlparse("http://www.baidu.com/index.html;user?id=5#comment")
  3. print(type(result), result)
复制代码

结果如下:
  1. <class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
复制代码

分别代表了协议(scheme),域名(netloc),访问路径(path),参数(params),查询条件(query),锚点(fragment)

urlunparse()
用于构造url,实例
  1. from urllib.parse import urlunparse
  2. data = ['http', 'www.baidu.com', '/index.html', 'user', 'id=5', 'comment']
  3. print(urlunparse(data))
复制代码

结果如下:
  1. http://www.baidu.com/index.html;user?id=5#comment
复制代码


下面还有很多的URL构造,我看书看了很久,有大神有看的话,可以告诉我,花那么大的力气必要来构造一个URL有没有必要,是不是我学的太粗浅
urlsplit(),urlunsplit(),urljoin(),urlencode(),parse_qs(),parse_qsl(),quote(),unquote()

下面介绍几个高级操作:
比如另外一些高级操作,如Cookies处理,代理设置等,我们需要用到更强大的工具: Handler, 可以理解他为各种处理器,利用他们我们几乎可以做到HTTP请求中的所用事情
首先介绍下urllib.request模块里面的BaseHandler类,它是所有其他Handler的父类,它提供了最基本的方法,如default_open(), protcol_resquest()等
接下来就用各种Handler子类继承这个Basehandler类,举例如下:
  • HTTPDefauktErroeHandler: 用于处理HTTP响应错误,错误都会抛出HTTPError异常。
  • HTTPRedurectHandler: 用于处理重定向
  • HTTPCookieProcessor: 用于处理Cookies
  • ProxyHandler: 用于设置代理,默认为空
  • HTTPPasswordMgr: 用于管理摩玛,维护用户和密码的表
  • HTTPBasicAuthHandler: 用于管理认证,如果一个连接打开时需要认证,可以用它来进行解决认证问题

还有其他的handler类,参考官方文档:https://docs.python.org/3/librar ... request.BaseHandler

验证:
  1. from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
  2. from urllib.error import URLError
  3. username = "Stubbron"
  4. password = "password"
  5. url = "http://localhost:5000"
  6. p = HTTPPasswordMgrWithDefaultRealm()
  7. p.add_password(None, uri=url, user=username, passwd=password)
  8. auth_passwd = HTTPBasicAuthHandler(p)
  9. opener = build_opener(auth_passwd)
  10. try:
  11.     result = opener.open(url)
  12.     html = result.read().decode("utf-8")
  13.     print(html)
  14. except URLError as e:
  15.     print(e.reason)
复制代码

首先实例化HTTPBasicAuthHandler对象,其参数是HTTPPasswordMgrWithDefaultRealm对象,它利用add_password()添加进去用户名和密码这样就建立了一个处理验证的handler

代理:
  1. from urllib.error import URLError
  2. from urllib.request import ProxyHandler, build_opener
  3. proxy = ProxyHandler({
  4.     "https": "https://127.0.0.1:9473",
  5.     "http": "http://127.0.0.0:9473"
  6. })
  7. opener = build_opener(proxy)
  8. try:
  9.     response = opener.open("http://www.baidu.com", timeout=5)
  10.     print(response.read().decode("utf-8"))
  11. except URLError as e:
  12.     print(e.reason)
复制代码

如上已经搭建一个代理,然后利用这个Haddler以及build_opener()方法构造一个请求就可以。

Cookies:
将获取到的cookies以LWP格式保存在cookie.txt文本中
  1. import http.cookiejar, urllib.request
  2. filename = "cookie.txt"
  3. cookie = http.cookiejar.LWPCookieJar(filename=filename)
  4. handler = urllib.request.HTTPCookieProcessor(cookie)
  5. opener = urllib.request.build_opener(handler)
  6. response = opener.open("http://www.baidu.com")
  7. cookie.save(ignore_expires=True, ignore_discard=True)
复制代码


下面是读取以及利用cookies
  1. import http.cookiejar,urllib.request
  2. cookie = http.cookiejar.LWPCookieJar()
  3. cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
  4. handler = urllib.request.HTTPCookieProcessor(cookie)
  5. opener = urllib.request.build_opener(handler)
  6. response = opener.open("http://www.baidu.com")
  7. print(response.read().decode("utf-8"))
复制代码



robotparser模块
简单的说用来网站的robots.txt文件,这个文件说明你那些地方可以爬取,那些地方是禁止爬取的,它是一个网络协议。个人写的一些小爬虫,可以直接无视,不做多讲。

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2019-2-12 23:02:16 | 显示全部楼层
前排
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-2-12 23:03:44 | 显示全部楼层

用requests更强大,更省心
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-12 23:19:36 | 显示全部楼层
小白提问,host就是IP地址吧,如果我想用代理IP,是不是直接在Host添加键值??
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-2-13 01:02:24 | 显示全部楼层
本帖最后由 Stubborn 于 2019-2-13 01:09 编辑
我刀锋偏冷 发表于 2019-2-12 23:19
小白提问,host就是IP地址吧,如果我想用代理IP,是不是直接在Host添加键值??


这个是用来测试代理IP是否可用的  你可以参考下这个函数,比较简明  194.135.97.179:3128  提取到的必须是这种格式,才能使用
  1. def ip_test(ip):
  2.     "IP代理测试"
  3.     proxy_support = urllib.request.ProxyHandler({"http" : ip})
  4.     opener = urllib.request.build_opener(proxy_support)
  5.     urllib.request.install_opener(opener=opener) #https://httpbin.org/ip
  6.     req = urllib.request.Request("https://httpbin.org/ip")
  7.     selp = random.randint(1,3)
  8.     print("测试等待{}秒".format(selp))
  9.     time.sleep(selp)
  10.     try:
  11.         html = urllib.request.urlopen(req).read()
  12.         print("当前IP可用:",html)
  13.     except Exception as e:
  14.         print("e")
  15.         print("当前IP不可用")
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-8 22:13:56 | 显示全部楼层
想问一下你的:        (爬虫基础篇-03:请求库---requests库)为啥没了,很想看。有别的分享渠道,比如公众号啥的,我可以看看嘛
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-9 22:40:34 | 显示全部楼层
shokunin 发表于 2019-7-8 22:13
想问一下你的:        (爬虫基础篇-03:请求库---requests库)为啥没了,很想看。有别的分享渠道,比如公众号啥 ...

我从书上整理出来的,过段时间,我重新整理下,发出来~
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-10 08:43:09 | 显示全部楼层
Stubborn 发表于 2019-7-9 22:40
我从书上整理出来的,过段时间,我重新整理下,发出来~

好的,谢谢啦,请问您看的是那本书啊,能推荐一下嘛
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-7-10 16:21:47 | 显示全部楼层
shokunin 发表于 2019-7-10 08:43
好的,谢谢啦,请问您看的是那本书啊,能推荐一下嘛

Python 3网络爬虫开发实战   崔庆才的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-7-10 20:43:21 | 显示全部楼层
Stubborn 发表于 2019-7-10 16:21
Python 3网络爬虫开发实战   崔庆才的

好的,谢谢啦
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-1-14 17:59

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表