当前位置: 首页 > 后端技术 > Python

一个爬虫的并发改造过程

时间:2023-03-26 12:36:34 Python

事情是这样的:因为我在写一个豆瓣抽奖的小程序,需要抓取所有豆瓣直播转发的用户信息,然后从这些用户中抽取幸运观众。典型的IO密集型操作。首先,爬虫需要进入广播,找出有多少转载页面。它看起来像这样:defget_pages(url):r=fetch(url)soup=BeautifulSoup(r,'lxml')page_num=soup.find("div",class_="paginator").find_all("a")[-2].string返回page_num然后依次解析每个页面的用户信息:defparse_one(r):human=list()soup=BeautifulSoup(r,'lxml')try:content=soup.find_all("li",class_="list-item")除了:记录。error("thereisnoinfo.")raise.....returnhuman非常简单。一开始我是用requests库,直接一个一个请求每个页面的内容。代码写好后,点击执行,等啊等啊等。终于爬完了,控制台输出:Time-consumed:106.168...我眼前一黑,如果用户用这个来抽奖,黄花菜就凉了。于是决定多开几个进程,使用multiprocessing.Pool()创建多个进程,看看效果:pool=multiprocessing.Pool(5)url_list=[url+'?start={}&tab=reshare#reshare'.format(i*20)foriinrange(0,int(page_num))]withpoolasp:res=p.map(parse_one,url_list)time-consuming:time-consuming:26.168740749359131好像还不错.比之前的顺序爬取要快很多。但还是有点慢。然后决定上携程(coroutine)。首先,必须异步获取网页内容:asyncdeffetch(url):headers={"User-Agent":"Mozilla/5.0(WindowsNT5.1;U;en;rv:1.8.1)Gecko/20061208Firefox/2.0.0Opera9.50",......}asyncwithaiohttp.ClientSession(headers=headers)assession:asyncwithsession.get(url)asres:result=awaitres.text()returnresult然后将所有的request放入task中:url_list=[redict_url+'?start={}&tab=reshare#reshare'.format(i*20)foriinrange(0,int(page_num))]loop=asyncio.=get_event_loop()tasks=[asyncio.ensure_future(reshare(url))forurl_list]loop.run_until_complete(asyncio.wait(tasks))fortasksintasks:human.extend(task.result()))接下来就是见证奇迹的时候了!(然而并不是,豆瓣把我屏蔽了,我太难了。)然后去代理IP。编写了另一个爬虫来爬取数百个代理ip地址。为每个请求随机选择一个代理:defrandom_proxy():url=hosts[random.randint(1,len(hosts))]proxy="http://{}".format(url)returnproxy现在让我们看看效果:耗时:2.2529048919677734Amazing!!!关于线程、进程、协程可以参考我之前的文章:Python并发编程的思考另外,我的豆瓣抽奖程序(豆江)已经上线了,欢迎大家使用提bug。