其实网上已经有不少帖子和代码了,但是网上的版本往往会缺少几个英雄。通过requests访问https://pvp.qq.com/web201605/herolist.shtml,解析内容后获取的英雄比实际的要少。理论上有99个,但是我试验下来只有93个。通过浏览器的开发者工具,发现第一次访问herolist.shtml的确只加载了93个。如果用selenium的话肯定能解决,但是不想搞这么麻烦。通过观察,可以通过herolist.json获得全部英雄的信息。不过这里有个问题,skin_name字段提供的皮肤列表不完整,有的英雄就没有这个字段。怎么办?没关系,ename是英雄id,我们可以打开每个英雄的页面去获取皮肤信息。
注意,因为requests在获取页面时没有动态的执行js,所以获得的内容与在浏览器中有差别。根据css路径'ul.pic-pf-list.pic-pf-list3'找到皮肤列表后,不要去看列表元素,都是空的,因为浏览器里的内容是动态生成额度。根据'data-imagename'字段可以知道有几个皮肤,拆分一下拼字符串就可以了。感谢鹅厂,这里处理比较简单,注意第一张皮肤是从1开始而不是0。
以下是全部代码
import json
import os
import requests
import time
from bs4 import BeautifulSoup
user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
headers = {'user-agent': user_agent}
hero_prefix = 'https://pvp.qq.com/web201605/herodetail/'
skin_prefix = 'http://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/'
def get_heroes():
data_url = 'https://pvp.qq.com/web201605/js/herolist.json'
r = requests.get(data_url, headers)
return json.loads(r.text)
def process_hero(hero):
hero_id = str(hero['ename'])
hero_name = hero['cname']
if not os.path.isdir(hero_name):
os.mkdir(hero_name)
hero_url = hero_prefix + hero_id + '.shtml'
r = requests.get(hero_url, headers)
text = r.text.encode('iso-8859-1').decode('gbk')
soup = BeautifulSoup(text, 'html5lib')
skins = soup.select('ul.pic-pf-list.pic-pf-list3')[0].get('data-imgname').split('|')
for i in range(len(skins)):
img_url = skin_prefix + hero_id + '/' + hero_id + '-bigskin-' + str(i + 1) + '.jpg'
r = requests.get(img_url, headers)
with open(hero_name + '/' + skins[i] + '.jpg', 'wb+') as f:
f.write(r.content)
print(hero_name + '有' + str(len(skins)) + '张皮肤')
if __name__ == '__main__':
heroes = get_heroes()
for hero in heroes:
process_hero(hero)
time.sleep(1)