使用 Python 爬取某网站简历模板(bs4/lxml+协程)
使用 Python 爬取站长素材简历模板
简介
在本教程中,我们将学习如何使用 Python 来爬取站长素材网站上的简历模板。我们将使用requests
和BeautifulSoup
库来发送 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}")
同方法一,但使用lxml
的xpath
方法。
方法比较
• 解析速度:lxml
通常比BeautifulSoup
快,特别是在处理大型 HTML 文档时。
• 易用性:BeautifulSoup
提供了更直观的方法来查找元素,如find
和find_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())
这段代码是一个使用asyncio
和aiohttp
库来异步爬取站长素材网站上的简历模板的 Python 脚本。以下是代码的详细解释和如何加快爬取速度的说明:
• parse_page 函数:一个异步函数,用于解析页面内容,提取模板链接和图片链接,并下载图片。
• 异步 I/O:使用asyncio
和aiohttp
可以实现异步 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())
原文地址:https://blog.csdn.net/F2022697486/article/details/144338843
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!