Day:005 | Python爬虫:高效数据抓取的编程技术(爬虫效率)

2024-04-10 23:52

本文主要是介绍Day:005 | Python爬虫:高效数据抓取的编程技术(爬虫效率),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

爬虫之多线程-了解

单线程爬虫的问题

  • 因为爬虫多为IO密集型的程序,而IO处理速度并不是很快,因此速度不会太快
  • 如果IO卡顿,直接影响速度

解决方案
考虑使用多线程、多进程

原理:

爬虫使用多线程来处理网络请求,使用线程来处理URL队列中的url,然后将url返回的结果保存在另一个队列中,其它线程在读取这个队列中的数据,然后写到文件中 。

主要组成部分

URL队列和结果队列

将将要爬去的url放在一个队列中,这里使用标准库Queue。访问url后的结果保存在结果队列中

初始化一个URL队列 

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

 类包装

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

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

        如果队列为空,线程就会被阻塞,直到队列不为空。处理队列中的一条数据后,就需要通知队列已经处理完该条数据

函数包装

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

线程池 

# 简单往队列中传输线程数
import threading
import time
import queueclass Threadingpool():def __init__(self,max_num = 10):self.queue = queue.Queue(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)print(i)p.addthreading()
if __name__ == "__main__":p = Threadingpool()for i in range(20):thread = p.getthreading()t = thread(target = func, args =
(p,i))t.start()
Queue模块中的常用方法 

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步

  • Queue.qsize() 返回队列的大小
  • Queue.empty() 如果队列为空,返回True,反之False
  • Queue.full() 如果队列满了,返回True,反之False
  • Queue.full 与 maxsize 大小对应
  • Queue.get([block[, timeout]])获取队列,timeout等待时间
  • Queue.get_nowait() 相当Queue.get(False)
  • Queue.put(item) 写入队列,timeout等待时间
  • Queue.put_nowait(item) 相当Queue.put(item, False)
  • Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一
  • 个信号
  • Queue.join() 实际上意味着等到队列为空,再执行别的操作

爬虫之多进程-了解 

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

multiprocessing模块

multiprocessing模块可以让程序员在给定的机器上充分的利用CPU

在multiprocessing中,通过创建Process对象生成进程,然后调用它的start()方法

from multiprocessing import Process
def func(name):print('hello', name)
if __name__ == "__main__":p = Process(target=func,args=('sxt',))p.start()p.join()  # 等待进程执行完毕
Manager类,实现数据共享

在使用并发设计的时候最好尽可能的避免共享数据,尤其是在使用多进程的时候。 如果你真有需要 要共享数据,可以使用由Manager()返回的manager提供list, dict, Namespace, Lock, RLock,
Semaphore, BoundedSemaphore, Condition, Event, Barrier,Queue, Value and Array类型的支持

from multiprocessing import
Process,Manager,Lock
def print_num(info_queue,l,lo):with lo:for n in l:info_queue.put(n)
def updata_num(info_queue,lo):with lo:while not info_queue.empty():print(info_queue.get())if __name__ == '__main__':manager = Manager()into_html = manager.Queue()lock = Lock()a = [1, 2, 3, 4, 5]b = [11, 12, 13, 14, 15]p1 = Process(target=print_num,args=
(into_html,a,lock))p1.start()p2 = Process(target=print_num,args=
(into_html,b,lock))p2.start()p3 = Process(target=updata_num,args=
(into_html,lock))p3.start()p1.join()p2.join()p3.join()
from multiprocessing import Process
from multiprocessing import Manager
import time
from fake_useragent import UserAgent
import requests
from time import sleepdef spider(url_queue):while not url_queue.empty():try:url = url_queue.get(timeout = 1)# headers = {'UserAgent':UserAgent().chrome}print(url)# resp =
requests.get(url,headers = headers)# 处理响应结果# for d in
resp.json().get('data'):#     print(f'tid:{d.get("tid")}
topic:{d.get("topicName")} content:
{d.get("content")}')sleep(1)# if resp.status_code == 200:#     print(f'成功获取第{i}页数据')except Exception as e:print(e)
if __name__ == '__main__':url_queue = Manager().Queue()for i in range(1,11):url =
f'https://www.hupu.com/home/v1/news?pageNo=
{i}&pageSize=50'url_queue.put(url)all_process = []for i in range(3):p1 = Process(target=spider,args=
(url_queue,))p1.start()all_process.append(p1)[p.join() for p in all_process]  
 进程池的使用
  • 进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
  • 进程池中有两个方法:
    • apply同步执行-串行
    • apply_async异步执行-并行
from multiprocessing import Pool,Manager
def print_num(info_queue,l):for n in l:info_queue.put(n)
def updata_num(info_queue):while not info_queue.empty():print(info_queue.get())
if __name__ == '__main__':html_queue =Manager().Queue()a=[11,12,13,14,15]b=[1,2,3,4,5]pool = Pool(3)
pool.apply_async(func=print_num,args=
(html_queue,a))pool.apply_async(func=print_num,args=
(html_queue,b))pool.apply_async(func=updata_num,args=
(html_queue,))pool.close() #这里join一定是在close之后,且必须要加join,否则主进程不等待创建的子进程执行完毕pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭

 

from multiprocessing import Pool,Manager
from time import sleep
def spider(url_queue):while not url_queue.empty():try:url = url_queue.get(timeout = 1)print(url)sleep(1)except Exception as e:print(e)
if __name__ == '__main__':url_queue = Manager().Queue()for i in range(1,11):url =
f'https://www.hupu.com/home/v1/news?pageNo=
{i}&pageSize=50'url_queue.put(url)pool = Pool(3)
pool.apply_async(func=spider,args=
(url_queue,))pool.apply_async(func=spider,args=
(url_queue,))pool.apply_async(func=spider,args=
(url_queue,))pool.close()pool.join()

 

爬虫之协程

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

协程一种轻量级线程,拥有自己的寄存器上下文和栈,本质是一个进程
相对于多进程,无需线程上下文切换的开销,无需原子操作锁定及同步的开销


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


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

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

安装 

pip install aiohttp

官网:https://docs.aiohttp.org/en/stable/ 

常用方法

属性或方法功能
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 aiohttp
import asyncio
async def first():async with aiohttp.ClientSession() as
session:  # aiohttp.ClientSession() ==
import requests 模块async with
session.get('http://httpbin.org/get') as
resp:rs = await resp.text()print(rs)
headers = {'User-Agent':'aaaaaa123'}
async def test_header():async with
aiohttp.ClientSession(headers= headers) as
session:  # aiohttp.ClientSession() ==
import requests 模块async with
session.get('http://httpbin.org/get') as
resp:rs = await resp.text()print(rs)async def test_params():async with
aiohttp.ClientSession(headers= headers) as
session:  # aiohttp.ClientSession() ==
import requests 模块async with
session.get('http://httpbin.org/get',params=
{'name':'bjsxt'}) as resp:rs = await resp.text()print(rs)
async def test_cookie():async with
aiohttp.ClientSession(headers=
headers,cookies={'token':'sxt123id'}) as
session:  # aiohttp.ClientSession() ==
import requests 模块async with
session.get('http://httpbin.org/get',params=
{'name':'bjsxt'}) as resp:rs = await resp.text()print(rs)
async def test_proxy():async with
aiohttp.ClientSession(headers=
headers,cookies={'token':'sxt123id'}) as
session:  # aiohttp.ClientSession() ==
import requests 模块async with
session.get('http://httpbin.org/get',params=
{'name':'bjsxt'},proxy =
'http://name:pwd@ip:port' ) as resp:rs = await resp.text()print(rs)
if __name__ == '__main__':loop = asyncio.get_event_loop()loop.run_until_complete(test_cookie())

 

这篇关于Day:005 | Python爬虫:高效数据抓取的编程技术(爬虫效率)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/892507

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi