urllib库的常用参数
- urllib.requeset.Request: 能够携带参数向服务器发起请求
- urllib.request.urlopen: 向服务器发起请求并获取服务器响应
- urllib.parse: 转换编码格式
模拟客户端向百度发起请求
import urllib.parse
import urllib.request
# 定义基础得网址
base_url = "https://www.baidu.com"
# 向服务发起请求并获得响应
req = urllib.request.urlopen(base_url)
# 转换编码格式读出index.html文件
res = req.read().decode('utf-8')
print(res)
如上,我们并不能获取完整的网页源代码,因为百度会是别为程序的发起的请求,故我们需要需要携带请求头,这也是最基本的反反盘设置,这时我们就需要用到urllib.requeset.Request这个模块,因为这个模块能够携带请求头发起请求,当然后续也会用第三方库的requests模块。
# 添加headers访问
import urllib.request
base_url = 'https://www.baidu.com/'
# 定义headers
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
}
# 携带请求头发起请求
req = urllib.request.Request(base_url,headers=headers)
# 获取服务器响应结果
res = urllib.request.urlopen(req)
# 读取index.html文件
html = res.read().decode('utf-8')
print(html)
这样我们就能利用urllib.requeset.Request模块获取完整的网页源代码,接下来我们看下百度搜索网页的带参数的网址如下:
https://www.baidu.com/s?wd=XXX,wd后面的就是我们搜索的内容,那我们来看下面这一段代码
import urllib.request
base_url = 'https://www.baidu.com/s?wd=美女'
res = urllib.request.urlopen(base_url)
print(res)
#程序运行报错,报错的提示如下
UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-11: ordinal not in range(128)
出现上面这个问题的原因在我们携带中文参数发起请求的时候,会出现编码格式的问题,出现类似于这样的情况我们可以利用urllib.parse模块去解决,如下:
import urllib.request
import urllib.parse
# 当我们发起请求的网址带有中文网址的时候会出现编码问题,如下:
base_url = 'https://www.baidu.com/s?wd=美女'
# 解决办法,先将中文字符编码,再发起请求
wd = {'wd': "美女"}
code = urllib.parse.urlencode(wd)
# 进行字符串的拼接,实现最终编码过的网址
url = 'https://www.baidu.com/s?' + code
# 设置请求头信息
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
}
# 携带请求头向服务器发起请求
req = urllib.request.Request(url,headers=headers)
# 获取服务器响应
res = urllib.request.urlopen(req)
# 解码index.html文件
html = res.read().decode('utf-8')
# 保存文件到本地
with open('text.html','w',encoding='utf-8') as obj:
obj.write(html)
当使用urllib.parse.urlencode()去进行格式转换的时候是字典,urllib还可以使用urllib.parse.quote()去转换,quote接受的是字符串参数,这个有兴趣的可以自己去试试。接下来我们来看下一个例子:
#'http%3A%2F%2Fshp%2Eqpic%2Ecn%2Fishow%2F2735041519%2F1618485629%5F84828260%5F22420%5FsProdImgNo%5F1%2Ejpg%2F200'
#这是一张王者荣耀的图片地址,遇到这种情况的话我们该如何去解决呢,如下:
hero_url = 'http%3A%2F%2Fshp%2Eqpic%2Ecn%2Fishow%2F2735041519%2F1618485629%5F84828260%5F22420%5FsProdImgNo%5F1%2Ejpg%2F200' # 图片的url
# 很明显上面的网址不能够直接访问,那么我们可以通过unquote去将网址转换成网站能够正常访问的地址,再进行下一步操作。
img_url = urllib.parse.unquote(hero_url)
# 得到正常访问的网址
print(img_url)
百度贴吧小练习
#https://tieba.baidu.com/f?kw=%E5%9C%B0%E4%B8%8B%E5%9F%8E%E4%B8%8E%E5%8B%87%E5%A3%AB&ie=utf-8&pn=0
# https://tieba.baidu.com/f?kw=%E5%9C%B0%E4%B8%8B%E5%9F%8E%E4%B8%8E%E5%8B%87%E5%A3%AB&ie=utf-8&pn=50
# https://tieba.baidu.com/f?kw=%E5%9C%B0%E4%B8%8B%E5%9F%8E%E4%B8%8E%E5%8B%87%E5%A3%AB&ie=utf-8&pn=100
# 通过分析和观察发现根据贴吧的页数不同,pn后面的值也会随之发生变化,并且一也得变化值为50,这样我们就可以利用for循环进行翻页的爬取。
import urllib.request
import urllib.parse
#设置请求头
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.72 Safari/537.36'
}
# 获取用户需求
user_key=input("请输入你要爬取的关键词:")
start=int(input("请输入开始的页数:"))
end=int(input("请输入结束的页数: "))
# 设置基础网址
base_url = "https://tieba.baidu.com/f?"
# 转换编码格式
base_kw = {"kw":user_key}
kw = urllib.parse.urlencode(base_kw)
for i in range(start,end+1):
#对网址进行拼接
url = base_url + kw + '=utf-8&pn=' + str((i -1)* 50)
print(url)
req = urllib.request.Request(url,headers=headers)
res = urllib.request.urlopen(req)
#读取数据
html = res.read().decode('utf-8')
filename = str(i) + '.html'
#保存数据
with open(filename,'w',encoding='utf-8') as f:
print("正在爬取第%s页" % i )
f.write(html)