Python零基础之爬取王者荣耀官方网站高清壁纸
目标:
- 1.下载王者荣耀网站游戏壁纸的高清壁纸
- 2.把同一个名称的壁纸放到同一个文件夹
分析过程:
1. 确定目标url
-
访问https://pvp.qq.com/web201605/wallpaper.shtml
-
发现图片地址并不在网页html源码中,检查浏览器,分析network。发现目标url有可能是:
- https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=0&iOrder=0&iSortNumClose=1&jsoncallback=jQuery17105576461901361978_1597489598391&iAMSActivityId=51991&everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&=1597489758464
-
删掉&jsoncallback回调函数部分的内容,此时可以返回json数据
-
所以目标url就是这个
- https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page=0&iOrder=0&iSortNumClose=1&iAMSActivityId=51991&everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&=1597489758464
-
通过json.cn格式化代码,发现其中含有jpg的地址信息
-
如:
- “http%3A%2F%2Fshp%2Eqpic%2Ecn%2Fishow%2F2735081209%2F1597196301%5F84828260%5F17286%5FsProdImgNo%5F1%2Ejpg%2F200”
-
http地址经过了编码,需要解码还原jpg地址
-
同时发现’sProdName’对应的为图片名称,也需要解码
2. 解决url解析问题
- 尝试利用urllib里边的parse.unquote解码地址
from urllib import parse
base_url = "http%3A%2F%2Fshp%2Eqpic%2Ecn%2Fishow%2F2735081209%2F1597196301%5F84828260%5F17286%5FsProdImgNo%5F1%2Ejpg%2F200"
# 解析url
url = parse.unquote(base_url,encoding='utf-8')
print(url)
- 输出为:
http://shp.qpic.cn/ishow/2735081209/1597196301_84828260_17286_sProdImgNo_1.jpg/200
3. 图片下载解析
- 注意到/200都是缩略图,大图需要改成/0
http://shp.qpic.cn/ishow/2735081209/1597196301_84828260_17286_sProdImgNo_1.jpg/0
4. 多页面的处理
- 爬取多页需要修改url的&page参数,第一页默认0,以此类推
代码示例
import requests
from urllib import parse
import os
from urllib import request
# 添加请求头U-A和referer,避免反爬
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
'referer': 'https://pvp.qq.com/web201605/wallpaper.shtml'}
# 定义一个函数来获取每张图片的url
def extract_images(data):
image_urls = []
for x in range(1, 9):
# 每组图片共8张,通过这种方式获取一组照片的所有地址
# 通过.unquote解码地址,并且替代末尾的'200'为'0'
image_url = parse.unquote(data['sProdImgNo_%d' % x]).replace('/200', '/0')
image_urls.append(image_url)
return image_urls
def page_url_list(base_url):
page_urls = []
for i in range(23):
base_page_url = base_url.format(
str(i))
page_urls.append(base_page_url)
# print(page_urls)
return page_urls
def main():
# 确认页面url地址
base_url = 'https://apps.game.qq.com/cgi-bin/ams/module/ishow/V1.0/query/workList_inc.cgi?activityId=2735&sVerifyCode=ABCD&sDataType=JSON&iListNum=20&totalpage=0&page={}&iOrder=0&iSortNumClose=1&iAMSActivityId=51991&_everyRead=true&iTypeId=2&iFlowId=267733&iActId=2735&iModuleId=2735&_=1597489758464k'
page_urls = page_url_list(base_url)
for page_url in page_urls:
resp = requests.get(page_url, headers=headers)
# 获取的是一个json类型的字符串
# print(resp.text)
# 可以通过.json()直接处理,替代json.loads()
# print(type(resp.json()),resp.json())
# 返回的是一个字典,可以通过K-V取值
result = resp.json()
datas = result['List']
for data in datas:
# 通过图片地址处理函数处理列表数据
image_urls = extract_images(data)
# 获取图片的名称,由于要按照文件名创建目录,所以要对空格进行处理
name = parse.unquote(data['sProdName']).strip()
# print('-' * 70)
# print(name)
# print('-' * 70)
# print(image_urls)
# print('-' * 70)
# 先创建一个用来存放image的主目录
# 当文件夹不存在时创建,当存在时跳过
if os.path.exists('./image') == False:
os.mkdir('image')
else:
pass
# 创建一个文件夹./image/name/
# 创建路径
dirpath = os.path.join('image',name)
# 按照路径创建文件夹
os.mkdir(dirpath)
# 下载图片
# 注意index索引值写前边
for index,image_url in enumerate(image_urls):
# request.urlretrieve(,)传参地址和路径,就可以保存图片
# 每个图片的地址是不同的,按照保存路径,图片名称,和索引+1以及文件类型名称的路径保存
request.urlretrieve(image_url,os.path.join(dirpath,name+'%d.jpg' % (index + 1)))
print(name,'%s下载成功' % image_url)
if __name__ == '__main__':
main()
需要注意的问题:
- url分析时,找到对应url后,需要根据反馈结果在www.json.cn查看是否能够正常解析
- 发现图片地址格式和图面名称不正常,可以通过urllib.parse.unquote()解码成正常数据
- 图片地址修改时,不能只把200改成0,要防止url地址中出现200,所以改/200为/0出错的可能性会更小一点。当然也可以通过re正则从后端匹配修改,会更为稳妥
- 文件名中如果有空格,创建文件夹会报错,所以要用strip()处理; 文件名可能还有全角字符等,也需要进行处理(代码中未写全角字符的处理)
- 文件路径可以通过引入os,利用os.path.join()链接路径
- 文件夹创建使用os,mkdir(),可以利用os.path.exists()判断文件夹是否存在,如果不存在再创建,可以避免文件夹已存在的错误
- 多页的数据获取可以尝试修改&page=的数值
- 图片下载使用urllib.request.urlretrieve()比较简介只需要传入url和存储地址(含文件名)就可以了
- 图片保存的文件名可以利用enumerate()里的index值作为后缀添加;注意不要遗漏文件类型(本文为.jpg)
10.存储过程中,还要注意,如果url中有多个地址重复,保存时会提示文件已存在时无法创建文件等错误,还可以加入异常处理,或者文件是否存在的判断等(代码示例中不含该部分代码)