目录
I.urllib库实战之GET请求:获取并下载电影平台指定页码的数据到本地
II.urllib库实战之POST请求:获取并下载餐饮实体店指定页码的店铺位置数据到本地
I.urllib库实战之GET请求:获取并下载电影平台指定页码的数据到本地
第一个实战是利用urllib库获取电影平台指定页码范围的电影基本信息数据并下载到本地(先声明所有数据都是合规且公开的,可以爬取),该实战是对GET请求处理的复习。下面分步骤介绍该实战:
1️⃣ 首先,我们打开某电影平台,随便选一类电影类型,并按F12做网页检查以查找接口:
通过一些检查,最终锁定接口在top_list?type=5这一项中(可以点击preview查看,会发现里面有对应的电影信息),于是我们拿到了接口。此时回顾GET请求的特点,我们知道GET请求的参数是拼接在url字符串上的,于是我们尝试观察该请求的url:
start=20&limit=20
于是我们再次滚动鼠标滑到下一页电影的展示页面,查看下一个top_list?type=5的url:
start=40&limit=20
通过比较,每一个url中只有参数start的值在变化,于是我们可以通过修改start以完成我们的目标:获取指定页面范围的数据。
2️⃣ 接下来我们进行模块化coding:首先我们定义一个程序的入口,并调用我们的一些函数(虽然现在还没有定义和实现这些函数):
if __name__ == '__main__':
start_page = int(input('请输入起始页码'))
end_page = int(input('请输入结束页码'))
for page in range(start_page,end_page + 1):
# 每一页都有自己的请求对象定制
create_request(page)
# 获取响应的数据
get_content()
# 下载数据
down_load()
三个函数分别实现了请求对象的定制、获取响应数据并下载数据三个功能,下一个步骤开始实现这些功能。
3️⃣ 此时我们根据之前分析的url拼接start参数的变化特征,得到这个关系式:
start参数 = (page - 1) * 20
于是根据这个关系式,我们先对create_request(page)函数进行实现:
def create_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'
data = {
'start' : (page - 1)*20,
'limit' : 20
}
data = urllib.parse.urlencode(data)
url = base_url + data
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}
request = urllib.request.Request(url = url,headers = headers)
return request
上面的这个函数完成了对GET请求的请求对象定制,其中包含了对GET请求爬虫方法的复习:多个参数的转码、参数的拼接等。注意最后函数返回了request对象,这个对象将作为下一个函数的传参。
4️⃣ 接下来定制的请求对象要被用作模拟浏览器向服务器发起请求并获取响应上,并开始实现第二个函数get_content()。之前提到从create_request()函数获得了返回参数request,于是我们此时将request作为传参传入get_content(),并微调程序入口的部分代码如下:
request = create_request(page)
# 获取响应的数据
get_content(request)
而后开始书写get_content(request)函数以模拟请求并获取请求响应:
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
这个函数比较简单,也是之前的知识点,即调用urllib库的urlopen()函数并模拟发起请求,最后获取请求并转码。注意最后返回了content,这是因为后面要把content写入本地文件并保存。
5️⃣ 最后一步:定制我们的下载函数down_load(page,content),这个函数如下:
def down_load(page,content):
with open('.\douban\douban_' + str(page) + '.json','w',encoding = 'utf-8') as fp:
fp.write(content)
大家自己试的时候要修改一下下载路径,这里要补充说明一下:
with open(参数1,参数2,参数3) as 变量名:
fp.write() / fp.read()
这是文件操作的另一种模式,与之前笔记中的模式不同,它的好处是我们不需要去手动关闭文件,第一个参数代表文件的路径,第二个是对文件的操作模式,第三个是编码格式。另外这里一定要修改编码的格式为utf-8,因为我们获取的内容已经用utf-8进行了转码,如果不用强制转码时,默认的转码格式是gbk,这会导致报错:
同时可以看到down_load()函数传入了参数page,这是为了分别保存所有指定的页面的数据到不同的文件的一种策略。
最后补充说一下,我们保存的格式是.json,这是因为我们获取的数据本身是以json格式返回的,保存为json文件是对内容的保护。
6️⃣ 全部完成后,我们运行代码,输入起始页码和终止页码,即可获取指定的数据并下载到本地保存为json文件:
7️⃣ 完整的代码:
import urllib.request
import urllib.parse
def create_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'
data = {
'start' : (page - 1)*20,
'limit' : 20
}
data = urllib.parse.urlencode(data)
url = base_url + data
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}
request = urllib.request.Request(url = url,headers = headers)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(page,content):
with open('.\douban\douban_' + str(page) + '.json','w') as fp:
fp.write(content)
# # 程序的入口
if __name__ == '__main__':
start_page = int(input('请输入起始页码'))
end_page = int(input('请输入结束页码'))
for page in range(start_page,end_page + 1):
# 每一页都有自己的请求对象定制
request = create_request(page)
# 获取响应的数据
content = get_content(request)
# 下载数据
down_load(page,content)
II.urllib库实战之POST请求:获取并下载餐饮实体店指定页码的店铺位置数据到本地
第二个实战是利用urllib库获取餐饮平台KFC指定页码范围的实体店地址等数据并下载到本地(先声明所有数据都是合规且公开的,可爬取),该实战是对POST请求处理的复习。下面分步骤介绍该实战:
1️⃣ 首先还是一样的,我们先找一找接口,方法还是一样的,我们此时先进入KFC的官网,并搜寻它的实体店位置,随便选择一个省份:
这个实战以北京为例,我们还是按F12开启网页检查模式,对接口进行检查:
这个例子找接口比较简单,检查后只有一个项,而这个项里包含了我们需要的接口。此时回忆POST请求的处理,它的参数并不是在url上拼接,而是通过对参数进行编码和转码两道工序后直接传入请求对象定制中,于是我们点击payload,查看它的参数是什么样的:
很明显只有这四个参数,于是我们复制这些参数并先保存到注释中,并按照之前上一个实战的思路滑动鼠标,点击下一页查看参数,发现只有一个参数的值在变化:pageIndex,而且这个值与当前的页码一致,于是提供了请求对象定制的思路。
2️⃣ 接下来同样开始进行模块化coding,首先定义程序的入口:
if __name__ == '__main__':
start_page = int(input('起始页码:'))
end_page = int(input('结束页码:'))
for page in range(start_page,end_page + 1):
# 请求对象定制
create_request(page)
# 获取网页源码
get_content()
# 下载
down_load()
接下来逐个实现每一个函数。
3️⃣ 此时完成请求对象的定制,按照我们之前的思路,参数 pageIndex = page,于是我们可以实现函数create_request(page):
def create_request(page):
base_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
data = {
'cname' : '北京',
'pid' : '',
'pageIndex' : page,
'pageSize' : '10'
}
data = urllib.parse.urlencode(data).encode('utf-8')
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}
request = urllib.request.Request(url = base_url,headers = headers,data = data)
return request
我们把参数pageIndex的值用变量page替代,同时data参数进行了两步工序,最后传入,这些是对POST处理的复习。
4️⃣ 下面是实现get_content(request)函数,首先还是先修改程序入口,把request先通过函数create_request()返回,而后把这个request对象传入本函数,并开始实现函数:
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
通过对比上一个实战可以发现,这一步是完全相同的,这与我们之前笔记总结的post和get的区别不在这里是契合的。
5️⃣ 最后一步是下载文件到本地,这一步也和上一个实战相同:
def down_load(page,content):
with open('./kendeji/kfc_' + str(page) + '.json','w',encoding='utf-8') as fp:
fp.write(content)
6️⃣ 最后附上完整的该实战源码(记得修改路径):
import urllib.request
import urllib.parse
def create_request(page):
base_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
data = {
'cname' : '北京',
'pid' : '',
'pageIndex' : page,
'pageSize' : '10'
}
data = urllib.parse.urlencode(data).encode('utf-8')
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}
request = urllib.request.Request(url = base_url,headers = headers,data = data)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(page,content):
with open('./kendeji/kfc_' + str(page) + '.json','w',encoding='utf-8') as fp:
fp.write(content)
if __name__ == '__main__':
start_page = int(input('起始页码:'))
end_page = int(input('结束页码:'))
for page in range(start_page,end_page + 1):
# 请求对象定制
request = create_request(page)
# 获取网页源码
content = get_content(request)
# 下载
down_load(page,content)