使用 Python 的 urlliib.parse 库解析 URL | Linux 中国

2018 年 2 月 23 日 Linux中国 作者:Darksun
Python 中的 urllib.parse 模块提供了很多解析和组建 URL 的函数。
-- Darksun



致谢
转载自 | https://github.com/lujun9972/lujun9972.github.com/blob/source/%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%97%85/%E4%BD%BF%E7%94%A8urlliib.parse%E5%BA%93%E8%A7%A3%E6%9E%90url.org
 作者 | Darksun

Python 中的 urllib.parse 模块提供了很多解析和组建 URL 的函数。

解析url

urlparse() 函数可以将 URL 解析成 ParseResult 对象。对象中包含了六个元素,分别为:

◈ 协议(scheme)
◈ 域名(netloc)
◈ 路径(path)
◈ 路径参数(params)
◈ 查询参数(query)
◈ 片段(fragment)
   
     
     
     
  1. from urllib.parse import urlparse

  2. url='http://user:pwd@domain:80/path;params?query=queryarg#fragment'

  3. parsed_result=urlparse(url)

  4. print('parsed_result 包含了',len(parsed_result),'个元素')

  5. print(parsed_result)

结果为:

   
     
     
     
  1. parsed_result 包含了 6 个元素

  2. ParseResult(scheme='http', netloc='user:pwd@domain:80', path='/path', params='params', query='query=queryarg', fragment='fragment')

ParseResult 继承于 namedtuple,因此可以同时通过索引和命名属性来获取 URL 中各部分的值。

为了方便起见, ParseResult 还提供了 username、 password、 hostname、 port 对 netloc 进一步进行拆分。

   
     
     
     
  1. print('scheme  :', parsed_result.scheme)

  2. print('netloc  :', parsed_result.netloc)

  3. print('path    :', parsed_result.path)

  4. print('params  :', parsed_result.params)

  5. print('query   :', parsed_result.query)

  6. print('fragment:', parsed_result.fragment)

  7. print('username:', parsed_result.username)

  8. print('password:', parsed_result.password)

  9. print('hostname:', parsed_result.hostname)

  10. print('port    :', parsed_result.port)

结果为:

   
     
     
     
  1. scheme  : http

  2. netloc  : user:pwd@domain:80

  3. path    : /path

  4. params  : params

  5. query   : query=queryarg

  6. fragment: fragment

  7. username: user

  8. password: pwd

  9. hostname: domain

  10. port    : 80

除了 urlparse() 之外,还有一个类似的 urlsplit() 函数也能对 URL 进行拆分,所不同的是, urlsplit() 并不会把 路径参数(params) 从 路径(path) 中分离出来。

当 URL 中路径部分包含多个参数时,使用 urlparse() 解析是有问题的:

   
     
     
     
  1. url='http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg#fragment'

  2. parsed_result=urlparse(url)

  3. print(parsed_result)

  4. print('parsed.path    :', parsed_result.path)

  5. print('parsed.params  :', parsed_result.params)

结果为:

   
     
     
     
  1. ParseResult(scheme='http', netloc='user:pwd@domain:80', path='/path1;params1/path2', params='params2', query='query=queryarg', fragment='fragment')

  2. parsed.path    : /path1;params1/path2

  3. parsed.params  : params2

这时可以使用 urlsplit() 来解析:

   
     
     
     
  1. from urllib.parse import urlsplit

  2. split_result=urlsplit(url)

  3. print(split_result)

  4. print('split.path    :', split_result.path)

  5. # SplitResult 没有 params 属性

结果为:

   
     
     
     
  1. SplitResult(scheme='http', netloc='user:pwd@domain:80', path='/path1;params1/path2;params2', query='query=queryarg', fragment='fragment')

  2. split.path    : /path1;params1/path2;params2

若只是要将 URL 后的 fragment 标识拆分出来,可以使用 urldefrag() 函数:

   
     
     
     
  1. from urllib.parse import urldefrag

  2. url = 'http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg#fragment'

  3. d = urldefrag(url)

  4. print(d)

  5. print('url     :', d.url)

  6. print('fragment:', d.fragment)

结果为:

   
     
     
     
  1. DefragResult(url='http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg', fragment='fragment')

  2. url     : http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg

  3. fragment: fragment

组建URL

ParsedResult 对象和 SplitResult 对象都有一个 geturl() 方法,可以返回一个完整的 URL 字符串。

   
     
     
     
  1. print(parsed_result.geturl())

  2. print(split_result.geturl())

结果为:

   
     
     
     
  1. http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg#fragment

  2. http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg#fragment

但是 geturl() 只在 ParsedResult 和 SplitResult 对象中有,若想将一个普通的元组组成 URL,则需要使用 urlunparse() 函数:

   
     
     
     
  1. from urllib.parse import urlunparse

  2. url_compos = ('http', 'user:pwd@domain:80', '/path1;params1/path2', 'params2', 'query=queryarg', 'fragment')

  3. print(urlunparse(url_compos))

结果为:

   
     
     
     
  1. http://user:pwd@domain:80/path1;params1/path2;params2?query=queryarg#fragment

相对路径转换绝对路径

除此之外,urllib.parse 还提供了一个 urljoin() 函数,来将相对路径转换成绝对路径的 URL。

   
     
     
     
  1. from urllib.parse import urljoin

  2. print(urljoin('http://www.example.com/path/file.html', 'anotherfile.html'))

  3. print(urljoin('http://www.example.com/path/', 'anotherfile.html'))

  4. print(urljoin('http://www.example.com/path/file.html', '../anotherfile.html'))

  5. print(urljoin('http://www.example.com/path/file.html', '/anotherfile.html'))

结果为:

   
     
     
     
  1. http://www.example.com/path/anotherfile.html

  2. http://www.example.com/path/anotherfile.html

  3. http://www.example.com/anotherfile.html

  4. http://www.example.com/anotherfile.html

查询参数的构造和解析

使用 urlencode() 函数可以将一个 dict 转换成合法的查询参数:

   
     
     
     
  1. from urllib.parse import urlencode

  2. query_args = {

  3.    'name': 'dark sun',

  4.    'country': '中国'

  5. }

  6. query_args = urlencode(query_args)

  7. print(query_args)

结果为:

   
     
     
     
  1. name=dark+sun&country=%E4%B8%AD%E5%9B%BD

可以看到特殊字符也被正确地转义了。

相对的,可以使用 parse_qs() 来将查询参数解析成 dict。

   
     
     
     
  1. from urllib.parse import parse_qs

  2. print(parse_qs(query_args))

结果为:

   
     
     
     
  1. {'name': ['dark sun'], 'country': ['中国']}

如果只是希望对特殊字符进行转义,那么可以使用 quote 或 quote_plus 函数,其中 quote_plus 比 quote 更激进一些,会把 :/ 一类的符号也给转义了。

   
     
     
     
  1. from urllib.parse import quote, quote_plus, urlencode

  2. url = 'http://localhost:1080/~hello!/'

  3. print('urlencode :', urlencode({'url': url}))

  4. print('quote     :', quote(url))

  5. print('quote_plus:', quote_plus(url))

结果为:

   
     
     
     
  1. urlencode : url=http%3A%2F%2Flocalhost%3A1080%2F%7Ehello%21%2F

  2. quote     : http%3A//localhost%3A1080/%7Ehello%21/

  3. quote_plus: http%3A%2F%2Flocalhost%3A1080%2F%7Ehello%21%2F

可以看到 urlencode 中应该是调用 quote_plus 来进行转义的。

逆向操作则使用 unquote 或 unquote_plus 函数:

   
     
     
     
  1. from urllib.parse import unquote, unquote_plus

  2. encoded_url = 'http%3A%2F%2Flocalhost%3A1080%2F%7Ehello%21%2F'

  3. print(unquote(encoded_url))

  4. print(unquote_plus(encoded_url))

结果为:

   
     
     
     
  1. http://localhost:1080/~hello!/

  2. http://localhost:1080/~hello!/

你会发现 unquote 函数居然能正确地将 quote_plus 的结果转换回来。


登录查看更多
0

相关内容

【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
257+阅读 · 2020年6月10日
【Manning新书】现代Java实战,592页pdf
专知会员服务
98+阅读 · 2020年5月22日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
【哈佛《CS50 Python人工智能入门》课程 (2020)】
专知会员服务
109+阅读 · 2020年4月12日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
20+阅读 · 2019年11月7日
MIT新书《强化学习与最优控制》
专知会员服务
270+阅读 · 2019年10月9日
GitHub 热门:Python 算法大全,Star 超过 2 万
Python开发者
9+阅读 · 2019年4月27日
GitHub 热门:各大网站的 Python 爬虫登录汇总
机器学习算法与Python学习
9+阅读 · 2019年3月20日
34个最优秀好用的Python开源框架
专知
9+阅读 · 2019年3月1日
Python用法速查网站
Python程序员
17+阅读 · 2018年12月16日
在Python中使用SpaCy进行文本分类
专知
24+阅读 · 2018年5月8日
干货 | Python 爬虫的工具列表大全
机器学习算法与Python学习
10+阅读 · 2018年4月13日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
推荐|Python库中Top10 的AI项目(星级3k+),赶紧收藏!
全球人工智能
10+阅读 · 2018年1月16日
Python3爬虫之入门和正则表达式
全球人工智能
7+阅读 · 2017年10月9日
A Modern Introduction to Online Learning
Arxiv
19+阅读 · 2019年12月31日
Heterogeneous Deep Graph Infomax
Arxiv
12+阅读 · 2019年11月19日
Arxiv
3+阅读 · 2019年3月15日
Arxiv
7+阅读 · 2018年1月30日
VIP会员
相关VIP内容
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
257+阅读 · 2020年6月10日
【Manning新书】现代Java实战,592页pdf
专知会员服务
98+阅读 · 2020年5月22日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
【哈佛《CS50 Python人工智能入门》课程 (2020)】
专知会员服务
109+阅读 · 2020年4月12日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
20+阅读 · 2019年11月7日
MIT新书《强化学习与最优控制》
专知会员服务
270+阅读 · 2019年10月9日
相关资讯
GitHub 热门:Python 算法大全,Star 超过 2 万
Python开发者
9+阅读 · 2019年4月27日
GitHub 热门:各大网站的 Python 爬虫登录汇总
机器学习算法与Python学习
9+阅读 · 2019年3月20日
34个最优秀好用的Python开源框架
专知
9+阅读 · 2019年3月1日
Python用法速查网站
Python程序员
17+阅读 · 2018年12月16日
在Python中使用SpaCy进行文本分类
专知
24+阅读 · 2018年5月8日
干货 | Python 爬虫的工具列表大全
机器学习算法与Python学习
10+阅读 · 2018年4月13日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
推荐|Python库中Top10 的AI项目(星级3k+),赶紧收藏!
全球人工智能
10+阅读 · 2018年1月16日
Python3爬虫之入门和正则表达式
全球人工智能
7+阅读 · 2017年10月9日
Top
微信扫码咨询专知VIP会员