专栏首页AngelNIpython3爬虫urllib

python3爬虫urllib

基本库 urllib 的使用

urllib 简介

在 Python 中有两种方式可以发送 HTTP 请求,分别是自带的 urllib 库和第三方的 requests 库。

urllib 库:Python 内置的 HTTP 请求库,无需额外安装即可使用;Python 2 中有 urllib 和 urllib2 两个库来实现请求的发送,Python 3 中统一为 urllib。官方文档:https://docs.python.org/3/library/urllib.html

urllib所包含的常用模块

  1. urllib.request:模拟发送请求;
  2. urllib.error:异常处理模块,用于捕获异常;
  3. urrllib.parse:解析、拆分、合并URL
  4. urllib.robotparser:读取网站的robots.txt文件,判断哪些内容可以爬取

urllib.request所包含的常用方法

  1. urllib.request.urlopen():打开网址URL,这可以是一个字符串或一个 Request对象;
  2. urllib.request.Request():在请求的时候传入一些 headers 等信息;
  3. urllib.request.urlretrieve():将获取的URL的内容写到文件目录中去。

urllib.request所包含的常用方法

  1. URLError:继承自 OSError 类,是 error 异常模块的基类,由 request 模块产生的异常都可以通过捕获这个类来处理。
  2. HTTPError:是 URLError 的子类,专门用来处理 HTTP 请求错误,比如认证请求失败等。

urllib.parse 所包含的常用方法

  1. urllib.parse.urlencode():将字典参数序列化为 GET 请求参数;
  2. urllib.parse.parse_qs():将 GET 请求参数反序列化转回字典;
  3. urllib.parse.parse_qsl():将参数转化为元组组成的列表;
  4. urllib.parse.urlparse():对 URL 进行分段(返回6个结果);
  5. urllib.parse.urlunparse():对 URL 进行组合(长度必须为6);
  6. urllib.parse.urlsplit():对 URL 进行分段(不单独解析params部分,返回5个结果);
  7. urllib.parse.urlunsplit():对 URL 进行组合(长度必须为5)
  8. urllib.parse.urljoin():对 URL 进行组合(没有长度限制,给定两个参数,自动分析 scheme、netloc 和 path 这 3 个内容并对新链接缺失的部分进行补充,最后返回结果);
  9. urllib.parse.quote():将内容转化为 URL 编码格式;
  10. urllib.parse.unquote():对 URL 进行解码。

urllib.robotparser 所包含的类

  1. RobotFileParser:根据网站的 robots.txt 文件来判断一个爬取爬虫是否有权限来爬取这个网页

urllib.request

urllib.request.urlopen()

基本使用方法

urllib.request.urlopen(url, data=None, [timeout,]*, cafile=None, capath=None, cadefault=False, context=None)

使用

import urllib.request 

response = urllib.request.urlopen('https://angelni.github.io/')
print(response)

输出响应对象的类型和属性:

import urllib.request 

response = urllib.request.urlopen('https://angelni.github.io/')
print(type(response))
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))

运行结果

<class 'http.client.HTTPResponse'>
200
[('Connection', 'close'), ('Content-Length', '36930'), ('Content-Type', 'text/html; charset=utf-8'), ('Server', 'GitHub.com'), ('Strict-Transport-Security', 'max-age=rict-Transport-Security', 'max-age=31556952'), ('Last-Modified', 'Mon, 11 May 2020 05:38:18 GMT'), ('ETag', '"5eb8e4ca-9042"'), ('A('Expires', 'Thu, 21 May 2020 20:17ccess-Control-Allow-Origin', '*'), ('Expires', 'Thu, 21 May 2020 20:17:51 GMT'), ('Cache-Control', 'max-age=600'), ('X-Proxy-Cache', ('Accept-Ranges', 'bytes'), ('Dat, 'MISS'), ('X-GitHub-Request-Id', '9112:45A4:22C0FB:24F624:5EC6DF95'), ('Accept-Ranges', 'bytes'), ('Date', 'Fri, 22 May 2020 05:4IT'), ('X-Cache-Hits', '1'), ('X-Ti2:11 GMT'), ('Via', '1.1 varnish'), ('Age', '108'), ('X-Served-By', 'cache-tyo19939-TYO'), ('X-Cache', 'HIT'), ('X-Cache-Hits', '1'')]), ('X-Timer', 'S1590126131.497095,VS0,VE1'), ('Vary', 'Accept-Encoding'), ('X-Fastly-Request-ID', 'd0682d145390665c6ad5fa6b629b2af3a18a7654')]
GitHub.com

添加参数

timeout参数

timeout 设置为0.1,0.1秒过后服务器没有响应,便会抛出 URLError 异常

举例

import urllib.request

response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)  
print(response.read())
During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "f:\C-and-Python-Algorithn\python\Spider\1.py", line 3, in <module>
    response = urllib.request.urlopen('https://angelni.github.io/', timeout=0.1)  
  File "E:\python\lib\urllib\request.py", line 223, in urlopen
    return opener.open(url, data, timeout)
  File "E:\python\lib\urllib\request.py", line 526, in open
    response = self._open(req, data)
  File "E:\python\lib\urllib\request.py", line 544, in _open
    '_open', req)
  File "E:\python\lib\urllib\request.py", line 504, in _call_chain
    result = func(*args)
  File "E:\python\lib\urllib\request.py", line 1361, in https_open
    context=self._context, check_hostname=self._check_hostname)
  File "E:\python\lib\urllib\request.py", line 1320, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error _ssl.c:825: The handshake operation timed out>

urllib.request.Request()

Request() 方法可以在请求的时候传入一些 data、headers 等信息

Request() 的构造方法:

class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

构造方法各个参数的解释:

  • url:用于请求 URL,这是必传参数,其他都是可选参数。
  • data:如果要传,必须传 bytes(字节流)类型的。如果它是字典,可以先用 urllib.parse 模块里的 urlencode() 编码。
  • headers:是一个字典,它就是请求头,可以在构造请求时通过 headers 参数直接构造,也可以通过调用请求实例的 add_header() 方法添加。添加请求头最常用的用法就是通过修改 User-Agent 来伪装浏览器,默认的 User-Agent 是 Python-urllib,我们可以通过修改它来伪装浏览器。
  • origin_req_host:指的是请求方的 host 名称或者 IP 地址。
  • unverifiable:表示这个请求是否是无法验证的,默认是 False,意思就是说用户没有足够权限来选择接收这个请求的结果。例如,我们请求一个 HTML 文档中的图片,但是我们没有自动抓取图像的权限,这时 unverifiable 的值就是 True。
  • method:是一个字符串,用来指示请求使用的方法,比如 GET、POST 和 PUT 等。
import urllib.request
import urllib.parse

url = 'http://www.baidu.com/'

# 定制要伪装的头部
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
# 构建请求对象
request = urllib.request.Request(url=url, headers=headers)
# 发送请求
response = urllib.request.urlopen(request)
print(response.read().decode())

urllib.request.urlretrieve()

将获取到的 URL 内容保存到当前文件夹,简单举例:

import urllib.request

url = 'https://cdn.jsdelivr.net/gh/AngelNI/CDN@3.0/imgs/avatar.png'

# response = urllib.request.urlopen(image_url)
# with open('angelni.png', 'wb') as fp:
#    fp.write(response.read())

urllib.request.urlretrieve(url, 'angelni.png')

urllib.error 异常处理

URLError

如果打开一个不存在的页面,就会出现 URLError 错误,该错误有一个 reason 属性,用于返回错误的原因。简单举例:

from urllib import request, error  
try:  
    response = request.urlopen('https://angelni.github.io/index/')  
except error.URLError as e:  
    print(e.reason)

运行结果

Not Found

HTTPError

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

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

简单举例:

from urllib import request, error  
try:  
    response = request.urlopen('https://angelni.github.io/index/')  
except error.HTTPError as e:  
    print(e.code, e.reason, e.headers)

运行结果

404 Not Found Connection: close
Content-Length: 14054
Content-Type: text/html; charset=utf-8
Server: GitHub.com
Strict-Transport-Security: max-age=31556952
ETag: "5eb8e4ca-36e6"
Access-Control-Allow-Origin: *
X-Proxy-Cache: MISS
X-GitHub-Request-Id: 6496:45A5:369AC6:3A1948:5EC76895
Accept-Ranges: bytes
Date: Fri, 22 May 2020 05:59:06 GMT
Via: 1.1 varnish
Age: 403
X-Served-By: cache-tyo19926-TYO
X-Cache: HIT
X-Cache-Hits: 1
X-Timer: S1590127147.595289,VS0,VE0
Vary: Accept-Encoding
X-Fastly-Request-ID: b2a7e9ca856a64157cd67ea4a59e449062baa169

进阶用法

因为 URLError 是 HTTPError 的父类,所以可以先选择捕获子类的错误,再去捕获父类的错误,前面的代码改进:

from urllib import request, error  

try:  
    response = request.urlopen('https://angelni.github.io/index/')  
except error.HTTPError as e:  
    print(e.reason, e.code, e.headers)  
except error.URLError as e:  
    print(e.reason)  
else:  
    print('Request Successfully')

urllib.parse 解析 URL

urllib.parse.urlencode()

将字典参数序列化为 GET 请求参数,示例:

from urllib.parse import urlencode
data = {
    'ie': 'utf-8',
    'wd': 'TRHX',
}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(data)
print(url)

运行结果

http://www.baidu.com?ie=utf-8&wd=TRHX

urllib.parse.parse_qs()

与 urlencode() 相反,将 GET 请求参数反序列化转回字典,示例:

from urllib.parse import parse_qs
query = 'name=TRHX&age=20'
print(parse_qs(query))

运行结果

{'name': ['TRHX'], 'age': ['20']}

urllib.parse.parse_qsl()

将参数转化为元组组成的列表,示例:

from urllib.parse import parse_qsl
query = 'name=TRHX&age=20'
print(parse_qsl(query))

运行结果

[('name', 'TRHX'), ('age', '20')]

urllib.parse.urlparse()

对 URL 进行分段,返回 6 个结果,示例:

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')

返回结果为 ParseResult 类型的对象,含 scheme、netloc、path、params、query 和 fragment 6 个部分,依次代表协议、域名、路径、参数、查询条件、锚点

urllib.parse.urlunparse()

与 urlparse() 相反,对 URL 进行组合,传入的参数是一个可迭代对象,长度必须是 6,否则会抛出参数数量不足或者过多的问题,示例:

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

urllib.parse.urlsplit()

与 urlparse() 方法相似,但是它不再单独解析 params 部分,只返回 5 个结果。params 会合并到 path 中,示例:

from urllib.parse import urlsplit  
result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')  
print(result)

运行结果

SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')

urllib.parse.urlunsplit()

与 urlunparse() 方法类似,对 URL 进行组合,传入的参数也是一个可迭代对象,长度必须为 5,示例:

from urllib.parse import urlunsplit  
data = ['http', 'www.baidu.com', 'index.html', 'a=6', 'comment']  
print(urlunsplit(data))

运行结果

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

urllib.parse.urljoin()

对 URL 进行组合,提供两个 URL 作为两个参数,将会自动分析 URL 的 scheme、netloc 和 path 这 3 个内容并对新链接缺失的部分进行补充,最后返回结果,示例:

from urllib.parse import urljoin  
print(urljoin('http://www.baidu.com', 'friends.html'))  
print(urljoin('http://www.baidu.com', 'https://www.itrhx.com/friends.html'))  
print(urljoin('http://www.baidu.com/friends.html', 'https://www.itrhx.com/friends.html'))  
print(urljoin('http://www.baidu.com/friends.html', 'https://www.itrhx.com/friends.html?id=2'))  
print(urljoin('http://www.baidu.com?wd=trhx', 'https://www.itrhx.com/index.html'))  
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/friends.html
https://www.itrhx.com/friends.html
https://www.itrhx.com/friends.html
https://www.itrhx.com/friends.html?id=2
https://www.itrhx.com/index.html
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2

urllib.parse.quote()

将内容转化为 URL 编码的格式。当 URL 中带有中文参数时,可以将中文字符转化为 URL 编码,示例:

from urllib.parse import quote
keyword = '中国'  
url = 'https://www.baidu.com/s?wd=' + quote(keyword)  
print(url)

运行结果

https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD

urllib.parse.unquote()

与 quote() 方法相反,对 URL 进行解码,示例:

from urllib.parse import unquote  
url = 'https://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD'  
print(unquote(url))

运行结果

https://www.baidu.com/s?wd=中国

urllib.robotparser 爬取权限判断

Robots 协议简介

Robots 协议即爬虫协议,用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取。它通常是一个叫作 robots.txt 的文本文件,一般放在网站的根目录下。

robots.txt 基本格式:

User-agent:
Disallow:
Allow:
  • User-agent 为搜索爬虫的名称,设置为 * 则表示对任何爬虫皆有效;
  • Disallow 指定了不允许抓取的目录,设置为 / 则代表不允许抓取所有页面;
  • Allow 指定了允许抓取的目录,一般和 Disallow 一起使用,一般不会单独使用,用来排除某些限制。

RobotFileParser 类常用方法

RobotFileParser 类的声明:

urllib.robotparser.RobotFileParser(url='')

常用方法及其解释:

  • set_url:用来设置 robots.txt 文件的链接。如果在创建 RobotFileParser 对象时传入了链接,那么就不需要再用这种方法了。
  • read:读取 robots.txt 文件并进行分析。此方法执行一个读取和分析操作,若不调用此方法,接下来的判断都会为 False,这个方法不会返回任何内容,但是执行了读取操作。
  • parse:解析 robots.txt 文件,传入的参数是 robots.txt 某些行的内容,它会按照 robots.txt 的语法规则来分析这些内容。
  • can_fetch:该方法传入两个参数,第一个是 User-agent,第二个是要抓取的 URL。返回的内容是该搜索引擎是否可以抓取这个 URL,返回结果是 True 或 False。
  • mtime:返回的是上次抓取和分析 robots.txt 的时间,此方法可以定期检查来抓取最新的 robots.txt。
  • modified:将当前时间设置为上次抓取和分析 robots.txt 的时间。

以简书为例

from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.set_url('http://www.jianshu.com/robots.txt')
rp.read()
print(rp.can_fetch('*', 'https://www.jianshu.com/p/6d9527300b4c'))
print(rp.can_fetch('*', "http://www.jianshu.com/search?q=python&page=1&type=collections"))
False
False

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 暑假(补)-3

    学完了vector,接下来就开始学习其他容器了。这些都是C++ STL中的比较好用的方法,让你的编程变得简单。

    AngelNH
  • 最短路问题

    过去我也有美梦来着,有幻想来着,可不知神魔时候,都烟消云散了,还是遇见你之前的事。

    AngelNH
  • jsDelivr+Github建立免费CDN

    CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的...

    AngelNH
  • Python 网络请求模块 urllib 、requests

    Python 给人的印象是抓取网页非常方便,提供这种生产力的,主要依靠的就是 urllib、requests这两个模块。

    大江小浪
  • Python爬虫之urllib库—进阶篇

    urllib库除了一些基础的用法外,还有很多高级的功能,可以更加灵活的适用在爬虫应用中,比如,用HTTP的POST请求方法向服务器提交数据实现用户登录、当服务器...

    用户2769421
  • Python-数据挖掘-网络异常

    假设有个请求,要爬取1000个网站,如果其中有100个网站需要等待30s才能返回数据,如果要返回所有的数据,至少需要等待3000s。

    小团子
  • 53. Python 爬虫(2)

        Name   value   domain   path  expires

    py3study
  • Python-数据传输-urllib库

    在爬取网页时,通过 URL 传递数据给服务器,传递数据的方式主要分为 GET 和 POST 两种。这两种方式最大的区别在于:GET 方式是直接使用 URL 访问...

    小团子
  • Python爬虫核心模块urllib的学习

    因为在玩Python challenge的时候,有用过这个模块,而且学习这个模块之后也对系统学习网络爬虫有用。 当时查了各种资料...

    Python中文社区
  • Python爬虫之urllib库—爬虫的第一步

    第一个爬虫代码的实现我想应该是从urllib开始吧,博主开始学习的时候就是使用urllib库敲了几行代码就实现了简单的爬数据功能,我想大多伙伴们也都是这么过来的...

    用户2769421

扫码关注云+社区

领取腾讯云代金券