少女祈祷中...

(更新动图)Python爬虫-pixiv关注画师作品[3]


本篇概述:第二篇的续作,主要是各种图片类型的下载和文件夹创建;

github地址、文中代码不一定能直接执行,粘贴过来可能缩进有问题。


1、分析——如何判断类型?

单图 ↓

多图 ↓

动图


仔细观察就会发现:

  1. 单图 url : 56309403_p0_square1200.jpg,有p0;pageCount:1
  2. 多图 url : 56527887_p0_square1200.jpg,有p0;pageCount:3
  3. 动图 url : 57027347_square1200.jpg,无p0;pageCount:1

2、代码——匹配类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def painter_picture(self):
'''
上次的code
'''
if pageCount == 1:
# 有p0
# 2016/05/23/19/25/26/57027442_p0
# 无p0
# 2016/05/23/19/18/47/57027347
if small_url[51:-15][-2:] == 'p0':
print('作品类型:单图\n')
self.img_single(small_url,folder_path,folder_id) # 单图
else:
print('作品类型:动图\n')
self.img_gif(folder_path,folder_id) # 动图
else:
print('作品类型:多图\n')
self.img_multi(small_url,folder_path,folder_id,pageCount) # 多图

PS:拼接 url 时不要问为啥这么麻烦,看这里

  1. 本篇记录的是自己刚学python爬虫第一个爬虫项目的代码,这篇的代码可以说是仅仅是为了实现功能写出来的。
  2. 现在也有想法要重构,重构好之后发篇完整的出来,不过没有那么快而已。
  3. 现在找到了作品的详细信息接口,后面再更新了,这里用的是之前的方法。
  4. 回首看自己2个月前的代码,一点都不优雅。o(╥﹏╥)o

3、分析——创建画师文件夹及作品文件夹

  1. 首先指定一个下载目录
  2. 下载目录下为每个画师创建一个文件夹,形如:{id}–{name}
  3. 画师文件夹下为每个作品创建一个文件夹,形如:{id}

4、代码——文件夹

1、创建画师文件夹

此处解决了画师更改名字,会导致该画师所有作品重下。

具体看代码吧,解释也挺麻烦的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 执行 mkdir_painter() 应在 attention_html() 的 painter_information 循环中
# self.father_folder = self.mkdir_painter(painter_id,name)
def mkdir_painter (self,painter_id,name):
name = re.sub('[\/:*?"<>|]','_',name)
folder_name = painter_id + '--' + name
# 画师改名字!会导致重下
for folder in os.listdir(self.path):
if painter_id == folder.split('--')[0]:
print(u'[名字叫{0}文件夹已存在!]'.format(folder_name))
father_folder = os.path.join(self.path,folder)
os.chdir(father_folder) ##切换到目录
return father_folder

print(u'[建了一个{0}文件夹!]'.format(folder_name))
father_folder = os.path.join(self.path,folder_name)
os.makedirs(father_folder)
os.chdir(father_folder) ##切换到目录
return father_folder

2、创建作品文件夹

1
2
3
4
5
6
7
8
9
10
11
12
13
def mkdir_works(self,folder_id):
folder_path = os.path.join(self.father_folder,folder_id)
isExists = os.path.exists(folder_path)

if not isExists:
print(u'\n[在',self.father_folder,'下建了一个', folder_id, u'文件夹!]')
os.makedirs(folder_path)
os.chdir(folder_path) ##切换到目录
return folder_path
else:
print(u'\n[在',self.father_folder,'下已经有', folder_id, u'文件夹!]')
os.chdir(folder_path) ##切换到目录
return folder_path

5、单图下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def img_single(self,small_url,folder_path,folder_id):
work_name = folder_id + small_url[-4:]
# p站的图片有jpg和png的,但是从works_url获取到的只有小图jpg的url
jpg_judge_path = folder_path + '\\' + work_name
png_judge_path = folder_path + '\\' + folder_id + '.png'
# 判断是否是上次因为jpg不行而下载png的图片,如果是的话,expand_name 用 .png 替换进行比对是否重复
if os.path.exists(jpg_judge_path) == True and os.path.getsize(jpg_judge_path) != 58:
# 判断jpg
print(jpg_judge_path,'已存在且字节数不为58!')
else:
if os.path.exists(png_judge_path) == True and os.path.getsize(png_judge_path) != 58:
# 判断png
print(png_judge_path,'已存在且字节数不为58!')
else:
try:
small_date = small_url[51:-15] #动图的small_url没有p0
head = 'https://i.pximg.net/img-original/img/'
img_url = head + small_date + small_url[-4:] #.jpg
img_html = self.request(img_url)
self.down(img_html,work_name,jpg_judge_path)
# time.sleep(2)
if os.path.getsize(jpg_judge_path) == 58:
print('{}格式不对,准备重下'.format(work_name))
img_url = head + small_date + '.png'
img_html = self.request(img_url)
self.down_conversion(img_html,folder_id,jpg_judge_path,png_judge_path)
except:
print(work_name,'下载失败')

6、多图下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def img_multi(self,small_url,folder_path,folder_id,pageCount):
for img_num in range(0,pageCount):
work_name = folder_id + '-' + str(img_num) + small_url[-4:]
jpg_judge_path = folder_path + '\\' + work_name
if os.path.exists(jpg_judge_path) == True and os.path.getsize(jpg_judge_path) != 58:
print(jpg_judge_path,'已存在且字节数不为58!')
else:
multi_url = 'https://www.pixiv.net/member_illust.php?mode=manga_big&illust_id=' +folder_id + '&page=' + str(img_num)
self.headers['User-Agent'] = random.choice(self.user_agent_list)
try:
multi_html = self.request(multi_url)
multi_html_soup = BeautifulSoup(multi_html.text, 'lxml')
img_url = multi_html_soup.find('img')['src'] #要请求src的地址再写入
img_html = self.request(img_url)
self.down(img_html,work_name,jpg_judge_path)
except:
print(work_name,'下载失败')

7、动图

P站动图其实只是多个图片设置页面停留时间而已,所以需要我们手动合成。

1.在动图的源文件地址(是个 zip 文件),里面有关于每个图片的 delay (也就是页面停留时间)和图片文件。
2.下载 zip,解压,用 imageio 进行合成,指定合成 gif 的帧率为 delay 就行了

但是存在一个问题,有些动图的每个图片设置的页面停留时间不同,这就让人很难搞了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import imageio
# from PIL import Image
# 记得没有用到PIL,但防止意外,我就先放这里了

# 获取压缩包网址
zip_url = 'https://www.pixiv.net/ajax/illust/' +folder_id + '/ugoira_meta
zip_html = self.request(zip_url
zip_json = json.loads(zip_html.text)
zip_originalSrc = zip_json["body"]["src"]
# 计算帧率
delay = 1/(zip_json["body"]["frames"][0]['delay']/1000) #80(ms)/1000 -> 0.08(s)
print('帧率:',delay)
# 下载zip
headers['Referer'] = 'https://www.pixiv.net/member_illust.php?mode=medium&illust_id=' + folder_id
gif_html = self.request(zip_originalSrc)
zip_name = folder_id + '.zip'
f = open(zip_name, 'ab')
f.write(gif_html.content)
f.close()
# 解压zip
f = zipfile.ZipFile(zip_name,'r')
for file in f.namelist():
f.extract(file,".")
f.close()
print('解压完成')
os.remove(zip_name) # 删除压缩包
gif_name = folder_id + '.gif' # gif图片name
frames = [] # 用来存储要进行合成gif的图片
files = os.listdir(folder_path) # 扫描当前作品目录下的文件
print('开始合成')
for image_num in range(1,len(files)):
frames.append(imageio.imread(files[image_num]))
imageio.mimsave(gif_name, frames, 'GIF', fps = delay) # 间隔
print(folder_id,'动图下载完成!')
# 删除解压出的图片
for file in files:
os.remove(file)

8、最后

鸽了挺久的,觉得大部分东西代码和实践都说得清楚,毕竟不是教程贴ヽ(ー_ー)ノ

github地址、文中代码不一定能直接执行,复制粘贴的。

-------------本文结束感谢您的阅读-------------

本文标题:(更新动图)Python爬虫-pixiv关注画师作品[3]

文章作者:Coder-Sakura

发布时间:2019年06月12日 - 02:03:44

最后更新:2019年10月27日 - 15:17:37

原始链接:https://coder-sakura.github.io/blog/2019/06/12/pixiv-three/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。