2020/4/11 斗图啦多线程爬取表情包

【斗图啦多线程爬虫思路】

网站:https://www.doutula.com/photo/list/?page=1
爬取的是最新的表情包这个页面的图片

思路
1.分析需求,创建解析线程和下载线程
因为按照顺序爬取速度比较忙,所以也是第一次使用多线程来爬取,加快爬取速度。
2020/4/11 斗图啦多线程爬取表情包_第1张图片
2.空列表的预先准备
把初始url地址构造好后统一放入到一个空列表中,方便调用多个线程解析
把线程解析后的url统一放入另一个空列表中,方便调用多个线程下载

3.构造解析图片url地址函数
这个网站数据解析相对比较简单,就是普通的页面。
因为是多线程,所以函数里面在获取列表里面的值的时候要加上线程锁,获取完毕后把锁揭开。
用list.pop()方法,每次只请求列表最后一个的数据,如果列表里面是空值,则结束循环。

这里有个注意问题:最开始启动线程的时候,放url地址的列表最开始是空的,如果直接同时,会导致线程获取不到数据而直接结束。
所以解决的办法是在下载线程启动前停顿个几秒钟,让列表里面有写入值,然后才能解析。
2020/4/11 斗图啦多线程爬取表情包_第2张图片
4、构造下载图片函数
下载图片的函数原理跟解析图片函数的原理基本一致

5.线程之间尽量间隔一点时间
解析太快有时候可能会出现问题,所以尽量加一点间隔时间。

最终代码如下:

```python
import requests
from lxml import etree
import urllib.request
import os
import threading
import time


URL = 'https://www.doutula.com/photo/list/?page={}'
URL_LIST = []
PAGE_LIST = []
LOCK  = threading.Lock()


headers = {
     
	'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3704.400 QQBrowser/10.4.3587.400'
}

# 创建文件夹,判断如果不存在,则创建文件夹
dirpath = 'images'
if not os.path.exists(dirpath):
	os.mkdir(dirpath)

# 解析线程
def parse_thread():
	while 1:
		LOCK.acquire()
		if len(URL_LIST) == 0:
			LOCK.release()
			break
		else:
			url = URL_LIST.pop() # 每次拿出最后一个
			LOCK.release()
			response = requests.get(url,headers = headers,timeout=100)
			tree = etree.HTML(response.content)
			img_list = tree.xpath('//div[@class="page-content text-center"]/div/a')
			for li in img_list:
				img_link = li.xpath('.//img/@data-original')[0]
				# 把img_link保存到列表里面,给下载线程去下载
				PAGE_LIST.append(img_link)
			time.sleep(1)


# 下载线程
def download_thread():
	while 1:
		LOCK.acquire()
		if len(PAGE_LIST) == 0:
			LOCK.release()
			break
		else:
			url = PAGE_LIST.pop()
			LOCK.release()
			# 保存图片
			filename = url.split('/')[-1]
			filepath = os.path.join(dirpath,filename)
			urllib.request.urlretrieve(url,filepath)
			time.sleep(1)

def main():
	# 把所有url放到列表里面,方便使用多个线程解析
	for i in range(1,5):
		url = URL.format(i)
		URL_LIST.append(url)

		# 创建3个解析线程
	for i in range(3):
		parse = threading.Thread(target = parse_thread)
		parse.start()

	print('正在下载图片中。。。')

	# 创建3个下载线程
	for i in range(3):
		download = threading.Thread(target = download_thread)
		time.sleep(3) # 
		download.start()

if __name__ == '__main__':
	main()
PS :可能少了线程销毁的工作…

你可能感兴趣的:(python,thread)