起因
前段时间在微信群中看到群友发这种表情包:
出于感兴趣就问这个群友还有没有更多这种表情(盗图王)
然后群友告诉我了这个表情包的官网地址,看着满屏的沙雕表情包就想爬取下来使用
编写爬虫
点击官网的 YES!!!!! 之后就可以看到全部表情包,随便右击一张图片一张图片复制URL后可以看到图片连接:
http://motions.cat/gif/nhn/0106.gif
然后再右击它相邻的一张复制出链接:
http://motions.cat/gif/nhn/0105.gif
通过上面两个链接我们可以分析出图片路由是按照递增的规则进行存储 GIF 图片的,并且是四位数前置补0
所以我们可以通过自增一个数字然后使用格式化输出匹配出路由,使用python3测试一下:1
2
3
4$ python3
>>> number = 1
>>> '%04d' % number # %04d: 输出一个整数的时候 按照4位数对其 多余的使用 0 补齐
'0001'
开始编写 Python 代码:
首先定义前置 URL 这一块是不会变的,然后定义启始页1
2
3url = 'http://motions.cat/gif/nhn/'
start_number = 1
max_number = 139
随后我们写一个死循环,每循环一次就对 start_number
进行自增,当 start_number
自增到大于 max_number
的时候就退出循环,然后在循环中编写爬虫1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25while True:
if (start_number > max_number):
break
try:
filename = ('%04d' % start_number) + '.gif'
requestURL = url + filename
print('开始请求:', requestURL)
r = requests.get(requestURL)
if (r.status_code != 200):
print(requestURL + ', Request fail, status code: ', r.status_code)
continue
# 存储目录,目录不存在就创建
path = './motions/'
if not os.path.exists(path):
os.mkdir(path)
# 将请求到的二进制数据写入到 GIF 文件中
with open(path + filename, 'wb') as f:
f.write(r.content)
print('保存成功:', filename)
start_number += 1
except Exception as e:
print('Error: ', e)
完整代码: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
36import requests
import os
def main():
url = 'http://motions.cat/gif/nhn/'
start_number = 1
max_number = 139
while True:
if (start_number > max_number):
break
try:
filename = ('%04d' % start_number) + '.gif'
requestURL = url + filename
print('开始请求:', requestURL)
r = requests.get(requestURL)
if (r.status_code != 200):
print(requestURL + ', Request fail, status code: ', r.status_code)
continue
path = './motions/'
if not os.path.exists(path):
os.mkdir(path)
with open(path + filename, 'wb') as f:
f.write(r.content)
print('保存成功:', filename)
start_number += 1
except Exception as e:
print('Error: ', e)
if ('__main__' == __name__):
main()
运行效果:
由于该网站运行在国外,所以爬的很慢所以我打算编写多线程代码交替执行爬虫来提高爬虫效率。
编写多线程爬虫
Python 的标准库提供了 threading
模块用于编写多线程,开启线程使用 threading.Thread
类创建一个实例,然后通过调用 Thread.start()
方法执行线程:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import threading
def methodName(methodArgs1, methodArgs2):
# 调用 threading.current_thread().name 可以看到当前线程的名称
print("currency thread name:", threading.current_thread().name)
# 创建一个 Thread 对象
# target 是需要执行的方法,name 给线程起一个名字,args 是方法的参数
thread = threading.Thread(
target=methodName,
name='线程名称'
args=(methodArgs1, methodArgs2)
)
thread.start() # 执行线程
thread.join() # 回到主线程中继续执行
多线程爬虫完整代码: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
62import requests
import queue
import threading
import os
def crawl_motions(taskQueue):
while not taskQueue.empty():
number = taskQueue.get()
print('正在下载第' + str(number) + '张表情包', threading.currentThread().name)
filename = ('%04d' % number) + '.gif'
url = 'http://motions.cat/gif/nhn/' + filename
try:
r = requests.get(url)
if r.status_code != 200:
print('请求第' + url + '失败', 'Thread name: ', threading.currentThread().name)
taskQueue.put(number)
store_path = './motions-test/'
if not os.path.exists(store_path):
os.mkdir(store_path)
with open(store_path + filename, 'wb') as f:
f.write(r.content)
print("保存成功" + filename, 'Thread name:', threading.currentThread().name)
except Exception as e:
taskQueue.put(number)
print('Error: ', e, 'Thread name: ', threading.currentThread().name)
# def store_data(dataQueue):
def main():
taskQueue = queue.Queue()
start_number = 1
max_number = 139
for i in range(start_number, max_number):
taskQueue.put(i) # 将需要爬取的 GIF 放到任务队列
crawl_thread = []
for i in range(1, 10):
# 创建线程
threading_crawl = threading.Thread(
target=crawl_motions,
name='crawl-' + str(i),
args=(taskQueue,)
)
crawl_thread.append(threading_crawl)
# 开启线程
threading_crawl.start()
for thread in crawl_thread:
thread.join()
if '__main__' == __name__:
main()
print("OK!")
执行效果: