urlopen()
原型 :urlopen(url, data=None, proxies=None)
作用:创建一个表示远程url的类文件对象,然后像本地文件一样操作这个类文件对象来获取远程数据。
url:统一资源定位符,表示远程数据的路径,一般是网址;
data:表示数据提交到url的方式
proxies:用于设置代理
from urllib import request
from urllib import parse
res = request.urlopen('http://www.baidu.com')
print(res) # 返回类文件对象http.client.HTTPResponse
print(res.read().decode('utf-8'))
print(res.readline()) # 返回bytes
print(res.readlines()) # 返回list
print(res.getcode()) # 返回int状态码
print(res.geturl()) # 返回请求的url
res.close()
urlretrieve()
原型:urlretrieve(url, filename=None, reporthook=None, data=None)
作用:直接将远程数据下载到本地。
filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。
request.urlretrieve('http://www.baidu.com', 'baidu.html') # 爬取源码并保存
request.urlretrieve('https://images.unsplash.com/photo-1579102298128-754755f6087b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=600&q=60','1.jpg') # 爬取图片并保存
运行结果:
urlencode()
作用:可以把key-value这样的键值对转换成我们想要的格式,返回的是a=1&b=2这样的字符串。其中除中文,数字,部分字符外,其他的字符用%和十六进制编码
params = {'name':'刘德华', 'age':18, 'greet':'hello'}
result = parse.urlencode(params)
print("编码结果:\n",result)
运行结果:
parse_qs()
作用:将a=1&b=2这样的请求参数转成字典格式
params = {'name':'刘德华', 'age':18, 'greet':'hello'}
qs = parse.urlencode(params)
print("将字典转换为请求参数格式:\n", qs)
res = parse.parse_qs(qs)
print("将请求参数转换成字典格式:\n", res)
运行结果:
unquote()
作用:将url请求参数形式(%和十六进制编码)的字符串解码
url = 'https://www.baidu.com/s?wd=%E5%88%98%E5%BE%B7%E5%8D%8E'
print('解码结果:',parse.unquote(url))
运行结果:
urlparse() 和 urlsplit()
作用:对url按照一定格式进行拆分或拼接,获取指定参数
URL基本结构:
以下面这个URL为例,介绍下普通URL的各部分组成
http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
从上面的URL可以看出,一个完整的URL包括以下几部分:
1、协议部分:该URL的协议部分为“http:”,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。在"HTTP"后面的“//”为分隔符2、域名部分:该URL的域名部分为“www.aspxfans.com”。一个URL中,也可以使用IP地址作为域名使用
3、端口部分:跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口80
4、虚拟目录部分:从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是“/news/”
5、文件名部分:从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中的文件名是“index.asp”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名
6、锚部分:从“#”开始到最后,都是锚部分。本例中的锚部分是“name”。锚部分也不是一个URL必须的部分
7、参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“boardID=5&ID=24618&page=1”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。
参考博客:https://www.cnblogs.com/Peng-Yankee/p/9600481.html
urlsplit是拆分,而urlparse是解析,所以urlparse粒度更为细致
url = 'https://www.baidu.com/s;hello?wd=python&username=shen#1'
res1 = parse.urlparse(url) # 多一个params属性,一般用的比较少
res2 = parse.urlsplit(url)
print(res1) # urllib.parse.ParseResult
print(res2)
运行结果:
注:可以看到urlparse()的结果中多了一个params属性,urlsplit()在分割的时候,path和params属性是在一起的,其他属性完全一样
案例:爬取拉钩网数据
下面用到Request对象对服务器发起请求,这里可能有人要问了,那urlopen()可以发起请求,为什么还要创建Request对象再发起请求呢?
如果我们在获取请求对象时,不需要过多的参数传递,可以直接用urlopen()
如果需要进一步的包装请求,则需要用Request对象对请求数据进行包装处理
# 请求网址
url = 'https://www.lagou.com/message/newMessageList.json'
# 请求头信息中加入User-Agent和Referer让我们伪装的更像浏览器请求
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
'Referer': 'https://www.lagou.com/zhaopin/Python/?labelWords=label'
}
# 账户信息
data = {
'first': 'true',
'pn': 1,
'kd': 'Python'
}
# Request对象中的data必须为bytes格式
req = request.Request(url, headers=headers, data=parse.urlencode(data).encode('utf-8'), method='POST')
res = request.urlopen(req)
content = res.read()
with open('1.html', 'wb') as f:
f.write(content)
爬取结果: