当前位置: 首页 > article >正文

Python----Python爬虫(多线程,多进程,协程爬虫)

注意:

        该代码爬取小说不久或许会失效,有时候该网站会被封禁,代码只供参考,不同小说不同网址会有差异 

神印王座II皓月当空最新章节_神印王座II皓月当空全文免费阅读-笔趣阁

一、多线程爬虫

1.1、单线程爬虫的问题

        爬虫通常被认为是IO密集型的程序,因为它们主要依赖于网络请求来获取数据。然而,IO处理的速度相对较慢,可能导致爬虫的整体速度受限。具体来说,单线程爬虫在处理大量网页时效率较低,主要存在以下几个问题:

  1. 速度慢:单线程爬虫只能一个接一个地请求网页,缺乏并发能力。在面对大量网页时,这种逐个请求的方式显著增加了爬取所需的时间。

  2. 资源利用率低:在等待网络响应的过程中,CPU处于闲置状态,未能充分利用系统资源。这种低效利用不仅影响了爬虫的速度,也使得系统资源浪费。

  3. 易受限于网络延迟:网络延迟是影响爬虫效率的重要因素。单线程爬虫在面对高延迟的网络时,整体爬取时间会显著延长,从而降低用户体验。

1.2、原理

        多线程爬虫的核心原理是利用多线程并行处理多个网页请求,从而提高网络请求的并发性,加速数据抓取的过程。在这种架构中,爬虫将URL队列中的链接分配给多个线程进行处理,每个线程负责发送网络请求并获取响应。

具体来说,爬虫的工作流程如下:

  1. URL队列:爬虫首先维护一个包含待爬取URL的队列。每个线程从这个队列中取出一个URL进行处理。

  2. 并行请求:多个线程同时运行,独立地发送网络请求。在等待响应的过程中,线程不会闲置,而是可以继续处理队列中的其他URL。这种并行处理显著减少了整体的爬取时间。

  3. 结果队列:每个线程在获取到网页响应后,将结果存储到一个结果队列中。这个结构确保了数据的有序存储,并允许其他线程安全地读取这些结果。

  4. 数据写入:另一些线程则负责从结果队列中读取数据,并将其写入文件或进行进一步处理。这种分工使得爬虫的各个部分能够高效协作,最大限度地提高资源利用率。

1.3、主要组成部分

1.3.1、URL队列和结果队列

  • URL队列:存储待爬取的URL链接,通常使用线程安全的队列(如queue.Queue),以便多个线程可以安全地访问和修改。

  • 结果队列:用于存放从网页中提取的结果,允许在爬取完成后统一处理或存储。

from queue import Queue
urls_queue = Queue()
out_queue = Queue()

1.3.2、类包装

使用多个线程,不停的取URL队列中的url,并进行处理:

import threading
class ThreadCrawl(threading.Thread):
 def __init__(self, queue, out_queue):
    threading.Thread.__init__(self)
    self.queue = queue
    self.out_queue = out_queue
 def run(self):
    while True:
        item = self.queue.get()

如果队列为空,线程就会被阻塞,直到队列不为空。

处理队列中的 一条数据后,就需要通知队列已经处理完该条数据 

1.3.3、函数包装

from threading import Thread
def func(args):
    pass
if __name__ == '__main__':
    info_html = Queue()
    t1 = Thread(target=func,args=(info_html,))

1.3.4、线程池

import threading  # 导入 threading 模块,用于创建和管理线程  
import time       # 导入 time 模块,使用 sleep 来模拟工作  
import queue      # 导入 queue 模块,使用线程安全的队列  

class Threadingpool():  
    def __init__(self, max_num=10):  
        # 初始化线程池,最大线程数量为 max_num  
        self.queue = queue.Queue(max_num)  # 创建一个最大大小为 max_num 的队列  
        for i in range(max_num):  
            # 将线程类的引用放入队列中  
            self.queue.put(threading.Thread)  

    def getthreading(self):  
        # 从队列中获取一个线程  
        return self.queue.get()  

    def addthreading(self):  
        # 将新的线程类引用放回队列  
        self.queue.put(threading.Thread)  

def func(p, i):  
    # 每个线程执行的函数  
    time.sleep(1)  # 通过休眠1秒来模拟工作  
    print(i)       # 打印传递给函数的索引  
    p.addthreading()  # 线程完成后,将线程返回到池中  

if __name__ == "__main__":  
    p = Threadingpool()  # 创建一个 Threadingpool 实例  
    for i in range(20):  
        thread = p.getthreading()  # 从池中获取一个线程  
        t = thread(target=func, args=(p, i))  # 创建一个新线程,目标函数和参数  
        t.start()  # 启动线程

1.4、多线程函数爬虫

import re  # 导入正则表达式模块  
import requests  # 导入请求库,用于发送HTTP请求  
from fake_useragent import UserAgent  # 导入假用户代理库,用于伪装请求的用户代理  
from lxml import etree  # 导入lxml库,用于解析HTML  
from threading import Thread  # 导入线程模块,用于实现多线程  
import time  # 导入时间模块,用于控制延时  

def sanitize_filename(title):  
    # 替换 Windows 文件名中的无效字符  
    return re.sub(r'[<>:"/\\|?*]', '', title)  

def get_new_url(url):  
    # 设置请求头,伪装成浏览器  
    header = {'User-Agent': UserAgent().edge}  
    # 发送GET请求获取网页内容  
    resp = requests.get(url, header)  
    resp.encoding = 'gbk'  # 设置网页编码为'gbk'  
    e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
    titles = []  # 存储章节标题  
    new_urls = []  # 存储章节链接  

    # 遍历指定范围内的章节  
    for i in range(13, 516):  
        if i == 368:  # 跳过特定章节  
            continue  
        # 获取章节标题并打印  
        print(e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0])  
        titles.append(e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0])  # 添加标题到列表  
        # 构造章节链接并添加到列表  
        new_urls.append('https://www.bbiquge.cc/book_61985/' + e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/@href")[0])  
    
    return titles, new_urls  # 返回标题和链接列表  

def spider(title, new_url):  
    # 设置请求头,伪装成浏览器  
    header = {'User-Agent': UserAgent().edge}  
    # 发送GET请求获取章节内容  
    resp = requests.get(new_url, header)  
    resp.encoding = 'gbk'  # 设置编码为'gbk'  
    e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
    safe_title = sanitize_filename(title)  # 清理标题以作为文件名  
    print(title)  # 打印当前正在抓取的章节标题  
    content = e.xpath("//div[@id='content']/text()")  # 获取章节内容  
    # 打开文件以写入章节内容  
    with open(f'./神印王座/{safe_title}.txt', 'a+', encoding='utf-8') as f:  
        for i in content:  
            f.write(i.strip() + "\n")  # 写入内容并清理空白  
    time.sleep(2)  # 每次抓取后暂停2秒,防止过于频繁的请求  

if __name__ == '__main__':  
    url = 'https://www.bbiquge.cc/book_61985/'  # 目标网址  
    titles, new_urls = get_new_url(url)  # 获取章节标题和链接  
    threads = []  # 存储线程列表  

    # 为每个章节创建一个线程进行抓取  
    for title, new_url in zip(titles, new_urls):  
        thread = Thread(target=spider, args=(title, new_url))  # 创建线程  
        threads.append(thread)  # 添加线程到列表  
        thread.start()  # 启动线程  

    # 等待所有线程完成  
    for thread in threads:  
        thread.join()  # 等待每个线程结束

1.5、多线程类爬虫

import re  # 导入正则表达式模块  
import requests  # 导入请求库,用于发送HTTP请求  
from fake_useragent import UserAgent  # 导入假用户代理库,用于伪装请求的用户代理  
from lxml import etree  # 导入lxml库,用于解析HTML  
from threading import Thread  # 导入线程模块  
import time  # 导入时间模块,用于控制延时  

class NovelSpider(Thread):  
    def __init__(self, title, new_url):  
        super().__init__()  # 调用父类的构造函数  
        self.title = title  # 章节标题  
        self.new_url = new_url  # 章节链接  
        self.headers = {'User-Agent': UserAgent().edge}  # 请求头  

    @staticmethod  
    def sanitize_filename(title):  
        # 替换 Windows 文件名中的无效字符  
        return re.sub(r'[<>:"/\\|?*]', '', title)  

    def run(self):  
        # 发送GET请求获取章节内容  
        resp = requests.get(self.new_url, headers=self.headers)  
        resp.encoding = 'gbk'  # 设置编码为'gbk'  
        e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
        safe_title = self.sanitize_filename(self.title)  # 清理标题以作为文件名  
        print(f"抓取中: {safe_title}")  # 打印当前正在抓取的章节标题  
        content = e.xpath("//div[@id='content']/text()")  # 获取章节内容  
        
        # 打开文件以写入章节内容  
        with open(f'./神印王座/{safe_title}.txt', 'a+', encoding='utf-8') as f:  
            for i in content:  
                f.write(i.strip() + "\n")  # 写入内容并清理空白  
        time.sleep(2)  # 每次抓取后暂停2秒,防止过于频繁的请求  

class NovelCrawler:  
    def __init__(self, base_url):  
        self.base_url = base_url  # 基础网址  
        self.headers = {'User-Agent': UserAgent().edge}  # 请求头  
        self.titles = []  # 存储章节标题  
        self.new_urls = []  # 存储章节链接  

    def get_new_url(self):  
        # 发送GET请求获取网页内容  
        resp = requests.get(self.base_url, headers=self.headers)  
        resp.encoding = 'gbk'  # 设置网页编码为'gbk'  
        e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
        
        # 遍历指定范围内的章节  
        for i in range(13, 516):  
            if i == 368:  # 跳过特定章节  
                continue  
            title = e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0]  # 获取章节标题  
            print(title)  # 打印章节标题  
            self.titles.append(title)  # 添加标题到列表  
            new_url = 'https://www.bbiquge.cc/book_61985/' + e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/@href")[0]  # 构造章节链接  
            self.new_urls.append(new_url)  # 添加链接到列表  

    def run(self):  
        self.get_new_url()  # 获取章节标题和链接  
        threads = []  # 存储线程列表  
        # 为每个章节创建一个线程进行抓取  
        for title, new_url in zip(self.titles, self.new_urls):  
            spider = NovelSpider(title, new_url)  # 创建爬虫实例  
            threads.append(spider)  # 添加线程到列表  
            spider.start()  # 启动线程  

        # 等待所有线程完成  
        for thread in threads:  
            thread.join()  # 等待每个线程结束  

if __name__ == '__main__':  
    url = 'https://www.bbiquge.cc/book_61985/'  # 目标网址  
    crawler = NovelCrawler(url)  # 创建爬虫控制器实例  
    crawler.run()  # 运行爬虫

1.6、 多线程--线程池

import re  # 导入正则表达式模块  
import requests  # 导入请求库,用于发送HTTP请求  
from fake_useragent import UserAgent  # 导入假用户代理库,用于伪装请求的用户代理  
from lxml import etree  # 导入lxml库,用于解析HTML  
from concurrent.futures import ThreadPoolExecutor  # 导入线程池执行器  
import time  # 导入时间模块,用于控制延时  

def sanitize_filename(title):  
    # 替换 Windows 文件名中的无效字符  
    return re.sub(r'[<>:"/\\|?*]', '', title)  

def get_new_url(url):  
    # 设置请求头,伪装成浏览器  
    header = {'User-Agent': UserAgent().edge}  
    # 发送GET请求获取网页内容  
    resp = requests.get(url, headers=header)  
    resp.encoding = 'gbk'  # 设置网页编码为'gbk'  
    e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
    titles = []  # 存储章节标题  
    new_urls = []  # 存储章节链接  

    # 遍历指定范围内的章节  
    for i in range(13, 516):  
        if i == 368:  # 跳过特定章节  
            continue  
        # 获取章节标题并打印  
        title = e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0]  
        print(title)  # 打印章节标题  
        titles.append(title)  # 添加标题到列表  
        # 构造章节链接并添加到列表  
        new_urls.append('https://www.bbiquge.cc/book_61985/' + e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/@href")[0])  
    
    return titles, new_urls  # 返回标题和链接列表  

def spider(title, new_url):  
    # 设置请求头,伪装成浏览器  
    header = {'User-Agent': UserAgent().edge}  
    # 发送GET请求获取章节内容  
    resp = requests.get(new_url, headers=header)  
    resp.encoding = 'gbk'  # 设置编码为'gbk'  
    e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
    safe_title = sanitize_filename(title)  # 清理标题以作为文件名  
    print(f"抓取中: {safe_title}")  # 打印当前正在抓取的章节标题  
    content = e.xpath("//div[@id='content']/text()")  # 获取章节内容  
    # 打开文件以写入章节内容  
    with open(f'./神印王座/{safe_title}.txt', 'a+', encoding='utf-8') as f:  
        for i in content:  
            f.write(i.strip() + "\n")  # 写入内容并清理空白  
    time.sleep(2)  # 每次抓取后暂停2秒,防止过于频繁的请求  

if __name__ == '__main__':  
    url = 'https://www.bbiquge.cc/book_61985/'  # 目标网址  
    titles, new_urls = get_new_url(url)  # 获取章节标题和链接  

    # 使用线程池进行抓取  
    with ThreadPoolExecutor(max_workers=10) as executor:  # 设置最大工作线程数  
        # 为每个章节提交任务  
        for title, new_url in zip(titles, new_urls):  
            executor.submit(spider, title, new_url)  # 提交任务到线程池

二、多进程爬虫

        multiprocessing是python的多进程管理包,和threading.Thread 类似 multiprocessing模块

        multiprocessing模块可以让程序员在给定的机器上充分的利用CPU 在multiprocessing中,通过创建Process对象生成进程,然后调用 它的start()方法

2.1、多进程函数爬虫

import re  # 导入正则表达式模块  
import requests  # 导入请求库,用于发送HTTP请求  
from fake_useragent import UserAgent  # 导入假用户代理库,用于伪装请求的用户代理  
from lxml import etree  # 导入lxml库,用于解析HTML  
from multiprocessing import Process, Manager  # 导入进程和管理器模块  
import time  # 导入时间模块,用于控制延时  

def sanitize_filename(title):  
    # 替换 Windows 文件名中的无效字符  
    return re.sub(r'[<>:"/\\|?*]', '', title)  

def get_new_url(url):  
    # 设置请求头,伪装成浏览器  
    header = {'User-Agent': UserAgent().edge}  
    # 发送GET请求获取网页内容  
    resp = requests.get(url, headers=header)  
    resp.encoding = 'gbk'  # 设置网页编码为'gbk'  
    e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
    titles = []  # 存储章节标题  
    new_urls = []  # 存储章节链接  

    # 遍历指定范围内的章节  
    for i in range(13, 516):  
        if i == 368:  # 跳过特定章节  
            continue  
        # 获取章节标题并打印  
        title = e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0]  
        print(title)  # 打印章节标题  
        titles.append(title)  # 添加标题到列表  
        # 构造章节链接并添加到列表  
        new_urls.append('https://www.bbiquge.cc/book_61985/' + e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/@href")[0])  

    return titles, new_urls  # 返回标题和链接列表  

def spider(title, new_url):  
    # 设置请求头,伪装成浏览器  
    header = {'User-Agent': UserAgent().edge}  
    # 发送GET请求获取章节内容  
    resp = requests.get(new_url, headers=header)  
    resp.encoding = 'gbk'  # 设置编码为'gbk'  
    e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
    safe_title = sanitize_filename(title)  # 清理标题以作为文件名  
    print(f"抓取中: {safe_title}")  # 打印当前正在抓取的章节标题  
    content = e.xpath("//div[@id='content']/text()")  # 获取章节内容  
    # 打开文件以写入章节内容  
    with open(f'./神印王座/{safe_title}.txt', 'a+', encoding='utf-8') as f:  
        for i in content:  
            f.write(i.strip() + "\n")  # 写入内容并清理空白  
    time.sleep(2)  # 每次抓取后暂停2秒,防止过于频繁的请求  

if __name__ == '__main__':  
    url = 'https://www.bbiquge.cc/book_61985/'  # 目标网址  
    titles, new_urls = get_new_url(url)  # 获取章节标题和链接  
    processes = []  # 存储进程列表  

    # 为每个章节创建一个进程进行抓取  
    for title, new_url in zip(titles, new_urls):  
        process = Process(target=spider, args=(title, new_url))  # 创建进程  
        processes.append(process)  # 添加进程到列表  
        process.start()  # 启动进程  

    # 等待所有进程完成  
    for process in processes:  
        process.join()  # 等待每个进程结束

2.2、多进程类爬虫

import re  # 导入正则表达式模块  
import requests  # 导入请求库,用于发送HTTP请求  
from fake_useragent import UserAgent  # 导入假用户代理库,用于伪装请求的用户代理  
from lxml import etree  # 导入lxml库,用于解析HTML  
from multiprocessing import Process  # 导入进程模块  
import time  # 导入时间模块,用于控制延时  

class NovelSpider(Process):  # 继承自 Process  
    def __init__(self, title, new_url):  
        super().__init__()  # 调用父类的构造函数  
        self.title = title  # 章节标题  
        self.new_url = new_url  # 章节链接  
        self.headers = {'User-Agent': UserAgent().edge}  # 请求头  

    @staticmethod  
    def sanitize_filename(title):  
        # 替换 Windows 文件名中的无效字符  
        return re.sub(r'[<>:"/\\|?*]', '', title)  

    def run(self):  
        # 发送GET请求获取章节内容  
        resp = requests.get(self.new_url, headers=self.headers)  
        resp.encoding = 'gbk'  # 设置编码为'gbk'  
        e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
        safe_title = self.sanitize_filename(self.title)  # 清理标题以作为文件名  
        print(f"抓取中: {safe_title}")  # 打印当前正在抓取的章节标题  
        content = e.xpath("//div[@id='content']/text()")  # 获取章节内容  
        
        # 打开文件以写入章节内容  
        with open(f'./神印王座/{safe_title}.txt', 'a+', encoding='utf-8') as f:  
            for i in content:  
                f.write(i.strip() + "\n")  # 写入内容并清理空白  
        time.sleep(2)  # 每次抓取后暂停2秒,防止过于频繁的请求  

class NovelCrawler:  
    def __init__(self, base_url):  
        self.base_url = base_url  # 基础网址  
        self.headers = {'User-Agent': UserAgent().edge}  # 请求头  
        self.titles = []  # 存储章节标题  
        self.new_urls = []  # 存储章节链接  

    def get_new_url(self):  
        # 发送GET请求获取网页内容  
        resp = requests.get(self.base_url, headers=self.headers)  
        resp.encoding = 'gbk'  # 设置网页编码为'gbk'  
        e = etree.HTML(resp.text)  # 解析网页内容为HTML树结构  
        
        # 遍历指定范围内的章节  
        for i in range(13, 516):  
            if i == 368:  # 跳过特定章节  
                continue  
            title = e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0]  # 获取章节标题  
            print(title)  # 打印章节标题  
            self.titles.append(title)  # 添加标题到列表  
            new_url = 'https://www.bbiquge.cc/book_61985/' + e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/@href")[0]  # 构造章节链接  
            self.new_urls.append(new_url)  # 添加链接到列表  

    def run(self):  
        self.get_new_url()  # 获取章节标题和链接  
        processes = []  # 存储进程列表  
        # 为每个章节创建一个进程进行抓取  
        for title, new_url in zip(self.titles, self.new_urls):  
            spider = NovelSpider(title, new_url)  # 创建爬虫实例  
            processes.append(spider)  # 添加进程到列表  
            spider.start()  # 启动进程  

        # 等待所有进程完成  
        for process in processes:  
            process.join()  # 等待每个进程结束  

if __name__ == '__main__':  
    url = 'https://www.bbiquge.cc/book_61985/'  # 目标网址  
    crawler = NovelCrawler(url)  # 创建爬虫控制器实例  
    crawler.run()  # 运行爬虫

三、协程爬虫

        网络爬虫速度效率慢,多部分在于阻塞IO这块(网络/磁盘)。在阻塞 时,CPU的中内核是可以处理别的非IO操作。因此可以考虑使用协 程来提升爬虫效率,这种操作的技术就是协程

协程一种轻量级线程,拥有自己的寄存器上下文和栈,本质是一个进程

相对于多进程,无需线程上下文切换的开销,无需原子操作锁定及同步的开销

简单的说就是让阻塞的子程序让出CPU给可以执行的子程序


一个进程包含多个线程,一个线程可以包含多个协程

多个线程相对独立,线程的切换受系统控制。 多个协程也相对独立,但是其切换由程序自己控制

pip install aiohttp 

属性或方法功能
aiohttp.ClientSession()获取客户端函数
session.get(url)发送get请求
seesion.post(url)发送post请求
resp.status获取响应状态码
resp.url获取响应url地址
resp.cookies获取响应cookie内容
resp.headers获取响应头信息
resp.read()获取响应bytes类型
resp.text()获取响应文本内容
import re  # 导入正则表达式模块  
import aiohttp  # 导入异步HTTP请求库  
import asyncio  # 导入异步库  
from fake_useragent import UserAgent  # 导入假用户代理库,用于伪装请求的用户代理  
from lxml import etree  # 导入lxml库,用于解析HTML  

async def sanitize_filename(title):  
    # 替换 Windows 文件名中的无效字符  
    return re.sub(r'[<>:"/\\|?*]', '', title)  

async def fetch(session, url):  
    # 异步获取网页内容  
    async with session.get(url) as response:  
        return await response.text()  

async def get_new_url(url):  
    header = {'User-Agent': UserAgent().edge}  
    async with aiohttp.ClientSession() as session:  # 创建异步会话  
        resp_text = await fetch(session, url)  # 获取网页内容  
        resp_text.encoding = 'gbk'  # 设置网页编码为'gbk'  
        e = etree.HTML(resp_text)  # 解析网页内容为HTML树结构  
        titles = []  # 存储章节标题  
        new_urls = []  # 存储章节链接  

        # 遍历指定范围内的章节  
        for i in range(13, 516):  
            if i == 368:  # 跳过特定章节  
                continue  
            title = e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/text()")[0]  # 获取章节标题  
            print(title)  # 打印章节标题  
            titles.append(title)  # 添加标题到列表  
            # 构造章节链接并添加到列表  
            new_urls.append('https://www.bbiquge.cc/book_61985/' + e.xpath(f"//div[@id='list']/dl/dd[{i}]/a/@href")[0])  

        return titles, new_urls  # 返回标题和链接列表  

async def spider(title, new_url):  
    header = {'User-Agent': UserAgent().edge}  
    async with aiohttp.ClientSession() as session:  # 创建异步会话  
        resp_text = await fetch(session, new_url)  # 异步获取章节内容  
        resp_text.encoding = 'gbk'  # 设置编码为'gbk'  
        e = etree.HTML(resp_text)  # 解析网页内容为HTML树结构  
        safe_title = await sanitize_filename(title)  # 清理标题以作为文件名  
        print(f"抓取中: {safe_title}")  # 打印当前正在抓取的章节标题  
        content = e.xpath("//div[@id='content']/text()")  # 获取章节内容  
        
        # 打开文件以写入章节内容  
        with open(f'./神印王座/{safe_title}.txt', 'a+', encoding='utf-8') as f:  
            for line in content:  
                f.write(line.strip() + "\n")  # 写入内容并清理空白  

async def main():  
    url = 'https://www.bbiquge.cc/book_61985/'  # 目标网址  
    titles, new_urls = await get_new_url(url)  # 获取章节标题和链接  

    # 创建任务列表并并发执行  
    tasks = [spider(title, new_url) for title, new_url in zip(titles, new_urls)]  
    await asyncio.gather(*tasks)  # 使用 gather() 并发  

if __name__ == '__main__':  
    asyncio.run(main())  # 运行主协程函数

 


http://www.kler.cn/a/569413.html

相关文章:

  • 运维安全计划书,驻场安全运维服务方案(Word完整版56页原件)
  • 如何在优云智算平台上面使用deepseek进行深度学习
  • C#知识|泛型Generic概念与方法
  • 【Leetcode 每日一题】132. 分割回文串 II
  • 重新审视 ChatGPT 和 Elasticsearch:第 2 部分 - UI 保持不变
  • c# winfrom增加进度条
  • WP 高级摘要插件:助力 WordPress 文章摘要精准自定义显示
  • Python Cookbook-2.13 使用C++的类iostream语法
  • 解决 Dell PowerEdge T630 增加第三方 PCIe 设备后制冷系统异常
  • 【深度学习】Hopfield网络:模拟联想记忆
  • JAVA调用Deepseek的api,完成基本对话
  • HTML AI 编程助手
  • Spring系列学习之Spring Messaging消息支持
  • 基于FD-MIMO技术的雷达通信一体化系统波形设计matlab模拟与仿真
  • Android应用app实现AI电话机器人接打电话
  • 如何在netlify一键部署静态网站
  • 【极客时间】浏览器工作原理与实践-2 宏观视角下的浏览器 (6讲) - 2.3 HTTP请求流程:为什么很多站点第二次打开速度会很快?
  • Python Tornado 框架面试题及参考答案
  • 计算机毕业设计Hadoop+Spark+DeepSeek-R1大模型音乐推荐系统 音乐数据分析 音乐可视化 音乐爬虫 知识图谱 大数据毕业设计
  • 视觉图像坐标转换