紧接上一篇:Python3 模块2之 Urllib之 urllib.error

urllib.parse

urllib.parse 模块定义了一个标准接口,在组件(addressing scheme、网址以及路径等)中打破了统一资源定位器(URL)字符串,并将相对 URL(relative URL)转换为给定的 基 URL(base URL) 的绝对 URL(absolute URL)。

urllib.parse 被设计成在相对统一资源定位器(Relative Uniform Resource Locators)上与互联网 RFC 相匹配。它支持如下的 URL schemes (URL 协议): file、 ftp、gopher、hdl、http、 https、imap、 mailto、 mms、news、nntp、 prospero、rsync、rtsp、 rtspu、 sftp、 shttp、 sip、 sips、 snews、svn、svn+ssh、 telnet、 wais、 ws、wss。

urllib.parse 分为 URL parsing (网址解析)和URL quoting(地址引用) 。

一. 网址解析(URL Parsing)

URL 解析函数专注于将 URL 字符串拆分为其组件,或将 URL 组件组合到 URL 字符串中。

下面简要分析使用对应解析函数

1.urlparse

定义:urllib.parse.urlparse(urlstring, scheme=”, allow_fragments=True)

作用特点:将 URL 拆分成 6 大组件

通常一个基本点 URL 应该为:scheme://netloc/path;parameters?query#fragment ,每个元素组都为 String 字符串类型,或者为空。例如,http://www.cwi.nl:80/%7Eguido/Python.html

除这六大组件外,该类具有以下附加的只读便利属性(可看下表):

属性 索引 值 值为 None

scheme 0 URL 协议 scheme 参数

netloc 1 网络端口 空字符串

path 2 分层路径 空字符串

params 3 最后一个路径元素参数 空字符串

query 4 Query 组件 空字符串

fragment 5 片段标志符 空字符串

username 用户名 None

password Password None

hostname 主机名 (小写) None

port 如果存在,端口值为整数 None

下面是一个实例:

#! /usr/bin/evn python3

#"测试urlparse"

#导入parse模块

from urllib import parse

urp = parse.urlparse('https://docs.python.org/3/search.html?q=parse&check_keywords=yes&area=default')

print(urp)

#result:ParseResult(scheme='http', netloc='www.baidu.com:80', path='/doc', params='', query='age=5', fragment='ff')

print(urp.scheme)

#result:http

print(urp.netloc)

#result:www.baidu.com:80

1

2

3

4

5

6

7

8

9

10

11

12

13

14

输出:

ParseResult(scheme='https', netloc='docs.python.org', path='/3/search.html', params='', query='q=parse&check_keywords=yes&area=default', fragment='')

https

docs.python.org

1

2

3

4

urllib.parse.parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding=’utf-8’, errors=’replace’)

2.urlunparse

定义:urllib.parse.urlunparse(parts)

从urlparse() 返回的元组元素构造一个URL 。该部分参数可以是任何六个组件的迭代。如果最初解析的 URL 有不必要的分隔符(例如 ?;带有空查询; RFC 声明它们是等同的),则这可能会导致稍微不同但等效的URL 。

下面是一个实例:

#! /usr/bin/evn python

#测试urlunparse

#导入parse模块

from urllib import parse

parsed=parse.urlparse('http://user:pass@NetLoc:80/path;parameters?query=argument#fragment')

print(parsed)

url=parse.urlunparse(parsed)

print(url)

1

2

3

4

5

6

7

8

9

输出:

ParseResult(scheme='http', netloc='user:pass@NetLoc:80', path='/path', params='parameters', query='query=argument', fragment='fragment')

http://user:pass@NetLoc:80/path;parameters?query=argument#fragment

1

2

3

三.parse_qs

定义:urllib.parse.parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding=’utf-8’, errors=’replace’)

解析一个作为字符串参数给定的查询字符串(类型application/x-www-form-urlencoded 类型的数据)。数据作为字典返回。字典键是唯一的查询变量名且值是每个名称的值列表。

可选参数 keep_blank_values 是指示分空值编码的查询应处理为空字符串标志。一个真值表示空值应保留为空字符串。参数 keep_blank_values 的默认值为 false 表示空值将被忽略,并被视为不包括在内。

可选参数 strict_parsing 是一个标志,表示如何处理解析错误。如果值为 FALSE(默认),错误将被忽略。如果是 `TRUE 1的,误差使 ValueError 异常增加。

四.parse_qsl

定义:urllib.parse.parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding=’utf-8’, errors=’replace’)

基本用法与 parse_qs 一致,只是urllib.parse.parse_qs 返回字典,urllib.parse.parse_qsl 返回列表。

下面是一个针对 三、四的实例:

from urllib import parse

url = r'https://docs.python.org/3.5/search.html?q=parse&check_keywords=yes&area=default'

parseResult = parse.urlparse(url)

#print(parseResult)

# parseResult 数据格式满足 parse.parse_qs、parse.parse_qsl 传入的数据格式要求

param_dict = parse.parse_qs(parseResult.query)

param_list = parse.parse_qsl(parseResult.query)

print("返回字典:",param_dict)

print("返回列表:",param_list)

#注意:加号会被解码,可能有时并不是我们想要的

pps = parse.parse_qs('proxy=183.222.102.178:8080&task=XXXXX|5-3+2')

print(pps)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

输出:

返回字典: {'q': ['parse'], 'check_keywords': ['yes'], 'area': ['default']}

返回列表: [('q', 'parse'), ('check_keywords', 'yes'), ('area', 'default')]

{'proxy': ['183.222.102.178:8080'], 'task': ['XXXXX|5-3 2']}

1

2

3

4

五.urlsplit

定义:urllib.parse.urlsplit(urlstring, scheme=”, allow_fragments=True)

返回:(scheme, netloc, path, query, fragment) 比 urlparse 少个params 参数

这与 urlparse()URL 相似,但不会将参数分开。通常应该使用这种方法,而不是使用 urlparse() 允许将参数应用到 URL 的路径部分的每个段的更新的 URL(请参阅RFC2396 )。分段函数分隔路径段和参数。这个函数返回一个5元组:(寻址方案(addressing scheme),网络地址(network location),路径(path),查询( query),片段标识符(fragment identifier))。

返回值实际上是一个子类的实例tuple。该类具有以下附加的只读便利属性:

属性 索引 值 值为空

scheme 0 URL 协议 scheme 参数

netloc 1 网络端口 空字符串

path 2 分层路径 空字符串

params 3 最后一个路径元素参数 空字符串

query 4 Query 组件 空字符串

fragment 5 片段标志符 空字符串

username 用户名 None

password Password None

hostname 主机名 (小写) None

port 如果存在,端口值为整数 None

下面是一个实例:

#! /usr/bin/evn python

#测试 urlsplit

#导入 parse 模块

from urllib import parse

print (parse.urlsplit('http://www.jb51.net:80/faq.cgi?src=fie'))

#result:SplitResult(scheme='http', netloc='www.jb51.net:80', path='/faq.cgi', query='src=fie', fragment='')

1

2

3

4

5

6

7

输出:

SplitResult(scheme='http', netloc='www.jb51.net:80', path='/faq.cgi', query='src=fie', fragment='')

1

六.urlunsplit

urllib.parse.urlunsplit(parts)

结合一个 urlsplit() 返回的元组元素形成一个完整的 URL 字符串。参数的部分参数可以是可迭代的 five-item。如果被解析的 URL 含有本不必要的分隔符(比如 ? 、查询为空、RFC 明这些是等价的),有这可能会导致一个稍有不同但等效的 URL。

下面是一个实例:

#! /usr/bin/evn python

#测试urlunparse

#导入parse模块

from urllib import parse

sr = parse.SplitResult(scheme='http', netloc='www.baidu.com:80', path='/doc', query='age=5', fragment='ff')

print(parse.urlunsplit(sr))

#result:http://www.baidu.com:80/doc?age=5#ff

1

2

3

4

5

6

7

8

输出:

http://www.baidu.com:80/doc?age=5#ff

1

七.urljoin

urllib.parse.urljoin(base, url, allow_fragments=True)

通过将基URL(base )与另一个 URL(url) 组合起来构建完整的(绝对)的URL。

下面是一个例子:

#!/usr/bin/evn python3

#测试urljoin

#导入parse模块

from urllib import parse

uj1 = parse.urljoin("http://www.asite.com/folder1/currentpage.html","anotherpage.html")

uj2 = parse.urljoin("http://www.asite.com/folder1/currentpage.html","folder2/anotherpage.html")

uj3 = parse.urljoin("http://www.asite.com/folder1/currentpage.html","/folder3/anotnerpage.html")

uj4 = parse.urljoin("http://www.asite.com/folder1/currentpage.html","../finalpage.html")

print(uj1)

print(uj2)

print(uj3)

print(uj4)

1

2

3

4

5

6

7

8

9

10

11

12

13

输出:

http://www.asite.com/folder1/anotherpage.html

http://www.asite.com/folder1/folder2/anotherpage.html

http://www.asite.com/folder3/anotnerpage.html

http://www.asite.com/finalpage.html

1

2

3

4

5

Note:如果 url 是一个绝对 URL(即以// 或 scheme:// 开头的 url ),url 的主机名或 scheme 将会替代 base 。

下面是一个实例:

#!/usr/bin/evn python3

#测试urljoin

#导入parse模块

from urllib import parse

uj1 = parse.urljoin("http://www.asite.com/folder/currentpage.html","https://www.python.org/folder2")

uj2 = parse.urljoin("http://www.asite.com/folder/currentpage.html","//www.python.org/folder1")

uj3 = parse.urljoin("http://www.asite.com/folder/currentpage.html","www.python.org/folder2")

print(uj1)

print(uj2)

print(uj3)

1

2

3

4

5

6

7

8

9

10

11

12

输出:

https://www.python.org/folder2

http://www.python.org/folder1

http://www.asite.com/folder/www.python.org/folder2

1

2

3

4

八.urldefrag

urllib.parse.urldefrag(url)

如果 url 包含片段标志符(即 url 尾部的 #+锚点标签 内容),则返回一个不含片段标志符的 url 且片段标志符分成独立的字符串序列。如何 url 不包含片段标志符则返回未修改的 url 和一个空字符串。

返回值实际上是元组( tuple) 的一个子类的实例。这个类具有以下附加的只读的,便利的属性:

属性 索引 值 值为空

url 0 不具有标志符的 url 空字符串

fragment 1 片段标志符 空字符串

下面是一个实例:

#! /usr/bin/evn python

#测试 urlunparse

#导入parse模块

from urllib import parse

ud = parse.urldefrag('http://music.163.com/#/my/')

print(ud)

#result:DefragResult(url='http://music.163.com/', fragment='/my/')

1

2

3

4

5

6

7

8

输出:

DefragResult(url='http://music.163.com/', fragment='/my/')

1

二.地址引用(URL Quoting)

URL引用函数侧重于获取程序数据,并通过引用特殊字符和适当地编码非ASCII文本来使其作为URL组件安全使用。它们还支持逆转这些操作,以使URL组件的内容重新创建原始数据,如果上述URL解析函数未覆盖该任务的话。

一.quote |quote_from_bytes

定义:urllib.parse.quote(string, safe=’/’, encoding=None, errors=None)

定义:urllib.parse.quote_from_bytes(bytes, safe=’/’)

功能:对字符进行转码,特殊字符(保留字符),如“;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” |”$” | “,” 不转码。

下面是一个实例:

#! /usr/bin/evn python

#测试 parse.quote

#导入parse模块

from urllib import parse

quoted = parse.quote('https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=%E6%95%B0%E5%AD%A6&oq=%25E9%25AB%2598%25E7%25AD%2589%25E6%2595%25B0%25E5%25AD%25A6&rsv_pq=bc3192bd00006199&rsv_t=9874L5kHfiTTvwbjdnArv85fD%2B4yAJXywKFWw1HfLoGCNsctPGieUGbvTcY')

print(quoted)

1

2

3

4

5

6

7

输出:

https%3A//www.baidu.com/s%3Fie%3Dutf-8%26f%3D8%26rsv_bp%3D1%26tn%3Dbaidu%26wd%3D%25E6%2595%25B0%25E5%25AD%25A6%26oq%3D%2525E9%2525AB%252598%2525E7%2525AD%252589%2525E6%252595%2525B0%2525E5%2525AD%2525A6%26rsv_pq%3Dbc3192bd00006199%26rsv_t%3D9874L5kHfiTTvwbjdnArv85fD%252B4yAJXywKFWw1HfLoGCNsctPGieUGbvTcY

1

2

二.quote_plus

定义:urllib.parse.quote_plus(string, safe=”, encoding=None, errors=None)

与 quote 相似,由 quote_plus 编码 /, quote 不编码 /

下面是个实例:

#! /usr/bin/evn python

#测试 parse.quote 、parse.quote_plus

#导入parse模块

from urllib import parse

p=parse.quote('a&b/c') #未编码斜线

print('quote:',p)

plus=parse.quote_plus('a&b/c') #编码了斜线

print('plus:',plus)

1

2

3

4

5

6

7

8

输出

quote: a%26b/c

plus: a%26b%2Fc

1

2

3

三.unquote|unquote_to_bytes

定义:urllib.parse.unquote(string, encoding=’utf-8’, errors=’replace’)

定义:urllib.parse.unquote_to_bytes(string)

功能:quote 的逆过程

下面是一个实例:

#!/usr/bin/evn python

#测试 unquote、unquote_to_bytes

#导入parse模块

from urllib import parse

print(parse.unquote('http%3A//www.baidu.com/doc/sub.html%3Fname%3Dhan%20jian%26age%3D45%40%3B+$'))

print(parse.unquote_to_bytes('http%3A//www.baidu.com/doc/sub.html%3Fname%3Dhan%20jian%26age%3D45%40%3B+$'))

1

2

3

4

5

6

7

输出:

http://www.baidu.com/doc/sub.html?name=han jian&age=45@;+$

b'http://www.baidu.com/doc/sub.html?name=han jian&age=45@;+$'

1

2

四.unquote_plus

定义:urllib.parse.unquote_plus(string, encoding=’utf-8’, errors=’replace’)

功能:quote_plus的逆过程

下面是个实例:

#! /usr/bin/evn python

#测试 parse.unquote 、parse.unquote_plus

#导入parse模块

from urllib import parse

uq=parse.unquote('1+2') #不解码加号

print('unquote:',uq)

uqp=parse.unquote_plus('1+2') #把加号解码为空格

print('unquote_plus:',uqp)

1

2

3

4

5

6

7

8

输出:

unquote: 1+2

unquote_plus: 1 2

1

2

五.urlencode

定义:urllib.parse.urlencode(query, doseq=False, safe=”, encoding=None, errors=None, quote_via=quote_plus)

功能:将字典形式的数据转化成查询字符串

参数的含义:

query:需要转化的字典数据

doseq:如果字典的某个值是序列的话是否解析,deseq值为False不解析doseq的值为True的时候解析,稍后在例子中给出

safe:那些字符串不需要编码

encoding:要转化成的字符串的编码

quote_via:使用quote编码还是qutoe_plus编码,默认quote_plus也就是空格被转化成+号

下面是一个实例:

#!/usr/bin/env python3

#urlencode 测试

from urllib import parse

#定义要转化的字典数据

qdict = {'age':34,'grils':('lili','tingting'),'name':'han p$'}

print(parse.urlencode(qdict))

#result:

#age=34&grils=%28%27lili%27%2C+%27tingting%27%29&name=han+p%24

#怎么让两个女朋友分开呢

print(parse.urlencode(qdict,True))

#result

#age=34&grils=lili&grils=tingting&name=han+p%24

#怎么让name里边的$不要编码呢

print(parse.urlencode(qdict,True,'$'))

#result

#age=34&grils=lili&grils=tingting&name=han+p$

#怎么让空格不编码成+而编译成%20呢

print(parse.urlencode(qdict,True,'$',quote_via=parse.quote))

#由于前面还有两个位置参数所以使用关键字参数

#result age=34&grils=lili&grils=tingting&name=han%20p$

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

输出:

age=34&grils=%28%27lili%27%2C+%27tingting%27%29&name=han+p%24

age=34&grils=lili&grils=tingting&name=han+p%24

age=34&grils=lili&grils=tingting&name=han+p$

age=34&grils=lili&grils=tingting&name=han%20p$

1

2

3

4

5

三.urllib.robotparse

一. 了解网站文件 robots.txt

每个网站都会定义 robots.txt 文件,这个文件可以告诉网络爬虫爬取该网站时存在哪些限制。作为良好网民以及其他人利益,一般上遵从这些限制。

如何查看这个文件?可以通过在目标网站站点或域名后面加上 robots.txt 进行访问。

例如 目标网站站点 https://www.douban.com 的 robots.txt 文件就是 https://www.douban.com/robots.txt。

下面即为这个文件内容:

User-agent: *

Disallow: /subject_search

Disallow: /amazon_search

Disallow: /search

Disallow: /group/search

Disallow: /event/search

Disallow: /celebrities/search

Disallow: /location/drama/search

Disallow: /forum/

Disallow: /new_subject

Disallow: /service/iframe

Disallow: /j/

Disallow: /link2/

Disallow: /recommend/

Disallow: /trailer/

Disallow: /doubanapp/card

# section 1

Sitemap: https://www.douban.com/sitemap_index.xml

Sitemap: https://www.douban.com/sitemap_updated_index.xml

# section 2

# Crawl-delay: 5

# section 3

User-agent: Wandoujia Spider

Disallow: /

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

关于这个 robots.txt 文件内容:

section 1:

定义了 ` Sitemap` 文件,即所谓的网站地图。

1

section 2:

这被注释掉的部分,如果没有被注释且指明了跳转链接,那么,表明每个用户两次爬虫之间的时间间隔不能小于 5s 否则所访问的网站网页会自动跳转到指定的链接页面。此时,相当于网站服务器禁封了 IP ,禁封时间依据各网站的情况。

1

section 3:

这部分表示,`robots.txt` 文件禁止那些代理为 ` Wandoujia Spider` 的爬虫访问网站。理解过来,就是禁止豌豆荚爬虫代理访问网站。

1

二. 检查网站地图(Sitemap)

打开 robots.txt 文件里面的 Sitemap 地址,例如上面的 Sitemap 有, https://www.douban.com/sitemap_index.xml 和 Sitemap: https://www.douban.com/sitemap_updated_index.xml 。

网站提供的 Sitemap 文件(即 网站地图)提供了该网站站点里面所有页面的链接,这些链接组成了这个 Sitemap 文件,所以叫做地图并不过分。 这样,便无须爬取某个网站站点里面的每一个网页因为网站提供的 Sitemap 文件 帮助了网络爬虫定为网站最新的内容(如下图)。

 

Note:虽然 Sitemap 文件提供了一种爬取网站的有效方式,但是我们仍需要对其谨慎处理,因为该文件经常存在缺失、过期或者不完整的问题。(观点以及学习视角引用自:Python 网络爬虫 010 (高级功能) 解析 robots.txt 文件

三. robots.txt 文件的使用测试

还是那个豆瓣的 robots.txt 文件 https://www.douban.com/robots.txt。

如下为文件内容:

User-agent: *

Disallow: /subject_search

Disallow: /amazon_search

Disallow: /search

Disallow: /group/search

Disallow: /event/search

Disallow: /celebrities/search

Disallow: /location/drama/search

Disallow: /forum/

Disallow: /new_subject

Disallow: /service/iframe

Disallow: /j/

Disallow: /link2/

Disallow: /recommend/

Disallow: /trailer/

Disallow: /doubanapp/card

Sitemap: https://www.douban.com/sitemap_index.xml

Sitemap: https://www.douban.com/sitemap_updated_index.xml

# Crawl-delay: 5

User-agent: Wandoujia Spider

Disallow: /

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

对于这个 robots.txt 文件来说, Wandoujia Spider 的代理用户是禁止预览该站点的。

可以使用Python 自带的 robotparser 模块测试一下:

import urllib.robotparser

rp = robotparser.RobotFileParser()

rp.set_url('https://www.douban.com/robots.txt')

rp.read()

url = 'https://www.douban.com'

user_agent = 'Wandoujia Spider'

wsp_info = rp.can_fetch(user_agent, url)

print("Wandoujia Spider 代理用户访问情况:",wsp_info)

user_agent = 'Other Spider'

osp_info = rp.can_fetch(user_agent, url)

print("Other Spider 代理用户访问情况:",osp_info)

1

2

3

4

5

6

7

8

9

10

11

12

输出:

Wandoujia Spider 代理用户访问情况: False

Other Spider 代理用户访问情况: True

1

2

3

学习资料:python doc 、Python 网络爬虫 010 (高级功能) 解析 robots.txt 文件 、Python 网络爬虫 010 (高级功能) 解析 robots.txt 文件、urllib的parse模块。



技术链接