:点击上方[Python爬虫数据分析挖掘]→右上角[...]→[设为星标⭐]html
多线程爬取表情包
有一个网站,叫作“斗图啦”,网址是:https://www.doutula.com/
。这里面包含了许许多多的有意思的斗图图片,还蛮好玩的。有时候为了斗图要跑到这个上面来找表情,实在有点费劲。因而就产生了一个邪恶的想法,能够写个爬虫,把全部的表情都给爬下来。这个网站对于爬虫来说算是比较友好了,他不会限制你的headers
,不会限制你的访问频率(固然,做为一个有素质的爬虫工程师,爬完赶忙撤,不要把人家服务器搞垮了),不会限制你的IP地址,所以技术难度不算过高。可是有一个问题,由于这里要爬的是图片,而不是文本信息,因此采用传统的爬虫是能够完成咱们的需求,可是由于是下载图片因此速度比较慢,可能要爬一两个小时都说不许。所以这里咱们准备采用多线程爬虫,一下能够把爬虫的效率提升好几倍。python
文章目录
一、爬取准备程序员
二、完整代码web
三、图片辅助分析ruby
四、运行结果服务器
一、爬取准备
爬取目标微信
https://www.doutula.com/article/list/
批量爬取网络
舒适提示:爬取过程当中保持网络通畅,否则会爬取失败!
这里多线程咱们使用的是Python
自带的threading
模块。而且咱们使用了一种叫作生产者和消费者的模式,生产者专门用来从每一个页面中获取表情的下载连接存储到一个全局列表中。而消费者专门从这个全局列表中提取表情连接进行下载。而且须要注意的是,在多线程中使用全局变量要用锁来保证数据的一致性。
ps:感兴趣的小伙伴能够试试线程池多线程
使用线程池app
线程池或进程池是用于在程序中优化和简化线程/进程的使用。经过池,你能够提交任务给executor。池由两部分组成,一部分是内部的队列,存放着待执行的任务;另外一部分是一系列的进程或线程,用于执行这些任务。池的概念主要目的是为了重用:让线程或进程在生命周期内能够屡次使用。它减小了建立建立线程和进程的开销,提升了程序性能。重用不是必须的规则,但它是程序员在应用中使用池的主要缘由。
二、完整代码
import requestsfrom threading import Threadfrom queue import Queuefrom lxml import etreeimport timeimport osimport random
# 请求头headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36"}path = "./图片"
#数据采集class CrawlInfo(Thread): def __init__(self ,url_queue ,html_queue): Thread.__init__(self)
self.url_queue = url_queue self.html_queue = html_queue
def run(self): # 不存在就建立 if not os.path.exists(path): # mkdir是建立文件夹 os.mkdir(path)
while self.url_queue.empty() == False: url = self.url_queue.get() response = requests.get(url,headers=headers) #请求成功状态码为200则进行put if response.status_code == 200: self.html_queue.put(response.text)
# 数据解析、保存class ParseCrawl(Thread): def __init__(self, html_queue): Thread.__init__(self) self.html_queue = html_queue
def run(self): #队列不为空则继续遍历 while self.html_queue.empty() == False: data = etree.HTML(self.html_queue.get()) #查看图1,根据class定位获取其下的全部a标签 a_list = data.xpath("//div[@class='col-sm-9 center-wrap']/a") #遍历a标签 for a_singer in a_list: #查看图2,从新写xpath根据class定位 #text():获取文本值 name = a_singer.xpath(".//div[@class='random_title']/text()")[0] #替换掉name中的\u200b\u200b\u200b字符串 name = str(name).replace("\u200b\u200b\u200b","") #拼接新的路径 new_path = path + "/" + name #新路径不存在就建立 if not os.path.exists(new_path): os.mkdir(new_path)
#获取图片url,查看图3 #根据class值定位到全部img的父标签,在根据img的class拿到全部img的data-original属性即图片url,这里不拿src属性是由于爬取时拿到的是图片还未加载完毕的url img_url_list = a_singer.xpath(".//div[@class='random_article']//img[@class='lazy image_dtb img-responsive']/@data-original") #遍历img_url_list for img in img_url_list: #因为图片有jpg、png、gif格式,这里咱们根据'.'分割获取图片格式后缀 suffix = "." + str(img).split(".")[-1] #发起请求,content为二进制 re = requests.get(img,headers=headers).content
#图片命名为随机数str(random.randint(1,500)) with open(new_path + "/" + str(random.randint(1,500)) + str(suffix), "wb") as f: #保存图片 f.write(re)
#开始if __name__ == '__main__': start = time.time()
url_queue = Queue() html_queue = Queue()
base_url = "https://www.doutula.com/article/list/?page={}" #咱们这只爬取13页 for i in range(1,14): print("正在爬取第{}页".format(i)) new_url = base_url.format(i) url_queue.put(new_url)
crawl_list = [] for i in range(3): Crawl = CrawlInfo(url_queue, html_queue) crawl_list.append(Crawl) Crawl.start()
for crawl in crawl_list: crawl.join()
parse_list = [] for i in range(3): parse = ParseCrawl(html_queue) parse_list.append(parse) parse.start()
for parse in parse_list: parse.join()
end = time.time() print("爬取时间:{}".format(end- start))
以上这份代码。能够完整的运行了。采用多线程,在一张图片下载的时候,就彻底能够去请求其余图片,而不用继续等待了。所以效率比较高。
三、图片辅助分析
图1
图2
图3
四、运行结果
写在最后:
本教程采用多线程来完成表情的爬取,可让爬取效率高出不少倍。Python
的多线程虽然有GIL
全局解释器锁,但在网络IO
处理这一块表现仍是很好的,不用在一个地方一直等待。以上这个例子就很好的说明了多线程的好处。
【各类爬虫源码获取方式】
- END -
欢迎关注公众号:Python爬虫数据分析挖掘,方便及时阅读最新文章
记录学习python的点点滴滴;
回复【开源源码】免费获取更多开源项目源码;
本文分享自微信公众号 - Python爬虫数据分析挖掘(zyzx3344)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。