导言:异步爬虫——网络数据的获取
随着互联网的快速发展,网络数据成为了现代社会中不可或缺的一部分。如何有效地获取和处理这些数据,成为了许多领域面临的重要问题。异步爬虫作为一种新型的网络数据获取和处理技术,正逐渐受到广泛关注和应用。本文将介绍异步爬虫的基本概念、优势以及在现实生活中的应用,并探讨其未来发展趋势。
一、异步爬虫的基本概念
异步爬虫是一种基于异步编程技术的网络爬虫程序。与传统的同步爬虫相比,异步爬虫在数据获取和处理方面具有更高的效率和灵活性。在异步爬虫中,程序可以同时发起多个请求,并在等待每个请求的响应时,继续执行其他请求。这种非阻塞的通信方式使得异步爬虫能够更高效地利用网络资源,提高数据处理速度。
二、异步爬虫的优势
- 高效率:由于异步爬虫可以同时处理多个请求,因此能够在相同的时间内获取更多的数据,提高了数据获取效率。
- 低延迟:异步爬虫在处理请求时不会阻塞程序执行,因此能够在短时间内快速响应,降低了数据处理延迟。
- 资源利用率高:异步爬虫能够充分利用系统资源,提高数据处理能力。在多核处理器系统中,异步爬虫能够实现真正的并行处理。
- 适应性强:异步爬虫能够适应各种网络环境,无论是稳定的高速网络还是不稳定的长延时网络,都能实现高效的数据获取和处理。
三、异步爬虫的应用
- 搜索引擎:搜索引擎是异步爬虫的重要应用领域之一。通过异步爬虫技术,搜索引擎可以快速地收集和更新网页信息,提高搜索结果的准确性和相关性。
- 数据挖掘和分析:异步爬虫可以用来收集大量数据,并通过数据分析技术挖掘出其中的有价值信息。例如,商业智能、舆情分析等领域都可以利用异步爬虫实现高效的数据获取和分析。
- 自动化测试:在软件测试领域,异步爬虫可以用来模拟用户行为,发起大量的请求来测试系统的性能和稳定性。
- 网络安全监控:网络安全监控是异步爬虫的另一个应用领域。通过收集和分析网络流量数据,异步爬虫可以帮助发现网络攻击、异常流量等安全问题。
四、未来发展趋势
随着互联网技术的不断发展和应用场景的不断扩大,异步爬虫技术也将迎来更多的发展机遇。未来,我们可以预见以下发展趋势:
- 智能化:随着人工智能技术的不断发展,未来的异步爬虫将更加智能化,能够根据应用需求自适应地调整数据获取和处理策略,提高数据处理效率和质量。
- 分布式:随着数据量的不断增大和复杂性的不断提高,未来的异步爬虫将更加分布式,通过多节点协同工作来提高数据处理能力。
- 隐私保护:随着数据安全和隐私保护问题的日益突出,未来的异步爬虫将更加注重隐私保护,采用各种加密和匿名化技术来保护用户隐私。
- 可解释性:未来的异步爬虫将更加注重可解释性,通过提供清晰的数据处理流程和结果解释来帮助用户更好地理解和利用数据。
总之,异步爬虫作为一种新型的网络数据获取和处理技术,具有广泛的应用前景和发展潜力。未来,我们需要不断探索和创新,推动异步爬虫技术的发展和应用,为现代社会的数字化转型提供有力支持。
异步爬虫简介:
下面是我学习异步爬虫时的一些学习笔记:
异步爬虫: -基于线程池 -基于单线程+多任务的异步爬虫 -线程池 -from multiprocessing.dummy import Pool -map(callback(异步的函数),alist(异步的对象)) -可以使用callback,对alist中的每个元素进行制定形式的异步操作 -单线程+多任务异步协程:pip install asyncio -特殊的函数 -如果一个函数的定义被async修饰后,则该函数就变成了一个特殊的函数; -特殊之处: -该特殊的函数被调用后,函数内部的实现语句不会被立即执行 -该特殊函数被调用后会返回一个协程对象 -协程对象 -对象:通过特殊函数的调用返回一个协程对象 -协程 == 特殊函数 ==一组指定操作 -任务对象 -任务对象就是一个高级的协程对象。(任务对象就是对协程对象的进一步封装) -任务 == 协程 == 特殊函数 ==一组指定操作 -如何创建一个任务对象: -asyncio.ensure_future(协程对象) -任务对象的高级之处: -可以给任务对象绑定回调: -task.add_done_callback(task_callback) -回调函数的调用时机: -任务被执行结束后,才可以调用回调函数 -回调函数的参数只可以有一个:表示的就是该回调函数的调用者(任务对象) -使用回调函数的参数调用result()返回的就是任务对象表示的特殊函数的返回值 -事件循环对象 -对象 -作用: -可以将多个任务对象注册/装载到时间循环对象中 -如果开启了时间循环后,则其内部注册/装载的任务对象表示的指定操作就会被基于异步的操作执行 -创建方式: -loop= asyncio.get_event_loop() -注册且启动方式: -loop.run_until_complete(task) -wait方法的作用 -将任务列表中的任务对象赋予可被挂起的权限。只有任务对象被赋予可被挂起的权限后任务对象才可以被挂起 -挂起:将当前的任务对象交出CPU的使用权 -注意事项: -在特殊函数内部不可以出现不支持异步模块对应的代码,否则会中断整个程序的异步效果(如requests) -await关键字 -在特殊函数内部,凡事阻塞操作前都必须使用await进行修饰,await就可以保证阻塞操作在异步执行的过程中不会被跳过 -aiohttp =是一个支持异步的网络请求模块 -使用代码: -大致框架 async def get_requset(url): #实例化好一个请求对象 async with aiohttp.ClientSession() as sess: #调用get发送请求,返回一个响应对象 async with await sess.get(url=url) as response: #获取字符串形式的响应数据 page_text = await response.text() return page_text -补充细节 -在阻塞操作前加上await关键字 -在每一个with前加上async关键字 -多任务爬虫的数据解析 -一定要使用任务对象的回调函数实现数据解析 -why: -多任务的架构中数据的爬取是封装在特殊函数中,我们一定要保证数据请求结束后再实现数据解析 -使用多任务的异步协程爬取数据实现套路: -可以先使用requests模块将待请求数据对应的URl封装到一个列表中(同步) -可以使用aiohttp模块将列表中的url进行异步的请求和数据解析(异步)
实例:
异步爬取表情包网站的表情包:
表情包网址:最新斗图表情 - 爱斗图 - adoutu.com
爬取表情包网址二十页内的表情包并将其下载保存下来
实现方法:
整体代码:
import requests
import parsel
import asyncio
import aiohttp
import re
import os
import time
import aiofiles
from io import BytesIO
headers = {
'Cookie': '_uab_collina=168174060388197251392936; JSESSIONID=870079FC7C9CF454596C43BF8E46E10D; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; RAIL_EXPIRATION=1682022495040; RAIL_DEVICEID=UGNWKvlIttEPrAHYs5qoS3W1LQijGzITNay4GGB_ygWkyDZF_zqWgTu2S0PKEQI5TwP25b13YSymCfctnktfSuC5wJZYBdC5-63VNOTwX3uZwtutxdm1hBZj627PiJ75s1e6FdBVLcWIOgnq6Ch5NA0yJKD2MJrU; fo=2ha297esu02yt2e951tOmP5M61joZTjo-p5_eHo9V2C1t91qCH61-ujGBp_wokyRynYHrf9xVckkj0cwXXk0IF26MK6xEe91migR3MembRNxxKuzKpFuoT5m8IDUyQYN42JxKt_kBlMAhyM8wXGIG6GDXoZLMhApU2fUYq95k-FcucY5QGiIfhlps2U; _jc_save_fromStation=%u957F%u6C99%2CCSQ; _jc_save_wfdc_flag=dc; _jc_save_toStation=%u4E0A%u6D77%2CSHH; route=c5c62a339e7744272a54643b3be5bf64; BIGipServerotn=3973513482.24610.0000; _jc_save_fromDate=2023-04-22; _jc_save_toDate=2023-04-18',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
def get_urls(page):
page_url = f'https://adoutu.com/picture/list/{page}'
datas = []
page_reponse = requests.get(url=page_url,headers=headers)
page_html = page_reponse.text
selector = parsel.Selector(page_html)
div_list = selector.xpath('/html/body/div/div/div/div[3]/div[2]/div/div/a').getall()
for div in div_list:
# print(div)
title = re.findall('title="(.*?)"',div)[0]
url = re.findall('src="(.*?)"',div)[0]
data = {
'title':title,
'url':url
}
datas.append(data)
print(datas)
return datas
async def get_img_data(data):
print(data)
print("准备下载", data['title'])
file_path = "./多线程爬取表情包/异步表情包/"
if not os.path.exists(file_path):
os.mkdir(file_path)
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(url=data['url']) as response:
async with aiofiles.open(file_path + data['title']+'.'+data['url'].split('.')[-1], "wb") as afp:
await afp.write(await response.content.read())
print(data['title']+'.'+data['url'].split('.')[-1], "保存成功")
if __name__ =="__main__":
start_time = time.time()
tasks = []
for page in range(1,20):
datas = get_urls(page)
for data in datas:
c = get_img_data(data)
task = asyncio.ensure_future(c)
# task.add_done_callback(download_img)
tasks.append(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start_time)
代码解释:
因为我们爬取表情包页面链接并不多并不会占用多少时间所以我们先使用同步的方式将一页中的所有表情包链接拿到再去异步的去向这些链接发送请求下载表情包。
同步获取页面内所有的表情包数据:
def get_urls(page):
page_url = f'https://adoutu.com/picture/list/{page}'
datas = []
page_reponse = requests.get(url=page_url,headers=headers)
page_html = page_reponse.text
selector = parsel.Selector(page_html)
div_list = selector.xpath('/html/body/div/div/div/div[3]/div[2]/div/div/a').getall()
for div in div_list:
# print(div)
title = re.findall('title="(.*?)"',div)[0]
url = re.findall('src="(.*?)"',div)[0]
data = {
'title':title,
'url':url
}
datas.append(data)
print(datas)
return datas
异步向表情包数据地址发送请求获取内容并将其使用异步的方式保存到本地文件夹中:
async def get_img_data(data):
print(data)
print("准备下载", data['title'])
file_path = "./多线程爬取表情包/异步表情包/"
if not os.path.exists(file_path):
os.mkdir(file_path)
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(url=data['url']) as response:
async with aiofiles.open(file_path + data['title']+'.'+data['url'].split('.')[-1], "wb") as afp:
await afp.write(await response.content.read())
print(data['title']+'.'+data['url'].split('.')[-1], "保存成功")
主函数实现依次向页面发送请求获取表情包链接,创建事件循环对象将任务对象封装到事件循环对象中并启动循环对象:
if __name__ =="__main__":
start_time = time.time()
tasks = []
for page in range(1,6):
datas = get_urls(page)
for data in datas:
c = get_img_data(data)
task = asyncio.ensure_future(c)
# task.add_done_callback(download_img)
tasks.append(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start_time)
总结:
异步爬虫是一种利用异步编程技术实现的网络爬虫程序。相比于传统的同步爬虫,异步爬虫在数据获取和处理方面具有更高的效率和灵活性。我们用一个简单的异步爬虫实例,用于抓取表情包网站上面的表情包。
- 目标网站分析
首先,我们需要对目标网站进行分析,了解其页面结构和数据结构。在本例中,目标网站是一个、表情包网站,页面结构比较简单,我们可以先解析页面页找到我们想要的每个表情包的链接名字等数据,在通过异步请求的方式向众多链接发送请求,在想目标服务器发送请求等待回应时实施挂起操作进行其它操作等这边回应拿到后再继续进行这边的内容进而忽略等待时间减少总程序运行时间。
2.确定爬取策略
根据目标网站的分析结果,我们可以确定爬取策略。由于目标网站的图片列表和详细内容在同一个页面中展示,我们可以采用深度优先搜索策略,从根节点开始遍历整个页面,找到所有的文章链接,并逐个访问。在遍历的过程中,我们需要注意避免重复访问和循环访问。
3.编写异步爬虫代码
接下来,我们编写异步爬虫代码。在本例中,我们使用Python的异步框架asyncio来实现异步爬虫。首先,我们需要导入目标网站的页面HTML代码,并使用正则表达式或parsel等工具解析出图片链接。然后,我们定义一个异步函数来处理每个表情包链接,包括获取文章标题、内容和评论等信息。在异步函数中,我们使用aiohttp库来发起HTTP请求并获取响应内容。最后,我们将获取到的图片信息使用aiofile库存储到数据库或文件中。
4.行异步爬虫程序
在编写完异步爬虫代码后,我们运行程序并观察程序的执行情况。在本例中,我们可以使用Python的命令行工具来运行程序,并通过输出结果来查看程序是否正常运行。如果程序出现异常或错误,我们可以查看日志文件或调试代码来解决问题。
总之,异步爬虫是一种高效的网络数据获取和处理技术,具有广泛的应用前景和发展潜力。通过一个简单的异步爬虫实例,我们可以了解到异步爬虫的基本原理和实现过程。在实际应用中,我们需要根据不同的场景和需求来选择合适的爬取策略和工具,并注意遵守网站的爬取规则和法律法规的要求。