第二章 Urllib库的使用

文章目录

  • 第二章 Urllib库的使用
    • 2.1 基本使用
      • 2.1.1 urlopen()
      • 2.1.2 1个类型与6个方法
      • 2.1.3 data参数
      • 2.1.4 timeout参数
      • 2.1.5 Request
    • 2.2 解析链接
      • 2.2.1 urlparse()
      • 2.2.2 urlunparse()
      • 2.2.3 urlsplit()
      • 2.2.4 urlunsplit()
      • 2.2.5 urljoin()
      • 2.2.6 urllib.parse.quote()
      • 2.2.7 urllib.parse.urlencode()
      • 2.2.8 post请求01
      • 2.2.9 post请求02
    • 2.3 异常处理
      • 2.3.1 URLError
      • 2.3.2 HTTPError
    • 2.4 Urllib下载到本地
    • 2.5 Robots协议
      • 2.5.1 robotparse

第二章 Urllib库的使用

Python内置的HTTP请求库,包含如下4个模块:

  • request:它是最基本的HTTP请求模块,可以用来模拟发送请求,需要给库方法传入URL以及额外的参数
  • error:异常处理模块,如果出现错误,我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止
  • parse:一个工具模块,提供了许多URL处理方法,如拆分,解析,合并等
  • robotparser:主要用来识别网站的robots.txt文件,然后判断哪些网站可以爬,哪些网站不可以爬,一般用的比较少

2.1 基本使用

2.1.1 urlopen()

import urllib.request


# 定义一个url,待访问的网址
url = 'http://www.baidu.com'
# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)
# read()方法返回的是字节形式的二进制数据,转换成字符串要解码decode()
content = response.read().decode('utf-8')

print(content)

2.1.2 1个类型与6个方法

一、response响应是HTTPResponse类型

import urllib.request


url = 'http://www.baidu.com'
response = urllib.request.urlopen(url)
print(type(response))
结果:
<class 'http.client.HTTPResponse'>

二、6个方法

- response.read() 一个字节一个字节的读,read()方法中的数字表示返回的字节的个数
- readline() 读取一行
- readlines() 一行一行的读直到读完
- getcode() 返回状态码,是200就没毛病
- geturl() 返回的是url地址
- getheaders() 返回的是状态信息及响应头

2.1.3 data参数

如果要添加该参数,它需要被转码成字节流类型,即 bytes 类型,通过 bytes()方法转化。一旦传递了这个参数,它的请求方式不再是GET方式,而是POST方式。

2.1.4 timeout参数

timeout参数用于设置超时时间(单位:秒),支持HTTP,HTTPS,FTP请求。如果请求超出了设置的时间还没有得到响应,就会抛出异常。不指定该参数就会使用全局默认时间。

import urllib.request


url = 'http://www.baidu.com'
response = urllib.request.urlopen(url=url, timeout=0.1)
content = response.read().decode('utf-8')
print(content)

报错:
socket.timeout: timed out

2.1.5 Request

利用urlopen()可以实现最基本请求的发起,但是这些简单的参数不足以构建完整的请求。要在请求中加入Headers等信息,需要用更强大的Request类,可以查看一下该类需要的参数。

说明:

  • url参数是必传参数,其他都是可选参数
  • data参数必须传bytes(字节流)类型,如果它是字典先用urllib.parse模块的urlencode()方法编码,还要encode()编码
  • headers是一个字典,就是请求头,我们可以在构造请求时通过headers参数直接构造,也可以调用请求实例add_header()方法添加,最常用的添加请求头就是通过UA伪装
  • origin_req_host指的是请求方的host名称或者ip地址
  • unverifiable表示这个请求是否是无法验证的,默认False
  • method表示请求使用的方法,GET,POST,PUT等

第二章 Urllib库的使用_第1张图片

2.2 解析链接

urllib库中的parse模块,他定义了处理URL的标准接口,url中各部分抽取,合并,转换。

2.2.1 urlparse()

可以实现url的识别与分段

import urllib.parse


url = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%91%A8%E6%9D%B0%E4%BC%A6'
response = urllib.parse.urlparse(url)
print(type(response), response)
<class 'urllib.parse.ParseResult'> ParseResult(scheme='https', netloc='www.baidu.com', path='/s', params='', query='ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%91%A8%E6%9D%B0%E4%BC%A6', fragment='')
  • 协议(scheme)
  • 域名(netloc)
  • 路径(path)
  • 路径参数(params)
  • 查询参数(query)
  • 片段(fragment)

2.2.2 urlunparse()

与urlparse()对立的方法,接受的参数是一个可迭代的对象,长度必须是6,否则会抛出参数不足或过多。

import urllib.parse


req = ['https', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urllib.parse.urlunparse(req))
结果:
https://www.baidu.com/index.html;user?a=6#comment

2.2.3 urlsplit()

用法urlparse()用法相似,不再单独解析params部分,合并到path,返回的参数只有5个。

2.2.4 urlunsplit()

相似于urlunparse(),长度是5

2.2.5 urljoin()

urlunparse()与urlunsplit()方法可以完成链接的合并,但是需要特定的长度的对象,每一部分都要清晰分开。

urljoin()基本用法:提供一个基础链接作为参数1,新的链接作为参数2,该方法会分析两个链接中的scheme,netloc,path。将这3个部分缺失的地方补充到新连接中。

import urllib.parse


print(urllib.parse.urljoin('http://www.baidu.com', 'FAQ.html'))
结果:
http://www.baidu.com/FAQ.html

2.2.6 urllib.parse.quote()

例如模拟在百度搜索’周杰伦’时

import urllib.request


url = 'https://www.baidu.com/s?wd=周杰伦'
# 请求对象定制
headers = {
	'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
}

request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)

会报错,因为识别不了’周杰伦’

UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-12: ordinal not in range(128)

quote():汉字或者其他字符变成Unicode编码

import urllib.parse

name = urllib.parse.quote('周杰伦')
print(name)

%E5%91%A8%E6%9D%B0%E4%BC%A6

真正的url:'https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6'

当需要转码的字符较多时,用quote()就会显得特别麻烦

2.2.7 urllib.parse.urlencode()

应用场景:url中有多个参数时,以字典形式存放,如:‘https://www.baidu.com/s?wd=周杰伦&sex=男’

import urllib.parse


data = {
    'wd': '周杰伦',
    'sex': '男'
}
res = urllib.parse.urlencode(data)
print(res)

# 结果:
wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7

2.2.8 post请求01

  • post请求方式的参数必须编码,编码之后还要调用encode()编码
  • 参数放在请求对象定制的方法中

以百度翻译为例。

import urllib.request
import urllib.parse


url_page = 'http://fanyi.baidu.com/sug'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
}

data = {
    'kw': 'spider'
}

# post的请求的参数必须进行编码
data = urllib.parse.urlencode(data)
# post的请求参数不会拼接在url后面,需要放在请求对象定制的参数中
request = urllib.request.Request(url=url_page, data=data, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.

问题出在第16行,改成:

data = urllib.parse.urlencode(data).encode('utf-8')
{"errno":1000,"errmsg":"\u672a\u77e5\u9519\u8bef"}

以上的结果是一个json数据,完整代码:

import urllib.request
import urllib.parse
import json


url_page = 'https://fanyi.baidu.com/sug'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
}

data = {
    'kw': 'spider'
}

# post的请求的参数必须进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
# post的请求参数不会拼接在url后面,需要放在请求对象定制的参数中
request = urllib.request.Request(url=url_page, data=data, headers=headers)
# 模拟浏览器请求
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
# 字符串->json对象
obj = json.loads(content)
print(obj)
{'errno': 0, 'data': [{'k': 'spider', 'v': 'n. 蜘蛛; 星形轮,十字叉; 带柄三脚平底锅; 三脚架'}, {'k': 'Spider', 'v': '[电影]蜘蛛'}, {'k': 'SPIDER', 'v': 'abbr. SEMATECH process induced damage effect revea'}, {'k': 'spiders', 'v': 'n. 蜘蛛( spider的名词复数 )'}, {'k': 'spidery', 'v': 'adj. 像蜘蛛腿一般细长的; 象蜘蛛网的,十分精致的'}]}

2.2.9 post请求02

用edge浏览器在Headers中找不到Form Data数据,可能是放在Payload中

第二章 Urllib库的使用_第2张图片

百度翻译中有一种详细翻译

import urllib.request
import urllib.parse
import json


url = 'https://fanyi.baidu.com/v2transapi?from=en&to=zh'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
}

Data = {
    'from': 'en',
    'to': 'zh',
    'query': 'love',
    'transtype': 'enter',
    'simple_means_flag': '3',
    'sign': '198772.518981',
    'token': '65e4e8433224437143da6972871e94fc',
    'domain': 'common'
}
data = urllib.parse.urlencode(Data).encode('utf-8')

request = urllib.request.Request(url=url, data=data, headers=headers)
# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')

obj = json.loads(content)
print(obj)
{'errno': 997, 'errmsg': '未知错误', 'query': 'lo', 'from': 'en', 'to': 'zh', 'error': 997}

请求头种的参数是真实浏览器发送请求时携带的参数,把请求头中数据都放进上面第7行的headers就欧克了?但是要记得看下图第2条Accept-Encoding中没有utf-8,所以要把它干掉

第二章 Urllib库的使用_第3张图片

结果超多,不展示了,但是要找准Form Data中query对应的值是否是完整的单词,不然结果会是上面那个未知错误。

上图中起决定性作用的是Cookie,把其他参数都拖出去咔嚓掉只留下Cookie结果也一样

2.3 异常处理

urllib的error模块定义了由request模块产生的异常。

2.3.1 URLError

URLError类来自urllib库的error模块,继承自OSError类,是error异常模块的基类。由request生成的异常都可以用这个类处理。

它具有一个属性reason,即返回错误的原因。

例如打开一个不存在的网页:

from urllib import request, error

try:
    url = 'https://www.piaopiao.com'
    response = request.urlopen(url)
except error.URLError as e:
    print(e.reason)

打开如上那个不存在的页面时应该说要报错,但我们捕获了URLError这个异常,得到以下的结果。程序没有直接报错,可以避免程序异常终止,同时异常得到处理。

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'www.piaopiao.com'. (_ssl.c:1129)

2.3.2 HTTPError

HTTPError是URLError的子类,专门处理HTTP请求错误,它有3个属性:

  • code:返回HTTP状态码
  • reason:同父类一样,返回错误的原因
  • headers:返回请求头

在捕获异常的时候一般先是找子类的异常,找不到再找父类

2.4 Urllib下载到本地

**urllib.request.urlretieve()**方法直接将远程数据下载到本地

函数原型:urlretrieve(url, filename=None, reporthook=None, data=None)

  • 参数 url 指定了要下载的文件的url
  • 参数 finename 指定了保存本地路径(如果参数未指定,urllib会生成一个临时文件保存数据。)
  • 参数 reporthook 是一个回调函数,当连接上服务器、以及相应的数据块传输完毕时会触发该回调,我们可以利用这个回调函数来显示当前的下载进度。
  • 参数 data 指 post 到服务器的数据,该方法返回一个包含两个元素的(filename, headers)元组,filename 表示保存到本地的路径,header 表示服务器的响应头。
import urllib.request


url_page = 'http://www.baidu.com'
# 下载网页
urllib.request.urlretrieve(url=url_page)
# 图片,视频也阔以...

或者写入文件

2.5 Robots协议

全称网络爬虫排除标准(Robots Exclusion Protocol),也叫做爬虫协议,机器人协议。用来告诉爬虫和搜索引擎哪些网页可以爬,哪些不能爬,robots.txt一般放在网站根目录下。在域名后加上robots.txt可以查看

当搜索爬虫访问一个网站时,首先检查该网站根目录下是否有robots.txt文件,若有,会根据其中定义的爬取范围爬取;否则,会访问所有可以访问的页面

2.5.1 robotparse

查看是否有权限爬取这个网页,传入robots.txt的链接即可,或者在声明时不传入,用set_url)()方法设置

urllib.robotparse.RobotFileParser(url='')

你可能感兴趣的:(爬虫学习笔记,python,前端,开发语言,url,爬虫)