Python3爬虫:爬取千张龙珠高清壁纸制成PDF浏览

今早上本来想看看Django的一些知识,做个小的实战玩玩的,结果有了下载一些龙珠高清壁纸的想法,这些壁纸真的太赞了~加上最近忍不住买了《龙珠超画集》,马上就开始了这个爬虫的进程。这个网站真的超赞啊~很多好的作品在这里分享。

爬取网站:Wallpaper Abyss - 高清壁纸, 桌面背景

本爬虫程序适合这个网站的所有的壁纸爬取~

分析过程

这个网站不是很难爬,基本上和爬静态网站一样的,难度不大。

在主页上搜索关键词“龙珠”之后,进入了壁纸页面,显示是两千多张的总数量,但是不能在主页面上直接爬,因为主页上的图片的尺寸都太小了,需要一个个的点开再到里边把正常大小的尺寸的图的真实地址爬出来,之后直接下载下来就OK了。

我用的是Chrome浏览器。

这是利用Chrome的探嗅器取得的在主页上的图片地址,尺寸太小了,不适合爬取收藏,另外它的父节点就是它的内嵌链接,即为点进去可以下载每个正常大小尺寸的图的页面。

这就是进去之后的内嵌的页面了,在主页面上的都有一个内嵌链接,点进去可提供下载正常尺寸的图片。

从上面的操作分析来看,这个网站的翻页,就是一个参数来实现的:page=num。这在写程序时可起到翻页爬取的作用,我们的目标是全部爬下来收藏~~

分享一个Chrome浏览器选择CSS选择器自动爬取的小技巧~如上,自行玩耍一般了解去吧,非常实用,省时省力。

这样就差不多分析完了,本身也没什么难度…

代码实现

以下为实现的代码:

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import requests
from urllib.parse import quote
from pyquery import PyQuery as pq
import time
from urllib.request import urlretrieve
def inlinkes(word, pages):
'''
页数页面换爬取,获得内嵌的链接,以便调用于直接爬取高清大图之用
'''
for i in range(1, pages):
# 输入要求爬取的关键词,语言默认为Chinese
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
'Connection':'keep-alive',
'Cookie':'wa_session=tmqupoqa9n72jj0cc39d3ervmmcf52ln68ro2lm44jhnii2acha6pburcqc5kt5nenla1qpitut92k6if6n3k73d66flmejvpehabj1; __cfduid=d9e4a7feea6a68864d2aa652e2e3bb4441552271424; _ga=GA1.2.222625191.1552271425; _gid=GA1.2.1439755337.1552271425',
'Host':'wall.alphacoders.com',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Upgrade-Insecure-Requests': '1'}
r = requests.get('https://wall.alphacoders.com/search.php?search=' + quote(word) + '&lang=Chinese&page=' + str(i), headers=headers, stream=True)
# 用pyquery库爬链接方式多样化,选择余地多更为方便,先获取内嵌链接,后将高清大图爬取下载下来,不然直接在页面上爬取尺寸太小
doc = pq(r.text)
inlikes = doc.find('div.thumb-container > div.boxgrid > a') # 爬取每一页的内嵌参数链接
for i in inlikes.items():
yield 'https://wall.alphacoders.com/' + i.attr('href') # 此处用到的关键词yield像流水一样有序执行每一个内嵌链接
if __name__ == '__main__':
num = 0 #作为图片取名和标号之用~
for i in inlinkes('龙珠', 92):
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
'Connection':'keep-alive',
'Cookie':'wa_session=tmqupoqa9n72jj0cc39d3ervmmcf52ln68ro2lm44jhnii2acha6pburcqc5kt5nenla1qpitut92k6if6n3k73d66flmejvpehabj1; __cfduid=d9e4a7feea6a68864d2aa652e2e3bb4441552271424; _ga=GA1.2.222625191.1552271425; _gid=GA1.2.1439755337.1552271425',
'Host':'wall.alphacoders.com',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Upgrade-Insecure-Requests': '1'}
# 制成完整的内嵌链接,接下来进入每个内嵌链接直接爬取高清图下载即可
r = requests.get(i, headers=headers, stream=True)
doc = pq(r.text)
down_link = doc.find('#page_container > div.center.img-container-desktop > a').attr('href')
down_links = requests.get(down_link) #将获取的图片地址再次解析才能转换为二进制写入文件
with open('/Users/junjieliu/Pictures/龙珠高清壁纸/' + str(num) + '.jpg', 'wb') as f:
f.write(down_links.content)
time.sleep(5)
num += 1

加上那么多的代理参数是为了防止HTTP Error 403: Forbidden的错误,但是最后还是出现了这样的错误出现,我使用函数urlretrieve依旧也有这样的问题出现,直到我发现了这篇文章:HTTP Error 403: Forbidden with urlretrieve,才解决了这样的错误,我选择过with open...的写法,但是url.content总是提示错误,原来是要在获得真实地址的情况下,再将真实地址的内容获取一遍(requests.get()),最后url.content终于也能行得通了~在这花费的时间最多…

需要注意一下的是cookies的事,这里是我的浏览器上的,可自行添加自己的浏览器上的cookies。

另外不懂我写的、我说的那就需要学习了:

一本好书,不解释。

上方的程序可将“龙珠”的关键词改为其他的(如火影忍者等),均可直接运行进行下载。

运行效果展示

速度设置了5秒钟一张的速度,基本两千多张还是需要一两个钟的….可以用多线程、多进程改写一下估计会有一些提高,自行了解吧。

速度还是有点慢的…

推荐使用Dash结合写代码

这个小东西非常多使用,不仅包含有各种许多编程语言的API可查,而且还可以直接作为搜索引擎使用,当然好处还是很多的~开发者必备!

Mac破解下载地址:https://xclient.info/s/dash.html

展示效果:

不错~

Mac上利用自带的预览自制DPF画册文件

可自行移步参考Google,百度搜索引擎

更新:多进程与异步加速爬取

妈蛋受不了了,爬两千多张图片慢的像一条狗…更新了多进程异步加速的代码。

为什么不用“多线程”?因为在Python中多线程就是个垃圾!自行了解去吧。可参考:python并发编程二三事(二)/)、Understanding the Python GILPython进程、线程、回调与协程 总结笔记 适合新手明确基本概念

多进程代码

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import requests
from urllib.parse import quote
from pyquery import PyQuery as pq
import time
from urllib.request import urlretrieve
import multiprocessing as mp
def inlinkes(word, pages):
'''
页数页面换爬取,获得内嵌的链接,以便调用于直接爬取高清大图之用
'''
for i in range(1, pages):
# 输入要求爬取的关键词,语言默认为Chinese
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
'Connection':'keep-alive',
'Cookie':'wa_session=tmqupoqa9n72jj0cc39d3ervmmcf52ln68ro2lm44jhnii2acha6pburcqc5kt5nenla1qpitut92k6if6n3k73d66flmejvpehabj1; __cfduid=d9e4a7feea6a68864d2aa652e2e3bb4441552271424; _ga=GA1.2.222625191.1552271425; _gid=GA1.2.1439755337.1552271425',
'Host':'wall.alphacoders.com',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Upgrade-Insecure-Requests': '1'}
r = requests.get('https://wall.alphacoders.com/search.php?search=' + quote(word) + '&lang=Chinese&page=' + str(i), headers=headers, stream=True)
# 用pyquery库爬链接方式多样化,选择余地多更为方便,先获取内嵌链接,后将高清大图爬取下载下来,不然直接在页面上爬取尺寸太小
doc = pq(r.text)
inlikes = doc.find('div.thumb-container > div.boxgrid > a') # 爬取每一页的内嵌参数链接
for i in inlikes.items():
yield 'https://wall.alphacoders.com/' + i.attr('href') # 此处用到的关键词yield像流水一样有序执行每一个内嵌链接
def down_pic():
num = 2888 #测试用的
for i in inlinkes('龙珠', 92):
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
'Connection':'keep-alive',
'Cookie':'wa_session=tmqupoqa9n72jj0cc39d3ervmmcf52ln68ro2lm44jhnii2acha6pburcqc5kt5nenla1qpitut92k6if6n3k73d66flmejvpehabj1; __cfduid=d9e4a7feea6a68864d2aa652e2e3bb4441552271424; _ga=GA1.2.222625191.1552271425; _gid=GA1.2.1439755337.1552271425',
'Host':'wall.alphacoders.com',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Upgrade-Insecure-Requests': '1'}
# 制成完整的内嵌链接,接下来进入每个内嵌链接直接爬取高清图下载即可
r = requests.get(i, headers=headers, stream=True)
doc = pq(r.text)
down_link = doc.find('#page_container > div.center.img-container-desktop > a').attr('href')
down_links = requests.get(down_link) # 将获取的图片地址再次解析才能转换为二进制写入文件
with open('/Users/junjieliu/Pictures/龙珠高清壁纸/' + str(num) + '.jpg', 'wb') as f:
f.write(down_links.content)
time.sleep(5)
num += 1
if __name__ == '__main__':
"""
#第一种可选编程:
CPU_counts = mp.cpu_count() # 获得CPU核数
pool = mp.Pool(CPU_counts) # CPU核数
"""
pool = mp.Pool() #CPU核数,默认的是你机器根据情况自动分配的核心数
pool.map(down_pic(), inlinkes('龙珠', 92))
pool.close()#关闭pool,使其不在接受新的任务。
pool.join()#进程有序进行到有序结束

关于这个多进程可以理解为:在main函数中有多个进程池一同来经营运行,可以说他是时刻已经准备好的状态了,程序基本上只是inlinkes函数在如往常一贯运行而已,所以时间起码会缩小一倍。

目视感觉差不多的效果…可能是我设置了time.sleep(5)的关系,但是不这样会给人家服务器增加压力…哎,有失必有得啊,多进程的感觉是有快了一点的(具体来说还是有点明显的!)…跟本地网络情况还是有挂钩的,毕竟下载图片还是要看网速的。

运行程序期间会出现SSL的错误提示,这个不用理会,重新运行即可,遇到问题重新运行即可。

关于多进程教程可参考:

好文!

以上函数不懂的地方一般看完这个就懂了。

异步加速

异步加速,久仰大名了,今天来试试看威力如何~

其中需要用到的库请自行下载。

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
38
39
from urllib.parse import quote
from pyquery import PyQuery as pq
import time
from urllib.request import urlretrieve
import multiprocessing as mp
import aiohttp
import asyncio
async def inlinkes1(word, pages):
for i in range(85, pages):
session = aiohttp.ClientSession()
response = await session.get('https://wall.alphacoders.com/search.php?search=' + quote(word) + '&lang=Chinese&page=' + str(i))
html = await response.text()
doc = pq(html)
inlikes = doc.find('div.thumb-container > div.boxgrid > a') # 爬取每一页的内嵌参数链接
for i in inlikes.items():
yield 'https://wall.alphacoders.com/' + i.attr('href') # 此处用到的关键词yield像流水一样有序执行每一个内嵌链接
async def down_pic():
num = 2900
#在以下的迭代器中加上关键词async,由迭代器变成生成器
async for i in inlinkes1('龙珠', 92):
session = aiohttp.ClientSession()
response = await session.get(i)
html = await response.text()
doc = pq(html)
down_link = doc.find('#page_container > div.center.img-container-desktop > a').attr('href')
down_links = requests.get(down_link) # 将获取的图片地址再次解析才能转换为二进制写入文件
with open('/Users/junjieliu/Pictures/龙珠高清壁纸/' + str(num) + '.jpg', 'wb') as f:
f.write(down_links.content)
time.sleep(5)
num += 1
if __name__ == '__main__':
coroutine = down_pic()
task = asyncio.ensure_future(coroutine)
loop = asyncio.get_event_loop()
loop.run_until_complete(task)

其中的寓意就是将耗时的应用用await关键词对等上,在实现整个异步程序时,可先将耗时不部分的应用挂起来进而去处理另一个耗时的await,流程以上述表示:一直挂起,一直跳着直到最后一个“一并运行”。这样就达成了异步处理的效果,最终时间会达到减少。

可参考:

异步结合多进程

这个库出自于Facebookaiomultiprocess

各位自行解决吧,我想快点结束这个系列了,我想去研究一点新的东西去了…

---------------本文终---------------

文章作者:刘俊

最后更新:2019年03月19日 - 09:03

许可协议: 转载请保留原文链接及作者。