Python多线程爬虫——数据分析项目实现详解

前言

在这里插入图片描述
「作者主页」:雪碧有白泡泡
「个人网站」:雪碧的个人网站
请添加图片描述

ChatGPT体验地址

请添加图片描述

文章目录

  • 前言
  • 爬虫
  • 获取cookie
    • 网站爬取与启动
      • CSDN爬虫
      • 爬虫启动
      • 将爬取内容存到文件中
  • 多线程爬虫
    • 选择要爬取的用户
  • 线程池

爬虫

爬虫是指一种自动化程序,能够模拟人类用户在互联网上浏览网页、抓取网页内容、提取数据等操作。爬虫通常用于搜索引擎、数据挖掘、网络分析、竞争情报、用户行为分析等领域。
在这里插入图片描述
我们以爬取某个用户的博文列表并存储到文件中实现多线程爬虫为例,带大家体验爬虫的魅力

获取cookie

首先我们在爬取网站的时候首先获取cookie
在这里插入图片描述

拿我的博客主页为例,用F12打开控制台,点击网络,找到cookie
在这里插入图片描述
创建一个cookie文件,复制进去
然后从给定的cookie_path文件中读取cookie信息,并将其存储在一个字典中。函数返回这个字典。
具体如下

def get_headers(cookie_path:str):
cookies = {}
with open(cookie_path, "r", encoding="utf-8") as f:
cookie_list = f.readlines()
for line in cookie_list:
cookie = line.split(":")
cookies[cookie[0]] = str(cookie[1]).strip()
return cookies

网站爬取与启动

CSDN爬虫

class CSDN(object):
def init(self, username, folder_name, cookie_path):
# self.headers = {
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"
# }
self.headers = get_headers(cookie_path)
self.s = requests.Session()
self.username = username
self.TaskQueue = TaskQueue()
self.folder_name = folder_name
self.url_num = 1
  1. headers: 这是一个字典,用于存储请求头信息。
  2. s: 这是一个会话对象,用于保持与CSDN网站的连接。
  3. username: 这是一个字符串,表示CSDN用户的用户名。
  4. TaskQueue: 这是一个任务队列对象,用于管理待访问的URL。
  5. folder_name: 这是一个字符串,表示保存爬取结果的文件夹名称。
  6. _name: 这是一个整数,表示当前保存的文件夹编号。
  7. _num: 这是一个整数,表示当前爬取的页面编号。

爬虫启动

def start(self):num = 0articles = [None]while len(articles) > 0:num += 1url = u'https://blog.csdn.net/' + self.username + '/article/list/' + str(num)response = self.s.get(url=url, headers=self.headers)html = response.textsoup = BeautifulSoup(html, "html.parser")articles = soup.find_all('div', attrs={"class":"article-item-box csdn-tracking-statistics"})for article in articles:article_title = article.a.text.strip().replace('        ',':')article_href = article.a['href']with ensure_memory(sys.getsizeof(self.TaskQueue.UnVisitedList)):self.TaskQueue.InsertUnVisitedList([article_title, article_href])
  1. 初始化一个变量num,用于表示当前访问的文章页码。
  2. 初始化一个列表articles,用于存储待处理的文章信息。
  3. 使用一个while循环,当articles列表中的文章数量大于0时,执行循环体。
  4. 更新num变量,表示当前访问的文章页码。
  5. 构造一个URL,该URL包含当前用户名、文章列表和页码。
  6. 使用requests库发送请求,并获取响应。
  7. 使用BeautifulSoup库解析HTML内容,并提取相关的文章信息。
  8. 遍历提取到的文章列表,提取文章标题和链接。
  9. 将文章标题和链接插入到任务队列TaskQueue的未访问列表中。

将爬取内容存到文件中

  1. 打印爬取开始的信息。
  2. 计算并获取存储博文列表的文件路径。
  3. 使用open函数以写入模式打开文件,并设置文件编码为utf-8
  4. 写入文件头,包括用户名和博文列表。
  5. 遍历任务队列TaskQueue中的未访问列表,将每篇文章的标题和链接写入文件。
  6. 在每篇文章标题和链接之间添加一个空行,以提高可读性。
  7. 更新一个变量_num,用于表示当前已写入的文章序号。

代码如下

def write_readme(self):print("+"*100)print("[++] 开始爬取 {} 的博文 ......".format(self.username))print("+"*100)reademe_path = result_file(self.username,file_name="README.md",folder_name=self.folder_name)with open(reademe_path,'w', encoding='utf-8') as reademe_file:readme_head = "# " + self.username + " 的博文\n"reademe_file.write(readme_head)for [article_title,article_href] in self.TaskQueue.UnVisitedList[::-1]:text = str(self.url_num) + '. [' + article_title + ']('+ article_href +')\n'reademe_file.write(text)self.url_num += 1self.url_num = 1

列表文件生成之后,我们要对每一个链接进行处理

def get_all_articles(self):try:while True:[article_title,article_href] = self.TaskQueue.PopUnVisitedList()try:file_name = re.sub(r'[\/::*?"<>|]','-', article_title) + ".md"artical_path = result_file(folder_username=self.username, file_name=file_name, folder_name=self.folder_name)md_head = "# " + article_title + "\n"md = md_head + self.get_md(article_href)print("[++++] 正在处理URL:{}".format(article_href))with open(artical_path, "w", encoding="utf-8") as artical_file:artical_file.write(md)except Exception:print("[----] 处理URL异常:{}".format(article_href))self.url_num += 1except Exception:pass
  1. 从任务队列TaskQueue中弹出未访问的文章链接和标题。
  2. 尝试获取一个文件名,该文件名由文章标题生成,以避免文件名中的特殊字符。
  3. 计算并获取存储文章的文件路径。
  4. 创建一个Markdown文件头,包括文章标题。
  5. 获取文章内容,并将其添加到Markdown文件头。
  6. 将处理后的Markdown内容写入文件。
  7. 打印正在处理的URL。
  8. 更新一个变量_num,用于表示已处理的文章数量。

多线程爬虫

实现多线程爬虫,以提高爬取速度。在循环中,会不断地创建新的线程来处理任务队列中的任务,直到任务队列为空。这样可以充分利用计算机的多核性能,提高爬取效率。

def muti_spider(self, thread_num):while self.TaskQueue.getUnVisitedListLength() > 0:thread_list = []for i in range(thread_num):th = threading.Thread(target=self.get_all_articles)thread_list.append(th)for th in thread_list:th.start()

我们在多线程爬虫的时候,要保证系统有足够的内存空间。通过使用contextlib库的contextmanager装饰器,可以轻松地实现上下文管理,确保内存分配和释放的正确性。

lock = threading.Lock()
total_mem= 1024 * 1024 * 500 #500MB spare memory
@contextlib.contextmanager
def ensure_memory(size):global total_memwhile 1:with lock:if total_mem > size:total_mem-= sizebreaktime.sleep(5)yield with lock:total_mem += size

__enter__方法中,使用with lock语句模拟加锁,确保在执行内存分配操作时,不会发生竞争条件。然后判断当前系统的总内存是否大于所需分配的内存空间,如果大于,则减少总内存,并跳出循环。

选择要爬取的用户

def spider_user(username: str, cookie_path:str, thread_num: int = 10, folder_name: str = "articles"):if not os.path.exists(folder_name):os.makedirs(folder_name)csdn = CSDN(username, folder_name, cookie_path)csdn.start()th1 = threading.Thread(target=csdn.write_readme)th1.start()th2 = threading.Thread(target=csdn.muti_spider, args=(thread_num,))th2.start()
  1. 检查文件夹folder_name是否存在,如果不存在,则创建该文件夹。
  2. 创建一个CSDN对象csdn,用于模拟用户登录和爬取文章。
  3. 创建一个线程th1,目标为_readme
  4. 创建一个线程th2,目标为_spider,并传入参数(thread_num,),用于指定线程数量。

这个函数的目的是爬取指定用户的CSDN博客文章,并将文章保存到文件夹folder_name中。通过创建线程,可以实现多线程爬虫,提高爬取速度。

线程池

线程池存储爬虫代理 IP 的数据库或集合。在网络爬虫中,由于目标网站可能会针对同一 IP 地址的访问频率进行限制,因此需要使用池来存储多个代理 IP 地址,以实现 IP 地址的轮换和代理。池可以提高爬虫的稳定性和效率,避免因为 IP 地址被封禁而导致的爬虫失效。
爬虫和池是爬虫领域中不可或缺的概念,池能够提高爬虫的稳定性和效率,同时帮助爬虫更好地适应目标的反爬虫策略。
在这里插入图片描述

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

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

相关文章

达梦数据库 忘记 SYSDBA 密码 处理方法

DM 提供数据库身份验证模式、基于操作系统的身份验证模式、外部身份验证模式和 UKEY 身份验证模式来保护对数据库访问的安全。数据库身份验证模式需要利用数据库口令&#xff0c; 即在创建或修改用户时指定用户口令&#xff0c;用户在登录时输入对应口令进行身份验证;基于操作 …

Kylin 安装novnc 远程访问

noVNC可以使用浏览器直接访问服务器&#xff0c;而不需要使用VNC客户端。 1.初始环境 关闭防火墙或允许IP访问本机 2.安装依赖 dnf install -y tigervnc-server git 3.git下载novnc git clone https://github.com/novnc/noVNC.git 4.配置信任证书 openssl req -new -x509 …

DEJA_VU3D - Cesium功能集 之 119-三维热力图

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小140个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(每篇博文都会奉上完整demo的源代码…

爬虫系列实战:使用json解析天气数据

大家好&#xff0c;爬虫是一项非常抢手的技能&#xff0c;收集、分析和清洗数据是数据科学项目中最重要的部分&#xff0c;本文介绍使用json解析气象局天气数据。 在官网上获取天气数据信息&#xff0c;可以定义当前查询的位置&#xff0c;提取时间、温度、湿度、气压、风速等…

RabbitMQ使用篇

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

(力扣记录)146. LRU 缓存

数据类型&#xff1a;链表 时间复杂度&#xff1a;O(1) 空间复杂度&#xff1a;O(N) 代码实现&#xff1a; class Node:def __init__(self, key-1, value-1):self.key keyself.val valueself.next Noneself.prev Noneclass LRUCache:def __init__(self, capacity: int)…

Django笔记(三):路由urls

首 Django中视图的作用是在链接与视图函数之间做映射。创建完Django项目后&#xff0c;同名文件夹下的urls.py为项目的总路由&#xff08;/project/project/urls.py&#xff09;&#xff1a; from django.contrib import admin from django.urls import pathurlpatterns [pa…

微信小程序带参数分享界面、打开界面加载分享内容

分享功能是微信小程序常用功能之一&#xff0c;带参分享和加载可以让分享对象打开界面时看到和分享内容。 带参分享 用户点击微信小程序右上角自带分享&#xff0c;或者点击自定义分享按钮进行分享时&#xff0c;可在onShareAppMessage函数定义分享行为。 分享界面路径可带参…

USB转SPI USB转IIC 串口转SPI串口转IIC SPI I2C模块

一款支持USB转SPI、USB转I2C、USB转GPIO、USB转PWM、USB转ADC的模块。提供上位机工具&#xff0c;开发协议。 资料下载&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1sw3RCMwjhrMO4qzUBq9bjA 提取码&#xff1a;qzjp 概述 串口转多协议模组为了客户调试一些功能…

PICO Developer Center 创建和调试 ADB 命令

PICO 开发者中心概览 ADB 是一个轻量级的 Android 调试桥(Android Debug Bridge&#xff0c;简称 ADB)&#xff0c;用于与 Android 设备进行通信和调试。ADB提供了许多有用的功能&#xff0c;使开发人员能够轻松地管理和调试设备上的应用程序。 你可以使用 PDC 工具来调试系统…

阿里云服务器4核8G配置收费标准及新老用户优惠价格整理

阿里云服务器4核8g配置云服务器u1价格是955.58元一年&#xff0c;4核8G配置还可以选择ECS计算型c7实例、计算型c8i实例、计算平衡增强型c6e、ECS经济型e实例、AMD计算型c8a等机型等ECS实例规格&#xff0c;规格不同性能不同&#xff0c;价格也不同&#xff0c;阿里云服务器网al…

openssl3.2 - 官方demo学习 - smime - smsign2.c

文章目录 openssl3.2 - 官方demo学习 - smime - smsign2.c概述笔记END openssl3.2 - 官方demo学习 - smime - smsign2.c 概述 PKCS7联合签名 从N张证书中, 分别得到N对(x509和私钥) 对明文进行签名(只是指定了bio_in和flag), 得到pkcs7* 对此pkcs7进行附加签名者的操作(指定证…

SparkSession对象操作--学习笔记

1,SparkSession对象操作 from pyspark.sql import SparkSessionfrom pyspark import SparkConffrom pyspark.sql import functions as F"""创建ss对象时可以指定一些参数如果参数在脚本中不生效&#xff0c;就需要通过saprk-submit指令中进行设置spark sql 的分…

使用 vsCode创建GO项目

最近回顾了一下go的使用&#xff1a;具体操作看下面的参考连接&#xff0c;下面只描述一些踩过的坑&#xff1a; 1. go安装配置 安装go->配置go环境变量 推荐官网下载&#xff0c;速度很快&#xff1b; 这里需要配置五个参数&#xff1a;GOPATH/GOROOT/Path、GO111MODULE/…

基于kubernetes部署MySQL主从环境

部署方式 通过部署mysql主从容器&#xff0c;配置主从pod之间数据同步。 配置数据库访问的密码 创建 Mysql 密码的 Secret [rootk8s-master1 master]# kubectl create secret generic mysql-password --namespaceapp --from-literalmysql_root_passwordroot secret/mysql-pas…

Vue2:给组件绑定自定义事件

一、场景描述 我们在页面开发中&#xff0c;难免要使用事件。 在之前的学习中&#xff0c;我们学过click、keyup、change等事件&#xff0c;这些是Vue自带的事件。 它一般是用在原生的HTML元素上的。在组件上使用需要加native修饰 比如&#xff1a; h1绑定一个click事件&…

如何快速打造属于自己的接口自动化测试框架

1 接口测试 接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。 接口自动化相对于UI自动化来说&#xff0c;属于更底层的测试&#xff0c;这样带来的好处就是测试收益更大&#xff…

WordPress设置回收站自动清理天数的插件Change Empty Trash Time

前面boke112百科跟大家分享的『WordPress回收站自动清空时间&#xff1f;如何关闭回收站或设置自动清理天数&#xff1f;』一文&#xff0c;就介绍了可以添加一行代码实现关闭或设置回收站自动清理时间&#xff0c;也可以通过安装Change Empty Trash Time插件来实现。 今天bok…

【论文阅读】One For All: Toward Training One Graph Model for All Classification Tasks

目录 0、基本信息1、研究动机2、创新点——One For All &#xff1a;unique features3、准备4、具体实现4.1、用TAGs统一来自不同领域的图数据4.2、用NOI&#xff08;NODES-OF-INTEREST&#xff09;统一不同图任务4.2.1、NOI子图4.2.2、NOI提示结点 4.3、用于图的上下文学习&am…

TypeError the JSON object must be str, bytes or bytearray, not ‘list‘

在使用python的jason库时&#xff0c;偶然碰到以下问题 TypeError: the JSON object must be str, bytes or bytearray, not ‘list’ 通过如下代码可复现问题 >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> import json >>> ra json.loads(a) Trac…