如何优化Python网络爬虫,提高爬取速度?

news/2024/11/22 18:14:10/

目录

  • 一、提升爬虫的速度
    • 二、并发和并行
      • 三、同步和异步
        • 四、多线程爬虫
        • 五、简单单线程爬虫
    • 多线程
    • 简单的多线程爬虫实例
    • 使用Queue的多线程爬虫
    • 多进程爬虫
    • 使用multiprocessing的多进程爬虫
      • 最后

一、提升爬虫的速度

爬虫可以从获取网页、解析网页、存储数据来实现一些基本的。现在记录一些进阶部分:提升爬虫速度,主要有3中方法:多线程爬虫、多进程爬虫、多协程爬虫。对比普通单线程爬虫,使用这3种方法爬虫的速度能成倍的提升。

二、并发和并行

并发是指在一段时间内发生的若干时间的情况
并行是值在同一时刻发生若干事件的情况

三、同步和异步

同步就是并发并行的各个任务不是独自运行的,任务之间有一定交替顺序,像接力赛一样。
异步就是并发和并行的各个任务独立运行互不干扰。每个任务都不在同一个赛道上面跑步的速度不受其他选手影响

四、多线程爬虫

多线程爬虫是以并发的方式执行的。也就是说,多线程并不能真正的同时执行,而是通过进程的快速切换加快网络爬虫的速度的。
在操作IO的时候使用多线程可以提升程序执行效率

五、简单单线程爬虫

link_list = []
with open(r'C:\Users\K1567\Desktop\alexa.txt', 'r') as file:file_list = file.readlines()for e in file_list:link = e.split('\t')[1]link = link.replace('\n', '')link_list.append(link)
stat = time.time()
for e in link_list:try:r = requests.get(e)print(r.status_code, e)except Exception as erro:print('Error:', erro)
end = time.time()
print('串行的总时长为:', end - stat)

多线程

python两种使用多线程的方法。
函数式:调用_thread模块中的start_new_thread()
类包装式:调用Threading库创建线程,从threading.thread继承。

# 为线程定义一个函数
def print_time(threadName, delay):
count = 0
while count < 3:time.sleep(delay)count += 1print(threadName, time.ctime())
# _thread.start_new_thread(print_time, ("Thread-1", 1))
# _thread.start_new_thread(print_time, ("Thread-2", 2))
# print("Main Finished")class myThread(threading.Thread):
def __init__(self, name, delay):threading.Thread.__init__(self)self.name = nameself.delay = delaydef run(self):print("Starting" + self.name)print_time(self.name, self.delay)print("Exiting" + self.name)def print_time(threadName, delay):counter = 0while counter < 3:time.sleep(delay)print(threadName, time.ctime())counter += 1
threads = []# 创建新线程
thread1 = myThread("Thread-1", 1)
thread2 = myThread("Thread-2", 2)# 开启新线程
thread1.start()
thread2.start()# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)# 等待所有线程完成
for t in threads:t.join()
print("Exiting Main Thread")

run():以表示线程活动的方法
start():启动线程活动
join([time]):组设调用线程直至线程的join()方法被调用为止
isAlive():返回线程是否是活动的
getNmae():返回线程名称
setName():设置线程名
上面代码中,thread1 = myThread(“Thread-1”, 1),然后在myThread这个类中对线程进行设置,使用run()表示线程运行方法当counter小于3时打印线程名称和时间。然后使用thread1.start()开启线程,使用threads.append(thread1)添加线程到线程列表中,用t.join()等待所有线程完成才会继续执行主线程。

简单的多线程爬虫实例

import threading
link_list = []
with open(r'C:\Users\K1567\Desktop\alexa.txt', 'r') as file:file_list = file.readlines()for e in file_list:link = e.split('\t')[1]link = link.replace('\n', '')link_list.append(link)
stat = time.time()class myThread(threading.Thread):def __init__(self, name, link_range):threading.Thread.__init__(self)self.name = nameself.link_range = link_rangedef run(self):print("Starting" + self.name)crawler(self.name, self.link_range)print("Exiting" + self.name)def crawler(threaName, link_range):for i in range(link_range[0], link_range[1] + 1):try:r = requests.get(link_list[i], timeout=20)print(threaName, r.status_code, link_list[i])except Exception as e:print(threaName, 'Error:', e)thread_list = []link_range_list = [(0, 200), (201, 400), (401, 600), (601, 800), (801, 1000)]# 创建
for i in range(1, 6):thread = myThread("Thread-" + str(i), link_range_list[i - 1])thread.start()thread_list.append(thread)
# 等待所有线程完成
for i in thread_list:i.join()
end = time.time()print('简单多线程爬虫的总时长为:', end - stat)

上面代码中,将1000个网页分成5份,然后利用for循环创建了5个线程,将这些网页分别指派到5个线程中运行

使用Queue的多线程爬虫

python的Queue模块提供了同步的、线程安全的队列类,包括FIFO(先进先出)队列、LIFO(后入先出)队列和优先级队列PriorityQueue。
例子:
开启五个线程然后通过队列的方式,把一千个网页平均分配给这五个线程

link_list = []  # 网页连接
with open(r'C:\Users\K1567\Desktop\alexa.txt', 'r') as file:file_list = file.readlines()for e in file_list:link = e.split('\t')[1]link = link.replace('\n', '')link_list.append(link)
# 开始时间
stat = time.time()
# 继承Thread类
class myThread(threading.Thread):def __init__(self, name, q):threading.Thread.__init__(self)self.name = nameself.q = qdef run(self):print("Starting" + self.name)while True:try:crawler(self.name, self.q)except Exception as e:breakprint("Exiting" + self.name)def crawler(threaName, q):# 获取队列中的链接url = q.get(timeout=2)try:r = requests.get(url, timeout=20)print(q.qsize(), threaName, r.status_code, url)except Exception as e:print(q.qsize(), threaName, url, 'Error', e)threadlist = ['Thread-1', 'Thread-2', 'Thread-3', 'Thread-4', 'Thread-5']
# 建立一个队列对象
workQueue = Queue.Queue(1000)
threads = []# 创建新线程
for tName in threadlist:thread = myThread(tName, workQueue)thread.start()threads.append(thread)# 填充队列
for url in link_list:workQueue.put(url)  # 填充队列# 等待所有线程完成
for t in threads:t.join()end = time.time()
print('简单多线程爬虫的总时长为:', end - stat)

多进程爬虫

python的多线程爬虫只能运行在单核上,各个线程以并发的方式异步运行。由于GIL的存在,多线程并不能发挥多核CPU的资源。
作为提升python网络爬虫的速度的另外一种方法,多进程爬虫则可以利用CPU的多核,多进程就需要用到multiprocessing这个库。
使用multiprocess这个库有两种方法,一种是使用Process+queue的方法,另外一种是pool+queue的方法。

使用multiprocessing的多进程爬虫

当进程数大于cpu的内核数量时,等待运行的进程会等其他进程运行完让出内核。所以我们需要了解计算机的cpu核心数量。

查看当前电脑spu核
from multiprocessing import cpu_count
print(cpu_count())

多线程爬虫实例:
1.Process+queue的方法,在多进程中,每个进程都可以单独设置它的属性,如果将daemon设置为true,当父进程结束后,子进程就会自动终止。

from multiprocessing import Queue, Process
link_list = []
with open(r'C:\Users\K1567\Desktop\alexa.txt', 'r') as file:file_list = file.readlines()for e in file_list:link = e.split('\t')[1]link = link.replace('\n', '')link_list.append(link)
stat = time.time()# Process子进程
class MyProcess(Process):def __init__(self, q):Process.__init__(self)self.q = qdef run(self):print("Starting", self.pid)while not self.q.empty():crawler(self.q)print("Exiting" + str(self.pid))def crawler(q):url = q.get(timeout=2)try:r = requests.get(url, timeout=20)print(q.qsize(), r.status_code, url)except Exception as e:print(q.qsize(), url, 'Error', e)if __name__ == '__main__':workQueue = Queue(1000)#     填充队列for url in link_list:workQueue.put(url)for i in range(0, 5):p = MyProcess(workQueue)p.daemon = Truep.start()p.join()end = time.time()print('简单多进程爬虫的总时长为:', end - stat)

2.使用pool+queue的多进程爬虫:当被操作数目不大时,可以直接利用multiprocessing中的process动态生成多个进程,十几个还好,如果成百上千个目标,手动的限制进程数量就太繁琐,此时可以使用pool发挥进程池的功效。

最后

👇👇👇课件源码、资料、素材、解答、皆点击下方获取呀👇👇👇

本文所有模块\环境\源码\教程皆可点击此处跳转免费领


http://www.ppmy.cn/news/47481.html

相关文章

基于html+css的图片展示11

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

腾讯云4核8G轻量服务器12M支持多少访客同时在线?并发数怎么算?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

成功上岸字节35K,技术4面+HR面,耗时20天,真是不容易

这次字节的面试&#xff0c;给我的感触很深&#xff0c;意识到基础的重要性。一共经历了五轮面试&#xff1a;技术4面&#xff0b;HR面。 下面看正文 本人自动专业毕业&#xff0c;压抑了五个多月&#xff0c;终于鼓起勇气&#xff0c;去字节面试&#xff0c;下面是我的面试过…

(排序11)排序的时间复杂度,空间复杂度,稳定性总结

图片总结 内排序时间复杂度总结 内部排序&#xff1a;数据元素全部放在内存中的排序。. 在内排序当中比较快的有希尔排序&#xff0c;堆排序&#xff0c;快速排序&#xff0c;归并排序&#xff0c;这四个排序的时间复杂度都是O(n*logn)。其中希尔排序的时间复杂度更加准确的来…

Windows实现在桌面上双击图标,自动进入到指定网址

功能实现步骤 创建一个快捷方式&#xff0c;右键点击桌面上的空白区域&#xff0c;选择“新建”->“快捷方式”。在弹出的“创建快捷方式”对话框中&#xff0c;输入你想要打开的网站的URL&#xff0c;例如 https://www.bing.com/?mktzh-cn&mktzh-CN &#xff0c;然后…

轻松掌握Qt FTP 机制:实现高效文件传输

轻松掌握Qt FTP&#xff1a;实现高效文件传输 一、简介&#xff08;Introduction&#xff09;1.1 文件传输协议&#xff08;FTP&#xff09;Qt及其网络模块&#xff08;Qt and its Network Module&#xff09; QNetwork:二、QNetworkAccessManager上传实例&#xff08;Qt FTP U…

Ubuntu中使用vscode+cmake进行编译调试

首先新建一个文件夹作为工作空间 mkdir test 进入工作空间文件夹&#xff0c;在vscode中打开 cd test code . 创建一个c文件 #include<iostream>using namespace std;int main(){int a 23;int b a3;for(int i 0; i<10; i){cout<<"hello vs code &a…

《程序员面试金典(第6版)》面试题 16.01. 交换数字(位运算符,异或性质)

题目描述 编写一个函数&#xff0c;不用临时变量&#xff0c;直接交换numbers [a, b]中a与b的值。 示例&#xff1a; 输入: numbers [1,2]输出: [2,1] 提示&#xff1a; numbers.length 2-2147483647 < numbers[i] < 2147483647 解题思路与代码 这道题不让使用额外…