基于python asyncio、aiohttp库采用协程方法的一个爬虫实验

新手小白的一个python晋级爬虫实验,基于python的asyncio、aiohttp库采用异步协程方法抓去了豆瓣电影TOP250基本信息。

一、案例背景

新手小白在入门python爬虫的学习中,发现大部分前辈分享的抓取豆瓣TOP250电影信息的学习案例基本都是基于TOP250电影排行的主页信息(每页25条电影信息,共计10页)爬取电影名称、导演、演员、评分等基本信息,笔者在刚入门的时候采取该方法发现最终获取到的信息不太完整,比如缺乏编剧信息,演员、导演信息不完整等等,为了能获得更干净的数据,应该进入每条电影的具体网址链接里面,抓取上述信息。

故整体思路分为两步:1,从每个主页中获得25条电影的次级网站链接;2:进入每条电影的链接获得详细数据。

对每个主业使用循环分别获得25条电影链接,在对25条电影链接分别使用循环,会面临较多的I/O阻塞问题,对于每次循环网页获得信息后笔者均设置了5秒的休眠时间,单线程同步执行的情况下250个网页至少需要1250秒,即20分钟。试探性的使用了异步协程方法,惊奇的发现,最后跑出来的并写入csv文件的时间为173.63秒,3分钟不到。故分享一下自己的探索代码,看看能否有进一步提升效率的可行性,以待完善和提高。

二、核心代码

1.进入每部电影链接获取数据的代码

主要思路是构建一个异步函数,网上查询了一些方法,使用aiohttp库,最后写入csv数据部分还未使用异步方法改进,暂时还有

#构建异步协程函数,获取单页数据
async def get_data(href):
    async with aiohttp.ClientSession() as session:
        async with await session.get(href,headers=headers) as response2:
            page_text= await response2.text()
            html_data=etree.HTML(page_text)
            div_info=html_data.xpath('/html/body/div[3]/div[1]/div[3]/div[1]/div[1]/div[1]/div[1]/div[2]')[0]
            #获取片名
            movie_name=html_data.xpath('/html/body/div[3]/div[1]/h1/span[1]/text()')[0]
            #获取导演信息
            director='/'.join(div_info.xpath('./span[1]/span[2]/a/text()')[0:])
            #获取编剧信息
            authors='/'.join(div_info.xpath('./span[2]/span[2]/a/text()')[0:])
            #获取演员信息
            actors='/'.join(div_info.xpath('./span[3]/span[2]//a/text()')[0:])
            #电影类型
            movie_type='/'.join(div_info.xpath('.//span[@property="v:genre"]/text()')[0:])
            #制片国家/地区
            country=div_info.xpath('.//span[contains(text(),"制片国家")]/following::text()[1]')[0].strip()
            #语言
            language=div_info.xpath('.//span[contains(text(),"语言")]/following::text()[1]')[0].strip()
            #上映时间
            year='/'.join(div_info.xpath('.//span[@property="v:initialReleaseDate"]/text()')[0:])
            #片长/分钟
            runtime=div_info.xpath('.//span[@property="v:runtime"]/text()')[0].replace('分钟','')

            rate_data=html_data.xpath('/html/body/div[3]/div[1]/div[3]/div[1]/div[1]/div[1]/div[2]')[0]
            #获取评分信息
            rate_score=rate_data.xpath('./div[1]/div[2]/strong/text()')[0]
            rate_amounts=rate_data.xpath('.//span[@property="v:votes"]/text()')[0]

            csvwriter.writerow([movie_name,year,movie_type,runtime,country,
                                language,director,authors,actors,rate_score,rate_amounts])
        await asyncio.sleep(5)

2.将获取电影数据的异步函数嵌入主函数

通过主函数获得各个电影的href,并将href参数传入上述异步函数,调用异步函数,并打包异步函数任务,建立异步函数待执行的Tasks任务集

async def get_movie_data(url):
    async with aiohttp.ClientSession() as session:
        async with await session.get(url,headers=headers) as response1:
            domain_page_data = await response1.text()
            domain_page=etree.HTML(domain_page_data)
            lis=domain_page.xpath('/html/body/div[3]/div[1]/div/div[1]/ol/li')
            tasks=[]
            for li in lis:
                name=li.xpath('./div/div[2]/div[1]/a/span[1]/text()')[0]
                href=li.xpath('./div/div[2]/div[1]/a/@href')[0]
                tasks.append(asyncio.create_task(get_data(href)))
            await asyncio.wait(tasks)
        await asyncio.sleep(5)

3.在main程序中设置循环语句,为以上函数传入10个电影主业的url,并执行以上的Tasks任务

if __name__ == '__main__':
    t1=time.time()
    for page in range(0,250,25):
        url='https://movie.douban.com/top250?start={}&filter='.format(page)
        headers={
    #填入自己的headers信息即可
        }
        loop = asyncio.get_event_loop()
        loop.run_until_complete(get_movie_data(url))
    t2=time.time()
    print(t2-t1)

总结

通过以上协程程序,跑完250个网页,并将提取到的数据写入csv文件共计173秒;

做为初步入门python爬虫之后的第一个晋级程序,初步试验结果如上,关于写入csv文件的环节应该还有效率提升的地方,还有待进一步完善

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值