大名鼎鼎的aiohttp,相信如果你学习Python或者爬虫的时候,肯定听说过这个东西。没听过也不要紧,今天看完文章,只要记住,aiohttp这个东西,在写爬虫的时候,很牛逼就行了。

aiohttp 就是一个用 asyncio实现的 HTTP client/server。 你可以通过它来简单实现一个具有异步处理功能的 clients 和 servers。 aiohttp同时还支持 Server WebSockets 和 Client WebSockets,让你使用起来更加简单。

今天,皮爷就带你来体验一下,这个“爬虫加速器”。

0x00 我们的爬虫需求

皮爷最近在做一个项目,就是用微信小程序追美剧的项目,那么首先,我们得需要有一个所有美剧的来源,恰巧,下面这个排行榜就有我们所有需要的信息:

http://www.ttmeiju.vip/index.php/summary/index/p/1.html

初级要求

我们很简单,就是需要从【第一页】:

http://www.ttmeiju.vip/index.php/summary/index/p/1.html

一直爬到最后一页【第三十五页】:

http://www.ttmeiju.vip/index.php/summary/index/p/35.html

中级要求

由于排行榜页面没有美剧的【季】信息,这个必须进入详情页来做,所以,中级要求就是针对每一条美剧,进入详情页,从里面爬取出来当前美剧的【季】信息。

这个要求不难吧?就是一级页面变换 page number 的数值来爬取信息。就算要爬取【季】信息,我们的爬虫深度也就才两级。

所以,这个需求不难。而且网页都是静态资源,一般简单的爬虫程序就能hou住。

0x01 撸码前的整理

这一步,我们需要想想通过什么样的方法能够实现上面的需求。

熟悉皮爷的童鞋都知道,皮爷之前的爬虫程序主要用 Scrapy 这个框架。为啥主要用这个?主要这个是一个框架。框架的意思就是写起来简单。何为简单?你只需要专注写爬虫的相关逻辑部分就好,不需要管理程序的生命周期,代码控制之类的问题,因为框架都给你整理好了。

那么,我们的需求就可以用两种做法来搞:

用 Scrapy 来写。自己写爬虫,但是要用到 aiohttp 的东西。下面皮爷就简单为大家来说一下他们是怎么实现的,以及最后对比结果。

0x02 Scrapy撸发撸起来

scrapy的写法,皮爷之前写过很多遍了,具体的教学文章,可以参考皮爷之前写的:

基于云服务的网站种子采集器,还能发送到邮箱,你不来考虑一下?

这里,我们就直接开始说具体的实现代码了。代码实现的就是从1页爬取到35页面,先不考虑“两层爬取”的数据。

class TtmjspiderSpider(scrapy.Spider):name = '皮爷spider'root_url = "http://www.ttmeiju.vip"def start_requests(self):start_url = "http://www.ttmeiju.vip/index.php/summary/index/p/1.html"yield Request(url=start_url, callback=self.parse_page, dont_filter=True, meta={"cur_page": 1, "max_page_num": -1})def parse_page(self, response):content = response.bodysoup = BeautifulSoup(content, "html.parser")cur_page = response.meta["cur_page"]cur_url = response.urlmax_page_num = response.meta["max_page_num"]# 第一页找top3的标签rank_top_3_div = soup.find_all(name="div", attrs={"class": "ranktop3"})for item in rank_top_3_div:link_a = item.find_all(name="a")[0]tv_url = self.root_url + link_a["href"]tv_name = link_a.texttv_rank_num = item.find_all(name="div", attrs={"class": "ranknum"})[0].textplay_info_div = item.find_all(name="div", attrs={"class": "mjinfo"})play_info_one = play_info_div[0].textplay_info_two = play_info_div[1].texttv_category = play_info_one.split("/")[0].strip()tv_status = play_info_one.split("/")[1].strip()tv_update_day = play_info_one.split("/")[2].split(":")[-1].strip()temp_result = re.findall("\d{4}-\d{2}-\d{2}", play_info_two)if len(temp_result) != 0:tv_return_date = temp_result[0]else:tv_return_date = "暂无"# 构建 itemtv_item = TtmjTvPlayItem()tv_item["tv_play_name"] = tv_nametv_item["tv_play_rank"] = int(tv_rank_num)tv_item["tv_play_category"] = tv_categorytv_item["tv_play_state"] = tv_statustv_item["tv_play_update_day"] = tv_update_daytv_item["tv_play_return_date"] = tv_return_datetv_item["tv_play_url"] = tv_urltv_item["tv_play_cur_season"] = 0yield tv_item# 正常信息列表content_div = soup.find_all(name="tr", attrs={"class": re.compile(r"Scontent")})for item in content_div:td_list = item.find_all(name="td")tv_rank_num = td_list[0].textlink_a = td_list[1].find(name="a")tv_url = self.root_url + link_a["href"]tv_name = link_a.texttv_category = td_list[2].text.strip()tv_status = td_list[3].text.strip()tv_update_day = td_list[4].text.strip()tv_return_date = td_list[5].text.strip()tv_item = TtmjTvPlayItem()tv_item["tv_play_name"] = tv_nametv_item["tv_play_rank"] = int(tv_rank_num)tv_item["tv_play_category"] = tv_categorytv_item["tv_play_state"] = tv_statustv_item["tv_play_update_day"] = tv_update_daytv_item["tv_play_return_date"] = tv_return_datetv_item["tv_play_url"] = tv_urltv_item["tv_play_cur_season"] = 0yield tv_itemnext_page_ul = soup.find_all(name="ul", attrs={"class": "pagination"})if len(next_page_ul) != 0:last_page_a = next_page_ul[0].find_all(name="a", attrs={"class": "end"})if len(last_page_a) != 0 and max_page_num == -1:max_page_num = last_page_a[0].textif int(cur_page) < int(max_page_num):next_page_num = int(cur_page) + 1else:logging.info("ALl finished")returnnext_page_url = cur_url[:-(len(cur_url.split("/")[-1]))] + str(next_page_num) + ".html"yield Request(url=next_page_url, callback=self.parse_page, dont_filter=True, meta={"cur_page": next_page_num, "max_page_num": max_page_num})

代码简单说一下,通过 【Chrome】--【检查】页面,看到我们要找的列表信息标签。

然后,通过 BeautifulSoup 来解析找到相对应的文字,并且解析成我们想要得到的 Scrapy Item ,最后在 pipeline 里面做存入数据库的操作。

那我们接下来就运行一下这个 Scrapy 框架写的爬取 35 页信息的爬虫,看看效果如何。

数据库里面看到已经存入了数据:

从结果里面看到,用 Scrapy ,没有修改 setting.py 文件,爬取 35 页数据,然后生成 Scrap.Item ,总共用了 2 分 10 秒。成绩还可以哈。

0x03 aiohttp撸法撸起来

这里,皮爷用网上的一张图来给大家看一下 aiohttp 的流程:

其实 aiohttp 就是讲事件进入一个队列,然后挨个调用执行,这些任务有个共同的特点,就是他们需要等待操作。所以,在等待的过程中,程序会调起其他任务接着执行。

我们来看代码:

sem = asyncio.Semaphore(80) # 信号量,控制协程数,防止爬的过快client = pymongo.MongoClient("mongodb://xx.xx.xx.xx/", xxx)db = client["xxx"]ttmj_collection = db["xxx"]result_dict = list()def generateRequestList(url, start, end):page_list = list()for i in range(start, end):genUrl = url.replace("**", str(i))page_list.append(genUrl)return page_listasync def grab_page(url):with(await sem):async with aiohttp.ClientSession() as session:content = await fetch(session, url, 0)async def fetch(session, url, level, tv_item=None):async with session.get(url) as req:content = await req.text()soup = BeautifulSoup(content, "html.parser")root_url = "http://www.ttmeiju.vip"cur_time_string = datetime.datetime.now().strftime('%Y-%m-%d')rank_top_3_div = soup.find_all(name="div", attrs={"class": "ranktop3"})for item in rank_top_3_div:link_a = item.find_all(name="a")[0]tv_url = root_url + link_a["href"]tv_name = link_a.texttv_rank_num = item.find_all(name="div", attrs={"class": "ranknum"})[0].textplay_info_div = item.find_all(name="div", attrs={"class": "mjinfo"})play_info_one = play_info_div[0].textplay_info_two = play_info_div[1].texttv_category = play_info_one.split("/")[0].strip()tv_status = play_info_one.split("/")[1].strip()tv_update_day = play_info_one.split("/")[2].split(":")[-1].strip()temp_result = re.findall("\d{4}-\d{2}-\d{2}", play_info_two)if len(temp_result) != 0:tv_return_date = temp_result[0]else:tv_return_date = "暂无"tv_item = TtmjTvPlayItem()tv_item.tv_play_name = tv_nametv_item.tv_play_rank = int(tv_rank_num)tv_item.tv_play_category = tv_categorytv_item.tv_play_state = tv_statustv_item.tv_play_update_day = tv_update_daytv_item.tv_play_return_date = tv_return_datetv_item.tv_play_update_time = cur_time_stringtv_item.tv_play_url = tv_urltv_item_dict = dict((name, getattr(tv_item, name)) for name in dir(tv_item) if not name.startswith('__'))# print("complete Item: %s" % (tv_item.tv_play_name))result_dict.append(tv_item_dict)# await fetch(session, tv_url, 1, tv_item)content_div = soup.find_all(name="tr", attrs={"class": re.compile(r"Scontent")})for item in content_div:td_list = item.find_all(name="td")tv_rank_num = td_list[0].textlink_a = td_list[1].find(name="a")tv_url = root_url + link_a["href"]tv_name = link_a.texttv_category = td_list[2].text.strip()tv_status = td_list[3].text.strip()tv_update_day = td_list[4].text.strip()tv_return_date = td_list[5].text.strip()tv_item = TtmjTvPlayItem()tv_item.tv_play_name = tv_nametv_item.tv_play_name_en = tv_url.split("/")[-1].replace(".", " ")[:-5]tv_item.tv_play_name_en_dot = tv_url.split("/")[-1][:-5]tv_item.tv_play_name_ch = tv_name.split(" ")[0]tv_item.tv_play_rank = int(tv_rank_num)tv_item.tv_play_category = tv_categorytv_item.tv_play_state = tv_statustv_item.tv_play_update_day = tv_update_daytv_item.tv_play_return_date = tv_return_datetv_item.tv_play_url = tv_urltv_item.tv_play_cur_season = 0tv_item_dict = dict((name, getattr(tv_item, name)) for name in dir(tv_item) if not name.startswith('__'))print("complete Item: %s" % (tv_item.tv_play_name))result_dict.append(tv_item_dict)def main_grab(page_list):loop = asyncio.get_event_loop() # 获取事件循环tasks = [grab_page(url) for url in page_list] # 把所有任务放到一个列表中loop.run_until_complete(asyncio.wait(tasks)) # 激活协程loop.close() # 关闭事件循环def writeToDb():for tv_item in result_dict:ttmj_collection.insert(tv_item)print("insert item: " + tv_item["tv_play_name"])client.close()if __name__ == '__main__':start_url = "http://www.ttmeiju.vip/index.php/summary/index/p/**.html"page_list = generateRequestList(start_url, 1, 36)start = time.time()main_grab(page_list)print('爬取总耗时:%.5f秒' % float(time.time() - start))writeToDb()print('总耗时:%.5f秒' % float(time.time() - start))

aiohttp的关键写法,就是在开头,得声明信号量,这里皮爷申请的是 80 个。

接着就是 main_grab 方法中,开始调用 aiohttp。 aiohttp的方法,都需要以

async def

开头来定义,其中,需要等待的地方,可以用

await

来写。皮爷的这个代码,你完全可以照猫画虎的写出自己的逻辑。如果还有什么不懂的,自己百度或者谷歌搜索 aiohttp 就可以,网上例子一大堆,都很简单,看了也没啥用。还不如实际的撸个项目,加深体验。

我们来看结果,爬取35个网页总共用了 2 秒多:

你没看错,单纯的爬取网页,就 2 秒。

数据库中是:

插入数据库,皮爷是一条一条插入的,所以这个耗时很严重,导致整个工程运行了 35 秒:

从之前的 130 秒,到现在的 35 秒,你说速度是不是快了很多???你说快不快?是不是比刘翔还快??接下来快看骚操作怎么搞。

0x04 骚操作福利

骚操作,就要骚起来。你看皮爷用 aiohttp 写的Python运行起来是不是很给力?不但爬取数据,还能将数据结果存储到服务器里面。你有没有想过,这个代码是不是可以放到服务器上面让服务器自己跑???

答案当然是:可以的!!!

没错,你以后写的 py 文件,均可以放到服务器上面自动执行。不再需要像现在这样,自己写了代码,在ide里面跑一边之后,就荒废了。

那么问题来了,首先,你是不是得有个服务器啊?皮爷不亏待你们,特意给你们准备了优惠券,有没有的都可以来领取。

阿里云部分: 【阿里云新人1888元云产品通用代金券】: https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=nrkmbo9q【阿里云爆款云主机,2折优惠券】:https://promotion.aliyun.com/ntms/act/qwbk.html?userCode=nrkmbo9q【阿里云企业级服务器2折优惠券】:https://promotion.aliyun.com/ntms/act/enterprise-discount.html?userCode=nrkmbo9q腾讯云:【新客户无门槛领取总价值高达2775元代金券,每种代金券限量500张,先到先得】:https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=b351b2fc50b15866ff9d19b58a5df0f5&from=console【腾讯云服务器、云数据库特惠,3折优惠券】:https://cloud.tencent.com/redirect.php?redirect=1014&cps_key=b351b2fc50b15866ff9d19b58a5df0f5&from=console

有了服务器,那么将本地文件上传到服务器上面,只需要用

scp

命令就好:

$ scp @:

上传代码参考文章

那么怎么定是执行呢?服务器一般都是 linux 系统,linux 系统自带一个命令叫

crontab

,用这个命令就可以定制执行了。

这一套组合拳打下来,你说骚不骚?

0x05 最后总结

爬虫用 aiohttp 来写还是用 Scrapy 来写,自己定夺,他们各有各的好处。

Scrapy框架完整,结果清晰;

aiohttp 速度更快,非常灵活。

所以,想用什么写爬虫,要根据你自己的需求来定。但是皮爷最近搞的东西,打算用 aiohttp 来自己做一套框架,来专门为自己使用。

python爬虫图片加速_Python爬虫加速神器的小试相关推荐

  1. python邮件图片加密_Python爬虫如何应对Cloudflare邮箱加密

    最近写一个小爬虫,需要拿到邮箱信息,发现拿不到,也不是ajax接口.最后查资料发现是被Cloudflare加密起来了,有加密肯定有解密. 柠之漠然: 这个解密方式就是从那段 js 代码转换过来的 其中 ...

  2. python爬虫多线程下载_Python爬虫之多线程下载豆瓣Top250电影图片

    爬虫项目介绍 本次爬虫项目将爬取豆瓣Top250电影的图片,其网址为:https://movie.douban.com/top250, 具体页面如下图所示: 本次爬虫项目将分别不使用多线程和使用多线程 ...

  3. python爬虫文献综述_Python爬虫入门(1):综述

    首先爬虫是什么?网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本. 根据我的经验,要学习Python爬虫, ...

  4. python爬虫文献综述_Python爬虫入门一之综述

    大家好哈,最近博主在学习Python,学习期间也遇到一些问题,获得了一些经验,在此将自己的学习系统地整理下来,如果大家有兴趣学习爬虫的话,可以将这些文章作为参考,也欢迎大家一共分享学习经验. Pyth ...

  5. python爬图片_网络爬虫经验:反爬和反反爬

    我想很多人入门python是图片爬虫,就是HTTP请求,保存一下图片,用python实现非常快.网上很多爬虫的教程就讲到这里,实际上很单一,看了跟没看没什么区别,都是找一下网页的规律,然后Beauti ...

  6. python爬虫自学路线_python 爬虫学习路线:从入门到进阶

    大家好,我是凉拌 今天给大家详解一下我的爬虫学习路线. 对于小白来说,爬虫可能是一件非常复杂.技术门槛很高的事情.比如有的人则认为先要掌握网页的知识,遂开始 HTML\CSS,结果入了前端的坑,浪费了 ...

  7. python爬虫面试问题_Python爬虫面试总结

    ## Python爬虫面试总结 1. 写一个邮箱地址的正则表达式? [A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$ 2. 谈 ...

  8. python爬虫知识大全_Python爬虫入门有哪些基础知识点

    1.什么是爬虫 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来.想抓取什么?这个由你来控制它咯. ...

  9. python爬虫的用途_python爬虫用途

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 专业点来说就是应用多台机器同时实现爬虫任务,这多台机器上的爬虫,就是称作分布式爬 ...

  10. python爬虫酷狗_python爬虫教程:爬取酷狗音乐,零基础小白也能爬取哦

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于腾讯云 作者:python学习教程 ( 想要学习Python?Pyt ...

最新文章

  1. OSPF中的frame-relay(3) 点到多点非广播
  2. 量子计算的符号表示(Dirac notation)
  3. careercup-中等难度 17.5
  4. 怎样学好python-零基础如何学好Python?
  5. RestTemplate带参发送get及post请求携带headers请求头代码示例
  6. 史上最简单的SpringCloud教程 | 第七篇: 高可用的分布式配置中心(Spring Cloud Config)
  7. 02_c3p0之c3p0-config.xml配置案例,操作c3p0的jdbcUtil工具类的编写
  8. 性能测试报告模板_性能测试新手误区
  9. 软件工程讲义 3 两人合作(2) 要会做汉堡包
  10. HDwiki 6.0 图片大图不能正常显示的解决方法
  11. jsp前端验证(非常好用)
  12. 10-12-顺序表地址排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版...
  13. java弱引用在安卓中有效吗_Android 软引用和弱引用详解及实例代码
  14. python查找当前路径,在Python中查找当前终端选项卡的当前目录
  15. jquery之提示信息
  16. win7电脑怎么设置桌面便签
  17. 最新fl studio20.8中文电音编曲宿主制作软件
  18. 室内定位——卡尔曼滤波原理、Matlab与javascript实现
  19. 前端js实现文字自动转拼音方法
  20. Android版本新特性(6-12)(13预览)

热门文章

  1. Springboot集成Flyway(适用于多数据源)
  2. Great Cow BASIC (大母牛BASIC)一个开源的8位芯片PIC和Atmel AVR微控制器的BASIC编译器
  3. [210923]操作系统(自考)重点笔记
  4. 中小河流水文监测系统、水文遥测系统、水文监测
  5. 欧姆龙PLC NJ系列ST语言EtherCat总线控制24个伺服轴大型程序电池生产线
  6. 第五维度存在的意义:或许可以解释量子理论
  7. 算法笔记-问题 A: 重心在哪里
  8. NYOJ_779兰州烧饼
  9. 将MySQL去重操作优化到极致之三弹连发(三):用rocksdb替代innodb
  10. 打扮114(淘宝试衣间产品)使用帮…