写真集 --爬取脚本
@功能1:实现了反防盗链、翻页、下载写真
@功能2:实现了文件的存储、文件命名、文件的完整性
@功能3:实现了网络异常捕获反馈、日志功能、状态进度条
- 实际演示效果(本文章仅用于学习参考)

演示效果.png

日志数据.png
@_@: 代码写的比较烂希望大佬指出不足!!!
import time
import requests
import csv
import os
import datetime
import urllib.error
from lxml import etree
from tqdm import tqdm
# 注意必须要加Referer该网站有防盗链防盗链原理是依赖Referer来判断的
headers = {
"Referer":"https://www.mzitu.com",
"User-Agent": "Mozilla/4.0 (Windows NT 11.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4430.85 Safari/537.36"
}
#======================================== Gte =================================================
def YEMA():
"""
@功能:实现获取页码总数
:return: 返回数值
"""
try:
url = 'https://www.mzitu.com/'
Session = requests.Session() # 使用Session()方法
GET_html = Session.get(url,headers=headers).text # 使用一个会话
get_xpath = etree.HTML(GET_html)
YeMian = get_xpath.xpath('/html/body/div[2]/div[1]/div[3]/div/a[4]/text()') # 获取页码 属性文本
return int(YeMian[0]) # 返回页码 转换数据类型
except urllib.error.URLError: # 检测网络是否异常
print('抱歉,检测到网络异常错误请稍后重试…… =_=!')
time.sleep(4)
quit()
# 创建日志
path_nome = f'写真数据'
if not os.path.exists(path_nome): # 检测文件是否存在
print(os.mkdir(path_nome), "检测到文件已丢失!--已重新创建") # 创建文件夹
with open('写真数据\\log.csv', 'a+', newline='', encoding='utf-8') as file_log: # 注意必须指定编码newline=''参数为不空行
fieldnames = ['文案/标题', '页面链接', '下载状态码', '作品发布时间', '下载时间','文件状态'] # 标题
# DictWriter()方法初始化一个字典写入对象 该fieldnames参数用于字典
# 注意:key键必须和标题一样否则报错“ValueError: dict contains fields not in fieldnames:”
weiter = csv.DictWriter(file_log, fieldnames=fieldnames)
weiter.writeheader() # 将fieldnames写入标题行
for yemian in range(YEMA()):
session = requests.Session() # 使用session()方法
url = f'https://www.mzitu.com/page/{1+yemian}/' # 拼接页面的url
GET_html = session.get(url, headers=headers).text # 获取文本
get_xpath = etree.HTML(GET_html) # 解析
for shu in range(24): # 一个主页有25个作品
Meizi_int = get_xpath.xpath(f'//*[@id="pins"]/li[{shu+1}]/span[1]//a/@href') # 获取作品链接 href属于属性
Meizi_nome = get_xpath.xpath(f'//*[@id="pins"]/li[{shu+1}]/span[1]/a/text()') # 获取作品名称 属性文本
Meizi_time = get_xpath.xpath(f'//*[@id="pins"]/li[{shu+1}]/span[2]/text()') # 获取发布日期 属性文本
print('页码:',yemian + 1, Meizi_int, Meizi_nome, Meizi_time) # 打印
#========================================= Download ================================================
try:
get_Data = session.get(Meizi_int[0],headers=headers).text # 请求作品页面
Data = etree.HTML(get_Data)
Data_ye = Data.xpath('/html/body/div[2]/div[1]/div[4]/a[5]/span/text()') # 图片数量 属性文本
data = Data_ye[0] # 收集图片数量 去掉列表
bue = tqdm(range(int(data))) # 实例tqdm对象 历遍图片
for i_jpg in bue:
Download_url = Meizi_int[0]+'/'+str(i_jpg) # 拼接下载页面链接
time.sleep(0.8) # 延时8毫秒
Download_get = session.get(Download_url,headers=headers).text # 请求下载页面
Download_Data = etree.HTML(Download_get) # 解析
Data_jpg = Download_Data.xpath('/html/body/div[2]/div[1]/div[3]/p/a/img/@src') # 图片url src属于属性 图片的下载链接 # 作品下载链接
Download_jpg = session.get(Data_jpg[0],headers=headers) # 请求下载图片
# print(Download_jpg)
#========================================= Path ================================================
nome_path = Meizi_nome[0] # 去掉列表
time_path = Meizi_time[0]
patn_file = f"写真数据\\{nome_path}" # 拼接成以标题命名的文件夹
if not os.path.exists(patn_file): # 如果文件存在则不执行如果不存在则执行
os.mkdir(patn_file)
path_jpg = f'写真数据\\{nome_path}\\{i_jpg}_{time_path}.jpg' # 拼接以序号和发布日期命名的文件夹
True_False = os.path.exists(path_jpg) # 检测文件的是否存在存在则输出到进度条
if True_False == False:
with open(path_jpg, 'wb') as flie_Download: # 以二进制模式写入文件
flie_Download.write(Download_jpg.content) # 写入下载的二进制数据(图片)
State = 'Download……'
elif True_False == True:
State = '该文件已存在(扫描中)……'
#========================================= log ================================================
# 日志收集
log_url = Download_url # 页面链接
log_200 = Download_jpg # 下载状态码
log_nome = nome_path # 文案/标题
log_time = time_path # 发布时间
now = datetime.datetime.now()
log_time_i = now.strftime('%Y-%m-%d %H:%M:%S') # 当前时间
cw = csv.writer(file_log) # 初始化写入对象
# 写入内容
weiter.writerow({'文案/标题':log_nome,'页面链接':log_url,'下载状态码':log_200,
'作品发布时间':log_time,'下载时间':log_time_i,'文件状态':State})
bue.set_description(f'{State}') # 进度条标题 状态
except Exception as r: # 捕获异常
print('未知错误 %s' % (r)) # 打印异常
print('抱歉,程序发生异常请联系开发者…… =_=!')
time.sleep(10) # 维持命令行界面