使用 Python 爬取某网站简历模板(bs4/lxml+协程)


使用 Python 爬取站长素材简历模板


简介

在本教程中,我们将学习如何使用 Python 来爬取站长素材网站上的简历模板。我们将使用requestsBeautifulSoup库来发送 HTTP 请求和解析 HTML 页面。本教程将分为两个部分:第一部分是使用BeautifulSoup的方法,第二部分是使用lxml的方法,并比较两者的差异。

环境准备

首先,确保你已经安装了 Python。然后,安装以下库:

pip install requests beautifulsoup4 lxml

方法一:使用 BeautifulSoup

1.导入库

import requests
from bs4 import BeautifulSoup
import os

2.创建文件夹用于保存爬取的简历图片

if not os.path.exists("resume_templates_images"):
    os.makedirs("resume_templates_images")

3.爬取第一页

first_page_url = "https://sc.chinaz.com/jianli/free.html"
response = requests.get(first_page_url)
response.encoding = 'utf-8'

if response.status_code == 200:
    soup = BeautifulSoup(response.text, 'html.parser')
    templates = soup.find_all('div', class_='box col3 ws_block')

    for template in templates:
        link = template.find('a', target='_blank')['href']
        img = template.find('img')['src']

        if img.startswith('//'):
            img = 'https:' + img

        title = template.find('p').find('a').text.strip()

        img_response = requests.get(img)
        if img_response.status_code == 200:
            img_name = f"{title.replace(' ', '_')}.jpg"
            img_path = os.path.join("resume_templates_images", img_name)
            with open(img_path, 'wb') as f:
                f.write(img_response.content)
        else:
            print(f"下载图片 {img} 失败,状态码: {img_response.status_code}")

4.爬取第二页到第五页

在这里插入代base_url = "https://sc.chinaz.com/jianli/free_"
for page_num in range(2, 6):
    url = f"{base_url}{page_num}.html"
    response = requests.get(url)
    response.encoding = 'utf-8'

    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        templates = soup.find_all('div', class_='box col3 ws_block')

        for template in templates:
            link = template.find('a', target='_blank')['href']
            img = template.find('img')['src']

            if img.startswith('//'):
                img = 'https:' + img

            title = template.find('p').find('a').text.strip()

            img_response = requests.get(img)
            if img_response.status_code == 200:
                img_name = f"{title.replace(' ', '_')}.jpg"
                img_path = os.path.join("resume_templates_images", img_name)
                with open(img_path, 'wb') as f:
                    f.write(img_response.content)
            else:
                print(f"下载图片 {img} 失败,状态码: {img_response.status_code}")
码片

方法二:使用 lxml

first_page_url = "https://sc.chinaz.com/jianli/free.html"
response = requests.get(first_page_url)
response.encoding = 'utf-8'

if response.status_code == 200:
    tree = etree.HTML(response.text)
    templates = tree.xpath('//div[@class="box col3 ws_block"]')

    for template in templates:
        link = template.xpath('.//a[@target="_blank"]/@href')[0]
        img = template.xpath('.//img/@src')[0]

        if img.startswith('//'):
            img = 'https:' + img

        title = template.xpath('.//p/a[@class="title_wl"]/text()')[0].strip()

        img_response = requests.get(img)
        if img_response.status_code == 200:
            img_name = f"{title.replace(' ', '_')}.jpg"
            img_path = os.path.join("resume_templates_images", img_name)
            with open(img_path, 'wb') as f:
                f.write(img_response.content)
        else:
            print(f"下载图片 {img} 失败,状态码: {img_response.status_code}")

同方法一,但使用lxmlxpath方法。

方法比较

• 解析速度:lxml通常比BeautifulSoup快,特别是在处理大型 HTML 文档时。

• 易用性:BeautifulSoup提供了更直观的方法来查找元素,如findfind_all,而lxml使用xpath,这可能需要更多的学习。

• 灵活性:xpath在定位复杂的 HTML 结构时更加灵活,但也需要更复杂的查询。

通过运行我们发现这段代码的执行时间较长,那么我们有没有方法来缩短运行时间呢

import asyncio
import aiohttp
from bs4 import BeautifulSoup
import os
import time  # 导入time模块来记录时间

# 创建一个文件夹resume_templates_images用于保存图片
if not os.path.exists("resume_templates_images"):
    os.makedirs("resume_templates_images")

# 用于存储所有页面的模板数据
all_template_data = []

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def parse_page(session, url):
    soup = BeautifulSoup(await fetch(session, url), 'html.parser')
    templates = soup.find_all('div', class_='box col3 ws_block')

    for template in templates:
        link = template.find('a', target='_blank')['href']
        img = template.find('img')['src']

        if img.startswith('//'):
            img = 'https:' + img

        title = template.find('p').find('a').text.strip()

        async with session.get(img) as img_response:
            if img_response.status == 200:
                img_name = f"{title.replace(' ', '_')}.jpg"
                img_path = os.path.join("resume_templates_images", img_name)
                with open(img_path, 'wb') as f:
                    f.write(await img_response.read())

        all_template_data.append({
            'title': title,
            'img_url': img,
            'link': link
        })

async def main():
    start_time = time.time()  # 记录开始时间

    async with aiohttp.ClientSession() as session:
        # 处理第一页
        await parse_page(session, "https://sc.chinaz.com/jianli/free.html")

        # 处理第二页到第五页
        for page_num in range(2, 6):
            url = f"https://sc.chinaz.com/jianli/free_{page_num}.html"
            await parse_page(session, url)

        # 输出所有页面的模板数据
        for idx, data in enumerate(all_template_data, 1):
            print(f"模板 {idx}:")
            print(f"名称: {data['title']}")
            print(f"图片链接: {data['img_url']}")
            print(f"模板链接: {data['link']}")
            print("=" * 50)

    end_time = time.time()  # 记录结束时间
    run_time = end_time - start_time  # 计算运行时间
    print(f"程序运行时间:{run_time:.2f}秒")

if __name__ == "__main__":
    asyncio.run(main())

这段代码是一个使用asyncioaiohttp库来异步爬取站长素材网站上的简历模板的 Python 脚本。以下是代码的详细解释和如何加快爬取速度的说明:

• parse_page 函数:一个异步函数,用于解析页面内容,提取模板链接和图片链接,并下载图片。

• 异步 I/O:使用asyncioaiohttp可以实现异步 I/O 操作,这意味着在等待网络响应时,程序可以执行其他任务,而不是被阻塞。这样可以显著提高爬取效率,特别是在需要处理多个页面时。
在这里插入图片描述
这段代码是顺序并发执行执行每个页面的爬取,有没有更快的方式——并发执行
• 并发请求:使用asyncio.gather来同时启动多个parse_page任务。

修改代码以实现并发请求

以下是如何修改main函数来实现并发请求:

async def main():
    start_time = time.time()  # 记录开始时间

    async with aiohttp.ClientSession() as session:
        # 处理第一页
        tasks = [parse_page(session, "https://sc.chinaz.com/jianli/free.html")]

        # 处理第二页到第五页,并发执行
        for page_num in range(2, 6):
            url = f"https://sc.chinaz.com/jianli/free_{page_num}.html"
            tasks.append(parse_page(session, url))

        # 等待所有页面处理完成
        await asyncio.gather(*tasks)

        # 输出所有页面的模板数据
        for idx, data in enumerate(all_template_data, 1):
            print(f"模板 {idx}:")
            print(f"名称: {data['title']}")
            print(f"图片链接: {data['img_url']}")
            print(f"模板链接: {data['link']}")
            print("=" * 50)

    end_time = time.time()  # 记录结束时间
    run_time = end_time - start_time  # 计算运行时间
    print(f"程序运行时间:{run_time:.2f}秒")


if __name__ == "__main__":
    asyncio.run(main())

在这个修改后的版本中,所有的页面爬取任务都被添加到一个列表中,然后使用asyncio.gather来并发执行这些任务。这样可以同时发送多个请求,而不是等待一个请求完成后再发送下一个请求,从而加快整体的爬取速度。
在这里插入图片描述
在这里插入图片描述

import asyncio
import aiohttp
from bs4 import BeautifulSoup
import os
import time
import aiofiles

# 创建一个文件夹resume_templates_images用于保存图片
if not os.path.exists("resume_templates_images"):
    os.makedirs("resume_templates_images")

# 用于存储所有页面的模板数据
all_template_data = []
#async with aiohttp.ClientSession() as session
async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()#返回字符串形式的响应数据

async def parse_page(session, url):
    soup = BeautifulSoup(await fetch(session, url), 'html.parser')
    templates = soup.find_all('div', class_='box col3 ws_block')

    for template in templates:
        link = template.find('a', target='_blank')['href']
        img = template.find('img')['src']

        if img.startswith('//'):
            img = 'https:' + img

        title = template.find('p').find('a').text.strip()

        async with session.get(img) as img_response:
            if img_response.status == 200:
                file_type = ".jpg.rar"#  以rar压缩文件的形式储存
                img_name = f"{title.replace(' ', '_')+file_type}"#  更改保存的格式仅需修改
                img_path = os.path.join("resume_templates_images", img_name)
                async with aiofiles.open(img_path, 'wb') as f:
                    await f.write(await img_response.read())# read()返回二进制数据

        all_template_data.append({
            'title': title,
            'img_url': img,
            'link': link
        })

async def main():
    start_time = time.time()  # 记录开始时间

    async with aiohttp.ClientSession() as session:
        # 创建任务列表
        tasks = []

        # 处理第一页
        task = asyncio.create_task(parse_page(session, "https://sc.chinaz.com/jianli/free.html"))
        tasks.append(task)

        # 处理第二页到第五页,并发执行
        for page_num in range(2, 6):
            url = f"https://sc.chinaz.com/jianli/free_{page_num}.html"
            task = asyncio.create_task(parse_page(session, url))
            tasks.append(task)

        # 等待所有页面处理完成  挂起任务列表 asyncio.gather 是 Python asyncio 模块中的一个函数,它用于并发地运行多个协程,并且等待它们全部完成。
        #  asyncio.gather 的作用类似于 asyncio.wait,但它不仅等待协程完成,还会返回一个包含所有结果的列表。
        await asyncio.gather(*tasks)

        # 输出所有页面的模板数据
        for idx, data in enumerate(all_template_data, 1):
            print(f"模板 {idx}:")
            print(f"名称: {data['title']}")
            print(f"图片链接: {data['img_url']}")
            print(f"模板链接: {data['link']}")
            print("=" * 50)

    end_time = time.time()  # 记录结束时间
    run_time = end_time - start_time  # 计算运行时间
    print(f"程序运行时间:{run_time:.2f}秒")

if __name__ == "__main__":
    asyncio.run(main())

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【QGIS入门实战精品教程】4.12:QGIS创建标识码(BSM)字段并生成标识码

文章目录 一、加载实验数据二、生成BSM三、说明一、加载实验数据 加载配套实验数据包(订阅专栏后,从私信查收)中的4.12.rar中的自然幢数据,如下图所示: 打开属性表,查看属性表中的BSM效果: BSM字段说明:字符串,10位长度,以1开头,从1开始的连续序号结尾,总长度为10…

【GL009】C/C++总结(一)

自查目录 1. typedef 和 #define 的区别 2. const 、volatile 和 static 的区别 3. const修饰指针 4. 数组指针和指针数组 5. 函数指针和指针函数 6. C/C内存管理 6.1 内存分布图解 6.2 C语言中的内存分配方式 6.3 堆(Heap)和栈(Sta…

Synchronizad优化原理(JUC)

目录 java对象头一:Monitor二:sychronized的优化轻量级锁(轻量级锁)锁膨胀(重量级锁)(重量级锁)锁自旋偏向锁(比轻量级锁更轻量)偏向锁状态如何撤销偏向锁批量…

Android显示系统(08)- OpenGL ES - 图片拉伸

Android显示系统(02)- OpenGL ES - 概述 Android显示系统(03)- OpenGL ES - GLSurfaceView的使用 Android显示系统(04)- OpenGL ES - Shader绘制三角形 Android显示系统(05)- OpenGL…

Vscode 构建 uniapp vue3 + ts 微信小程序项目

前言 为什么要使用 Vscode 来开发构建 uniapp 项目?从个人角度来讲,仅是想要 Vscode 丰富的插件生态,以及最重要的优秀的 TtypeScript 类型检查支持,因为本人是 TS 重度使用者。 如果你更习惯使用 js 进行开发,使用 …

[游戏开发] Unity中使用FlatBuffer

什么是FlatBuffer 为什么用FloatBuffer,优势在哪? 下图是常规使用的各种数据存储类型的性能对比。 对序列化数据的访问不需要打包和拆包——它将序列化数据存储在缓存中,这些数据既可以存储在文件中,又可以通过网络原样传输&…

软件工程 概述

软件 不仅仅是一个程序代码。程序是一个可执行的代码,它提供了一些计算的目的。 软件被认为是集合可执行的程序代码,相关库和文档的软件。当满足一个特定的要求,就被称为软件产品。 工程 是所有有关开发的产品,使用良好定义的&…

负载均衡策略:L(P)策略;L(Max) ;L(LDS)

负载均衡策略:L(P)策略;L(Max) ;L(LDS) 1. Proportion load distribution L(P)策略; 策略含义:服务器不配置为可变服务率,调度器按照服务器服务率的倒数比例分配负载。即每个服务器分配到的任务量与该服务器服务率的倒数成正比 2. (L(Max)) load distribution((L…

探店小程序:解锁商业新生态,定制未来

在数字化浪潮席卷全球的今天,商业的边界正在被重新定义。随着移动互联网技术的飞速发展,探店小程序作为一种新兴的商业模式,正以其独特的优势迅速成为连接商家与消费者的桥梁。我们刚刚为一家客户成功交付了一款集分销、分润、商业模式定制开…

从EXCEL表格到WEB TABLE的实践

前言 EXCEL管理数据 Bootstrap Bootstrap 是一个流行的开源前端框架,它由 Twitter 的员工开发,用于快速开发响应式和移动设备优先的网页和应用程序。 jQuery jQuery 是一个快速、小巧且功能丰富的 JavaScript 库。它简化了 HTML 文档的遍历、事件处理…

HarmonyOS(65) ArkUI FrameNode详解

Node 1、Node简介2、FrameNode2.1、创建和删除节点2.2、对FrameNode的增删改2.3、 FramNode的查询功能3、demo源码4、总结5、参考资料1、Node简介 在HarmonyOS(63) ArkUI 自定义占位组件NodeContainer介绍了自定义节点复用的原理(阅读本本篇博文之前,建议先读读这个),在No…

独家首发 | 基于 KAN、KAN卷积的轴承故障诊断模型

往期精彩内容: Python-凯斯西储大学(CWRU)轴承数据解读与分类处理 基于FFT CNN - BiGRU-Attention 时域、频域特征注意力融合的轴承故障识别模型-CSDN博客 基于FFT CNN - Transformer 时域、频域特征融合的轴承故障识别模型-CSDN博客 P…

【总结·反思·汇报·思考02】裸辞后,我的一些感想和感悟。

Hello,大家好! 首先,我需要向大家道个歉,对不起!因为最近发生了一些事情,博客文章一直没有更新。(90度鞠躬道歉) 那么,最近到底发生了什么呢?相信大家已经从…

解密分布式锁:保障系统一致性的关键

作者:后端小肥肠 🍇 我写过的文章中的相关代码放到了gitee,地址:xfc-fdw-cloud: 公共解决方案 🍊 有疑问可私信或评论区联系我。 🥑 创作不易未经允许严禁转载。 目录 1. 前言 2. 为何要使用分布式锁&…

HarmonyOS-高级(一)

文章目录 一次开发、多端部署自由流转 🏡作者主页:点击! 🤖HarmonyOS专栏:点击! ⏰️创作时间:2024年12月09日12点19分 一次开发、多端部署 布局能力 自适应布局 拉伸能力均分能力占比能力缩放…

河工oj第七周补题题解2024

A.GO LecturesⅠ—— Victory GO LecturesⅠ—— Victory - 问题 - 软件学院OJ 代码 统计 #include<bits/stdc.h> using namespace std;double b, w;int main() {for(int i 1; i < 19; i ) {for(int j 1; j < 19; j ) {char ch; cin >> ch;if(ch B) b …

开源架构安全深度解析:挑战、措施与未来

开源架构安全深度解析&#xff1a;挑战、措施与未来 一、引言二、开源架构面临的安全挑战&#xff08;一&#xff09;代码漏洞 —— 隐藏的定时炸弹&#xff08;二&#xff09;依赖项安全 —— 牵一发而动全身&#xff08;三&#xff09;社区安全 —— 开放中的潜在危机 三、开…

Ubuntu上使用system()函数运行不需要输入密码

使用system()运行一些终端命令的时候&#xff0c;需要sudo权限&#xff0c;也就是必须输入密码&#xff0c;那么在程序自启动的时候就无法成功启动。如果设置Ubuntu下所有操作都不需要密码&#xff0c;安全性太低&#xff0c;所以我们可以将需要用到的终端指令给予无需输入密码…

HBuilderX(uni-app)Vue3路由传参和接收路由参数!!

uni-app搭建小程序时候Vue3语法接收路由参数&#xff0c;去官方文档查看&#xff0c;是onLoad的option接收参数&#xff0c;我试过&#xff0c;接收不到&#xff0c;上网查各种方法也是不太行&#xff0c;最后自己琢磨出来了&#xff0c;这参数藏得还挺深&#xff01;&#xff…

操作系统(1)OS的基本概念

一、定义 操作系统&#xff08;OS&#xff09;是控制和管理整个计算机系统的硬件与软件资源&#xff0c;并合理地组织、调度计算机的工作与资源的分配&#xff0c;进而为用户和其他软件提供方便接口与环境的程序集合。它是计算机系统中最基本的系统软件。 二、功能 资源管理&am…