- ajax的get请求
该案例为请求电影的第一页,前几步和之前一样
url = 'https://movie.douban.com/j/chart/top_list?type=17&interval_id=100%3A90&action=&start=0&limit=20'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76'}
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
此时需要将数据下载到本地,将文件下载到本地可以用以下方法
fp = open('douban.json','w')
fp.write(content)
但是会出现报错:UnicodeEncodeError: 'gbk' codec can't encode character '\xf8' in position 8546: illegal multibyte sequence
后经了解得知是因为保存的数据有中文,所以保存的时候需要将数据编码
fp = open('douban.json','w',encoding='utf-8')
- 案例:请求豆瓣电影前十页数据
①首先将该过程封装成函数,先写主函数,从键盘输入起始和结束页码,此步要注意的是input方法返回值是字符串类型,要转成整型
start_page = int(input('请输入起始页码'))
end_page = int(input('请输入结束页码'))
②因为要遍历1~10页,所以需要用到for page in range结构,又因为每一页都要经历请求对象定制、获得响应数据、下载数据三步,所以需要在此结构下定义一个方法,使每一页都有自己请求对象的定制,即create_request(),随后写改方法
该方法的重点在于每一页的url不同,需要找到规律,而url里有两个参数,由于请求方法为get请求,参数只需urlencode拼接而不用如post请求传入参数,由于其中的start参数和page页码有关,因此可以将for page in range结构中的page作为参数传递给create_request()方法,即create_request(page)
def create_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=17&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 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76'}
request = urllib.request.Request(url=url,headers=headers)
③接下来就是获得响应数据,定义get_content()方法,response = urllib.request.urlopen(),由于urlopen()中需要传进request参数,所以需要request返回值,即在create_request()函数添加一步return request将request返回,并将其接收,再将其传给get_content()方法,最后get_content()方法中就可以调用request
request = create_request(page)
content = get_content(request)
④最后下载数据,定义down_load()方法,因为所下载的文件名不能一致,所以可以传入page参数实现以下操作,又因为保存的数据有中文,所以保存的时候需要将数据编码,加上encoding='utf-8'
fp = open('douban_' + page + 'json','w',encoding='utf-8')
然后fp.write()写入内容content,但该函数中没有此参数,所以需要在get_content()函数的最后一步添加return content将其返回,并经其接收,再将content传给down_load()方法,最后down_load()方法就可以调用content
down_load(page,content)
def down_load(page,content):
fp = open('douban_' + page + 'json','w',encoding='utf-8')
fp.write(content)
运行结果出现错误,原因在于字符串拼接时,两端必须是str型,而page为整形,所以需将page转换为字符串型:str(page)
fp = open('douban_' + str(page) + 'json','w',encoding='utf-8')
def create_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=17&interval_id=100%3A90&action=&'
data = {
'start':(page-1)*20,
'limit':20
}
data = urllib.parse.urlencode(data)
url = base_url + data
#此处出现一个问题:AttributeError: 'tuple' object has no attribute 'items' 解决方法是headers格式错误,{}后加了个,
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76'}
request = urllib.request.Request(url=url,headers=headers)
return request
def down_load(page,content):
fp = open('douban_' + str(page) + 'json','w',encoding='utf-8')
fp.write(content)
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return 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)
最后成功
*注:使用Ctrl+alt+L可以方便转换格式便于查看
- Ajax的post请求
此案例为请求肯德基官网餐厅位置
当点开检查,Headers往下看到X-Requested-With:XMLHttpRequest,这是ajax的核心对象,此时可以知道这是一个ajax请求,查看Request URL和From DATA可以找到每页的规律,然后其他步骤和上个案例基本一致。
需要注意的是data的格式为字典,其中参数需要加上'',并且页码的不同取决于pageIndex,因此可以将page参数传入create_request()方法。
且post请求参数必须要转换成Unicode编码拼接,并在Request()传入data参数
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 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76'}
request = urllib.request.Request(url=base_url,headers=headers,data=data)
return request
全部代码如下
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 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76'}
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):
fp = open('kfc_' + str(page) +'.json','w',encoding='utf-8')
fp.write(content)
if __name__ == '__main__':
start_page = int(input('请输入起始页码'))
end_page = int(input('请输入结束页码'))
for page in range(start_page,end_page):
requset = create_request(page)
content = get_content(requset)
down_load(page,content)
*注:在手打代码过程中我出现了一个混淆decode和encode的问题,主要原因还是对其理解的不清楚,随后查阅了他们的区别如下:decode就是把二进制数据 (bytes)转化成人看的懂得英文或者汉字 (decode用的比较多) ,encode的作用是将unicode编码的字符串编码成二进制数据
- urllib异常
一般会出现两种报错,一种是HTTPError,另一种是URLError。
出现URLError一般为①网络没有连接、②服务器连接失败、③找不到指定的服务器(主机地址或参数出现问题)
出现HTTPError则可以根据返回对应的状态码知道http具体状态
异常格式如下(首先要导入urllib.error包)
try:
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
except urllib.error.HTTPError:
print('系统正在升级')
except urllib.error.URLError:
print('系统正在升级,请稍后再试')