python爬虫进阶篇(异步)

news2024/11/27 14:43:19

        学习完前面的基础知识后,我们会发现这些爬虫的效率实在是太低了。那么我们需要学习一些新的爬虫方式来进行信息的获取。

异步

        使用python3.7后的版本中的异步进行爬取,多线程虽然快,但是异步才是爬虫真爱。

基本概念讲解

1.什么是异步?

        异步是指在程序执行过程中,当遇到耗时的操作时,不会等待这个操作完成才继续执行后面的代码,而是先去执行其他的操作,等到耗时的操作完成后再处理它的结果。这种方式能够提高程序的并发性响应性。在传统的同步编程中,当程序执行到一个耗时的操作时(比如文件读写、网络请求等),程序会被阻塞,直到这个操作完成才会继续往下执行。这样会导致程序不能充分利用计算资源,同时也会降低程序的响应速度。而在异步编程中,当遇到耗时操作时,程序会先切换到执行其他任务,等到耗时操作完成后再回来处理结果。这样可以让程序在等待耗时操作的同时继续执行其他任务,提高了程序的并发能力和整体性能。

        Python中的异步编程通常使用async/await关键字来定义异步事件,配合asyncio模块和一些第三方库(比如aiohttp、aiofiles等)来实现异步IO操作。异步编程在网络编程、Web开发、爬虫等领域有着广泛的应用。

并发性

        并发性是指在同一时间段内,有多个任务在同时执行。在计算机领域,这通常是指多个线程或进程在同时执行,从而提高了程序的效率和性能。在传统的单线程编程中,程序只能按照顺序执行代码,不能同时执行多个任务,这会导致程序效率低下,特别是当遇到大量IO操作时更为明显。

        而在多线程或多进程编程中,多个任务可以同时运行,从而可以充分利用计算机的多核处理器和其他硬件资源,提高了程序的效率和性能。同时,多线程/多进程编程也可以使得程序更加稳定,因为如果某个线程/进程崩溃或阻塞,其他线程/进程仍然可以继续执行。
        需要注意的是,并发性不同于并行性。并发性是指多个任务在同一时间段内交替执行,而并行性是指多个任务在同一时刻同时执行。并行性需要硬件支持,例如多核处理器、分布式系统等。

I/O操作的概念
        I/O操作是指输入/输出操作,是计算机领域中用来描述数据从外部设备(如磁盘、网络、键盘、显示器等)到内存或相反方向的数据传输过程。在计算机程序中,I/O操作通常涉及到读取或写入文件、网络通信、用户输入输出等操作。

常见的I/O操作
  • - 从磁盘读取文件到内存
  • - 从网络接收数据
  • - 向磁盘写入文件
  • - 向网络发送数据
  • - 从键盘获取用户输入
  • - 向屏幕输出数据

异步与多线程的区别

        多线程和异步都可以提高程序的并发性和响应性,但在不同的场景下可能会有不同的表现。

        多线程适合CPU密集型计算任务,因为它可以充分利用计算机的多核处理器,同时执行多个任务,从而提高程序的效率和性能。但是,在多线程编程中,线程之间需要共享内存,这可能会带来线程安全等问题,需要开发者自己管理线程之间的同步和互斥。

        异步适合I/O密集型任务,因为它可以在等待I/O操作的同时,继续执行其他任务,从而充分利用时间片,提高程序的并发性和响应性。异步编程通常使用事件循环机制,在一个线程中执行多个任务,并通过回调函数等方式处理异步事件。但是,在异步编程中,需要使用特定的异步库和语法,如async/await关键字、协程等,对新手来说有一定的学习。

python中的异步

准备工作

导包,准备好工具

异步
pip install asyncio
异步的文件操作
pip install aiofiles
异步的网路请求
pip install aiohttp

装好之后我们需要学习一些基本的方法。

学习基本语法

1.asyncio的使用

  1. await关键字:

    • await用于暂停当前协程的执行,等待一个异步操作的完成,并获取其结果。
    • 在使用await时,必须将其放在一个async修饰的函数内部,以指示该函数是一个协程函数。
    • await只能在协程函数内部使用,不能在普通函数或全局作用域中使用。
  2. async关键字:

    • async用于修饰一个函数,表示该函数是一个协程函数。
    • 协程函数可以通过await关键字来暂停执行,并在等待异步操作完成后继续执行。
    • 协程函数内部可以包含多个await语句,用于等待不同的异步操作。
  3. asyncio.wait()函数:

    • asyncio.wait()函数用于等待一组协程的完成。
    • 该函数接受一个可迭代对象(如列表或集合),其中包含要等待的协程对象。
    • asyncio.wait()函数返回两个集合,分别表示已完成和未完成的任务。
  4. loop.run_until_complete()方法:
    • loop.run_until_complete()方法用于执行一个协程,直到它完成。
    • 在使用该方法时,必须将协程对象作为参数传递给它。
    • run_until_complete()方法会阻塞当前线程,直到协程执行完成或发生异常。
  5. loop.create_task()方法:
    • loop.create_task()方法用于创建一个协程任务,并将它加入事件循环中等待执行。
    • 该方法接受一个协程函数作为参数,并返回一个Task对象。
    • Task对象表示一个可调度的协程,可以通过await语句来等待其执行完成。

aiofiles

aiofiles是一个用于在异步代码中进行文件 I/O 操作的库。它提供了异步版本的文件读取和写入操作,与标准库中的open()函数不同,aiofiles中的函数返回awaitable对象,可以在异步函数中使用await关键字来等待文件操作完成。

import asyncio
import aiofiles

async def read_and_print_file():
    async with aiofiles.open('example.txt', mode='r') as file:
        content = await file.read()
        print(content)

async def write_to_file():
    async with aiofiles.open('example.txt', mode='w') as file:
        await file.write('Hello, aiofiles!')

# 在事件循环中执行异步文件读写操作
async def main():
    await write_to_file()
    await read_and_print_file()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

记得文件操作属于i/o阻塞

aiohttp

aiohttp是一个用于在异步代码中进行HTTP请求的库。它提供了异步的HTTP客户端和服务器,能够高效地处理大量的并发请求。和request的使用一样

import aiohttp
import asyncio

async def fetch_content(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    url = 'https://jsonplaceholder.typicode.com/posts/1'
    content = await fetch_content(url)
    print(content)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

实战:只看不练假把式,直接干!基础没啥讲的,爬虫会用就行

这次案例,随意教学了,找一个新的网站实现爬取。中间出现错误的情况我也会直接列出来(我也是菜鸡,只是帮助大家入门的)。给大家分享一下我的思路和解决。

本博客只用于教学爬虫,决定爬取一个:

极简壁纸_海量电脑桌面壁纸美图_4K超高清_最潮壁纸网站

合理使用,这个网站是免费的并且还是免登录(良心网站,请求一两次就行,别一直搞(哭了,现在看我写这句话真是讽刺)),较为容易(容易个der,给我看懵逼了)

兄弟们这个案例当乐子看。

1.准备工作,了解网站结构,查看是否可以直接爬取。

这个主要是看源码中是否和前端调试工具中的结构一样,我们发现,调试工具中有的 是一个a中存在一个链接,但是我们点击打开发现是一个404页面

此时我以为这个是无效链接,然后我直接去看了网络请求,发现网络请求是可以获得图片的,但是在找url的关系时,我发现直接请求a中的地址也是可行的。

我们试一下发送请求,看看能不能获取到这张图片。

直接一顿操作

import requests


url = "https://api.zzzmh.cn/bz/v3/getUrl/c071cdc46f0c4867a1d52d0cb51fc6d629"

headers = {
    
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
}
response = requests.get(url,headers=headers).content

print(response)

我们发现出现了403界面源码,这就有点不对劲了。

那么我们学过的东西无法解决,表明需要学习新的知识了

在网页请求的头部中,包含了一个名为"Referer"的字段,这个字段通常用来标识当前请求是从哪个页面跳转过来的,即上一个网页的地址。这对于网站分析和统计访问来源非常有用,同时也可以在一定程度上用于防盗链和安全验证。在实际开发中,服务器端可以通过检查"Referer"字段来确定请求的来源,并做出相应的处理,例如允许或拒绝特定来源的请求。同时,网站管理员也可以利用这个字段来分析用户的访问行为和流量来源,为网站运营和优化提供参考依据。

搜嘎,现在我们在headers中加入Referer来测试一下

直接出现,现在把他写入文件中试一下,

import requests


url = "https://api.zzzmh.cn/bz/v3/getUrl/c071cdc46f0c4867a1d52d0cb51fc6d629"

headers = {
    "Referer":"https://bz.zzzmh.cn/",
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
}
response = requests.get(url,headers=headers).content

with open("壁纸.jpg",'wb') as file:
    file.write(response)

直接成功:网页请求也是可行的,但是在拼接url的时候还得来到这里。

为什么我们点击页面链接发现时进入一个404呢,我感觉是因为点击后的并没有发送请求,无法访问。

如何批量获取这些数据? 我们复制链接进源码看一下,发现并没有这段链接,那么这个需要找js代码,观察是否需要进行解密。寄了,我看蒙蔽了,大哥这是个人站?这么难吗?给我直接看蒙蔽了,js学是学过,但是那都是基础,后悔了早知道选哪个需要登录的了,不行我都干了四千多字了,怎么说也得爬几个。哥几个别爬了,我找半小时了。太难看了,我纯纯弱智,找这个爬。这反爬比爬网易云免费音乐还难,看这个过过眼瘾。看不懂没关系,我也不会。等我后续把js逆向学明白再带大家做这个。(其实后面介绍的selenium完全可以爬取这些链接,但是缺点就是速度太慢了。)
爬虫案例1:js逆向获取极简壁纸的高清壁纸_爬虫爬取极简壁纸_活火石的博客-CSDN博客

补充,使用自动化工具也可以爬取,就是速度太慢了。(其实也不算很慢,这里就打开的时候比较慢 有2秒等待时间,但是获取图片采用的是异步获取和处理,速度还是很快的。)

import time
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import requests

import asyncio
import aiofiles
import aiohttp

headers = {
    'Referer': 'https://bz.zzzmh.cn/',
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
}
async def download(href,count):
    print(f"第{count}图片开始缓存")
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(href,headers=headers) as p:
                data = await p.read()
                async with aiofiles.open(f"D:\桌面\pythoncode\爬虫案例\Selenium入门\极简壁纸\{count}.jpg",'wb') as file:
                    await file.write(data)
                print(f"第{count}图片缓存成功")
    except:
        print(f"第{count}图片缓存失败")


async def main():
    web = webdriver.Chrome()
    web.get("https://bz.zzzmh.cn/index")
    time.sleep(3)
    img_List  = web.find_elements(by="xpath",value='//div[@class="img-box"]')
    count = 1
    task = []
    for i in img_List:
        src = i.find_element(by="xpath",value='./span[@class="down-span"]/a')
        src= src.get_attribute('href')
        print(src)
        t = asyncio.create_task(download(src,count))
        task.append(t)
        count+=1
    return await asyncio.wait(task)
if __name__=="__main__":
    asyncio.run(main())    


案例2

上面那个案例给我整吐了,不行了,换回老朋友笔趣阁。

神秘复苏最新章节_神秘复苏全文在线阅读_佛前献花的小说_笔趣阁

1.查看网页源代码和检查中的链接是否一致 

直接爬取每个章节的内容,然后装填进一个数组中,我们爬取这些章节小说可以使用异步来进行。所以现在只需要解析出链接,然后交给异步即可。

注意此时的编码方式

获取请求链接
 

import requests
import aiofiles
import aiohttp
from lxml import etree
import asyncio




async def main():
    url = "https://www.bige3.cc/book/66/"
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
    }
    response = requests.get(url)
    response.encoding = 'utf-8'
    en = etree.HTML(response.text)
    title_List = en.xpath("//div[@class='listmain']/dl//dd")
    print(title_List)
if __name__=="__main__":
    asyncio.run(main())

解析链接和上个一样,区别在于此次获取每个章节的内容采用aiohttp 写入文件使用aiofiles 需要再阻塞前加入等待 await

装填链接

import requests
import aiofiles
import aiohttp
from lxml import etree
import asyncio



async def download(url):
    pass


async def main():
    url = "https://www.bige3.cc/book/66/"
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
    }
    response = requests.get(url)
    response.encoding = 'utf-8'
    en = etree.HTML(response.text)
    task = []
    title_List = en.xpath("//div[@class='listmain']/dl//dd")
    for i in title_List:
        src = i.xpath("./a/@href")[0]
        src = "https://www.bige3.cc/" + src
        t = asyncio.create_task(download(src))
        task.append(t)
    return await asyncio.wait(task)
if __name__=="__main__":
    asyncio.run(main())

 我们要注意asyncio.wait()这个过程需要等待所以加入了await 

下载内容

直接看界面,源码中存在小说内容,所以直接爬取就行。

 直接爬取:注意i/o阻塞的位置加入await即可,就是和之前的相比加入了一个async而已,没啥区别

import requests
import aiofiles
import aiohttp
from lxml import etree
import asyncio

async def download(url):
    try:
        print("小说开始下载")
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as r:
                response = await r.text()
                en = etree.HTML(response)
                file_Title = en.xpath('//h1[@class="wap_none"]/text()')[0]
                file_Content = en.xpath('//*[@id="chaptercontent"]/text()')
                file_Content = ("".join(file_Content)).replace("\u3000","\n")
                file_Title = f"D:\桌面\pythoncode\爬虫教学\神秘复苏\{file_Title}.txt"
                async with aiofiles.open(file_Title,'w',encoding='utf-8') as file:
                    await file.write(file_Content)
                print("小说下载成功")
    except:
        print("下载失败")

async def main():
    url = "https://www.bige3.cc/book/66/"
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
    }
    response = requests.get(url)
    response.encoding = 'utf-8'
    en = etree.HTML(response.text)
    task = []
    title_List = en.xpath("//div[@class='listmain']/dl//dd")
    for i in title_List:
        src = i.xpath("./a/@href")[0]
        src = "https://www.bige3.cc/" + src
        t = asyncio.create_task(download(src))
        task.append(t)
    return await asyncio.wait(task)
if __name__=="__main__":
    asyncio.run(main())

直接轻轻松松爬取一本小说且顺序是有序的。期待下次更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1257206.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光线追踪-Peter Shirley的RayTracing In One Weekend系列教程(book1-book3)代码分章节整理

自己码完了一遍了,把代码分章节整理了一下,可以按章节独立编译,运行, 也可以直接下载编译好的release版本直接运行。 项目地址: Github: https://github.com/disini/RayTracingInOneWeekendChaptByChapt ​ ​ ​ ​

【赠书第8期】工程效能十日谈

文章目录 前言 1 工程效能十日谈 1.1 制定清晰的目标和计划 1.2 引入先进的技术和工具 1.3 建立有效的沟通机制 1.4 灵活应对变化 1.5 确保资源充足 1.6 进行有效的风险管理 1.7 进行持续的监控和评估 1.8 优化团队合作 1.9 注重质量管理 1.10 进行项目总结和反思 …

【Amazon】安装Cloudwatch代理监控EC2

文章目录 一、实验概要二、实验操作步骤2.1 创建 CloudWatch 代理运行角色2.2 安装 CloudWatch 代理软件包2.3 使用 CloudWatch代理收集指标2.4 CloudWatch指标收集确认 三、参考链接 一、实验概要 使用 CloudWatch 代理从 Amazon EC2 实例和本地服务器中收集指标、日志和跟踪信…

NetSuite 应用性能管理器(APM)

前段时间,我们发过一个文章谈系统健康检查。 NetSuite ERP系统健康检查-CSDN博客文章浏览阅读119次。“健康检查”本质上是属于信息化持续改善的组成部分。如果说信息化是一个持续不断的过程的话,那么“健康检查”就是持续不断的PDCA中的Check那一环。h…

pygame加载图像,并让小球做平抛运动

文章目录 load转换和存储自由落体 在游戏设计中,图像显示是必不可少的功能,pygame中的image模块便用于加载图像。 load 通过load函数,可以加载多种图像格式,如下表所示 旧版本bmp, gpeg, png, pcx, tiff, xpmc, lbm(以及pbm, p…

CountDownLatch实战应用——批量数据多线程协调异步处理(主线程执行事务回滚)

😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: CountDownLatch实战应用——批量数据多线程协调异步处理(主线程执行事务…

MIT 6.824 -- MapReduce Lab

MIT 6.824 -- MapReduce Lab 环境准备实验背景实验要求测试说明流程说明 实验实现GoLand 配置代码实现对象介绍协调器启动工作线程启动Map阶段分配任务执行任务 Reduce 阶段分配任务执行任务 终止阶段 崩溃恢复 注意事项并发安全文件转换golang 知识点 测试 环境准备 从官方gi…

nginx配置文件的简单结构

nginx的配置文件(nginx.conf)整体上可分为三个部分:全局块、events块、http块 区域职责全局块配置和nginx运行相关的全局配置events块配置和网络连接相关的配置http块配置代理、缓存、日志记录、虚拟主机等配置在http块中,可以包含…

Linux的基本指令(四)

目录 前言 时间相关的指令 date指令 时间戳 日志 时间戳转化为具体的时间 cal指令 find指令(十分重要) grep指令(行文本过滤工具) 学前补充 什么是打包和压缩? 为什么要打包和压缩? 怎么打包和…

【洛谷算法题】P5715-三位数排序【入门2分支结构】

👨‍💻博客主页:花无缺 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5715-三位数排序【入门2分支结构】🌏题目描述🌏输入格式…

基于OGG实现MySQL实时同步

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

常见树种(贵州省):020女贞、异叶梁王茶、掌叶梁王茶、鹅掌柴、楤木、柞木、华重阳木、马蹄荷、山桐子、刺楸

摘要:本专栏树种介绍图片来源于PPBC中国植物图像库(下附网址),本文整理仅做交流学习使用,同时便于查找,如有侵权请联系删除。 图片网址:PPBC中国植物图像库——最大的植物分类图片库 一、女贞 …

我的创作纪念日-五周年

机缘 5年前,作为一名技术人员,平时利用CSDN作为学习平台工具,帮助解决工作中遇到的问题。随着30、35中年危机渐行渐近,回过头来发现平时虽然也有记录整理学习笔记的习惯,但还没有一个可以持续鞭笞自己和记录自己学习的…

C#,数值计算——插值和外推,RBF_fn 与 RBF_gauss 的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public interface RBF_fn { double rbf(double r); } } ---------------------------------------------- using System; namespace Legalsoft.Truffer { public class RBF_gauss : RBF…

transformers pipeline出现ConnectionResetError的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

上海亚商投顾:北证50指数大涨 逾百只北交所个股涨超10%

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 一.市场情绪 沪指11月24日震荡调整,深成指、创业板指盘中跌超1%。北证50指数大涨超6%,北交所个股持…

[架构之路-253]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 结构化设计的主要评估指标:高内聚(模块内部)、低耦合(模块之间)的含义

目录 前言: 一、软件工程中的软件设计种类:根据宏观到微观分 (1)软件架构设计(层次划分、模块划分、职责分工): (2)软件高层设计、概要设计(功能模块的接…

[设计模式] 常见的设计模式

文章目录 设计模式的 6 大设计原则设计模式的三大分类常见的设计模式有哪几种1. 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。(连接池)1. 饿汉式2. 懒汉式3. 双重检测 2. 工厂模式3. 观察者模式● 推模型● 拉…

Windows上常用的dos命令

cd更改目录 cd c:\users从其他目录改成c:\users。 type显示文件内容 type good.txt显示文件good.txt里边的内容。 del删除文件 del good.txt删除文件。

(C++)string类的模拟实现

愿所有美好如期而遇 前言 我们模拟实现string类不是为了去实现他,而是为了了解他内部成员函数的一些运行原理和时间复杂度,在将来我们使用时能够合理地去使用他们。 为了避免我们模拟实现的string类与全局上的string类冲突(string类也在std命名空间中)&…