Python实战:高效爬取mm131图片资源与自动化更新策略
2026/7/15 3:15:47 网站建设 项目流程

1. 项目背景与核心需求

最近在做一个图片资源归档项目,需要定期从特定网站抓取最新图片。经过多次尝试,发现mm131这个站点的资源质量稳定且更新及时,但手动下载效率实在太低。于是决定用Python写个自动化脚本,既能高效抓取图片,又能自动识别新增内容。

这个爬虫需要解决三个核心问题:首先是高效抓取,要能在短时间内完成大量图片下载;其次是稳定性,要能应对网站的反爬机制;最后是可持续性,要能自动识别新内容并增量更新。下面我就把实战中总结的经验分享给大家,这个方案已经稳定运行了半年多,日均抓取上千张图片从没翻车。

2. 环境准备与基础配置

2.1 必备工具清单

工欲善其事必先利其器,先准备好这些工具:

  • Python 3.8+(我用的3.9.7版本最稳定)
  • Requests库(处理HTTP请求)
  • BeautifulSoup4(解析HTML)
  • lxml(加速解析)
  • tqdm(显示进度条)

安装命令很简单:

pip install requests beautifulsoup4 lxml tqdm

2.2 反爬应对策略

现在网站都有基础反爬措施,我们需要做好这些准备:

  1. 用户代理轮换:准备10个常见浏览器的User-Agent
  2. 请求间隔控制:随机延迟1-3秒
  3. 代理IP池(可选):如果是大规模抓取建议配置
  4. Referer设置:模拟从站内跳转

这是我的headers模板,实测有效:

headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Referer': 'https://www.mm131.net/' }

3. 网页结构分析与数据提取

3.1 分页机制解析

首先分析列表页规律,比如首页是:

https://www.mm131.net/xinggan/

翻页后变成:

https://www.mm131.net/xinggan/list_1_2.html

可以看出分页参数在list_1_2.html中,其中1是分类ID,2是页码。

3.2 图片链接提取技巧

通过开发者工具检查元素,发现图集链接藏在article标签里:

<article> <a href="/xinggan/1234.html" title="清纯写真"> <img src="https://img.mm131.net/pic/1234/1.jpg"> </article>

用BeautifulSoup可以这样提取:

soup.find_all('article') for item in articles: title = item.a['title'] url = item.a['href']

3.3 图片详情页抓取

进入图集详情页后,发现图片URL有规律:

https://img.mm131.net/pic/1234/1.jpg https://img.mm131.net/pic/1234/2.jpg ...

只需要替换最后的数字就能获取所有图片。

4. 核心爬虫代码实现

4.1 分页抓取模块

先写个分页抓取函数:

def get_page_list(category, max_page): base_url = f'https://www.mm131.net/{category}/' for page in range(1, max_page+1): url = f'{base_url}list_1_{page}.html' if page > 1 else base_url response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, 'lxml') parse_album_list(soup) # 解析图集列表 time.sleep(random.uniform(1, 3)) # 随机延迟

4.2 图片下载函数

下载函数要考虑重试机制:

def download_image(url, save_path): for retry in range(3): # 最多重试3次 try: resp = requests.get(url, headers=headers, stream=True) if resp.status_code == 200: with open(save_path, 'wb') as f: for chunk in resp: f.write(chunk) return True except Exception as e: print(f'下载失败,重试 {retry+1}/3') time.sleep(2) return False

4.3 自动创建目录结构

按分类+日期自动创建目录:

def create_folder(category): today = datetime.now().strftime('%Y%m%d') path = f'./downloads/{category}/{today}/' if not os.path.exists(path): os.makedirs(path) return path

5. 自动化更新策略

5.1 增量更新机制

每次运行先读取已下载记录:

def get_downloaded_ids(): try: with open('downloaded.json', 'r') as f: return set(json.load(f)) except FileNotFoundError: return set()

下载完成后更新记录:

def update_record(album_id): downloaded = get_downloaded_ids() downloaded.add(album_id) with open('downloaded.json', 'w') as f: json.dump(list(downloaded), f)

5.2 定时任务配置

用APScheduler设置每日定时运行:

from apscheduler.schedulers.blocking import BlockingScheduler sched = BlockingScheduler() @sched.scheduled_job('cron', hour=2) # 每天凌晨2点运行 def daily_job(): main() sched.start()

6. 异常处理与日志记录

6.1 常见错误处理

针对不同错误采取不同策略:

try: response = requests.get(url, timeout=10) except requests.exceptions.Timeout: print('请求超时') except requests.exceptions.TooManyRedirects: print('重定向过多') except requests.exceptions.RequestException as e: print(f'严重错误:{e}')

6.2 日志系统配置

使用logging模块记录运行情况:

import logging logging.basicConfig( filename='spider.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) logging.info('开始下载图集 %s', album_title) logging.warning('图片 %s 下载失败', image_url)

7. 性能优化技巧

7.1 多线程加速

使用线程池提高下载速度:

from concurrent.futures import ThreadPoolExecutor with ThreadPoolExecutor(max_workers=5) as executor: futures = [] for img_url in image_urls: futures.append(executor.submit(download_image, img_url, save_path)) for future in tqdm(as_completed(futures), total=len(futures)): pass # 等待所有任务完成

7.2 内存优化

对于大文件使用流式下载:

response = requests.get(url, stream=True) with open(path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): if chunk: # 过滤keep-alive数据块 f.write(chunk)

8. 完整代码示例

最后给出整合后的核心代码:

import os import json import time import random import requests from bs4 import BeautifulSoup from datetime import datetime from tqdm import tqdm from concurrent.futures import ThreadPoolExecutor class MM131Spider: def __init__(self): self.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Referer': 'https://www.mm131.net/' } self.downloaded = self.load_records() def run(self, category='xinggan', max_page=3): for page in range(1, max_page+1): self.crawl_page(category, page) def crawl_page(self, category, page): url = self.build_url(category, page) soup = self.get_soup(url) albums = soup.find_all('article') with ThreadPoolExecutor(max_workers=5) as executor: list(tqdm( executor.map(self.process_album, albums), total=len(albums), desc=f'第{page}页进度' )) def process_album(self, album): album_url = album.a['href'] if album_url in self.downloaded: return images = self.get_album_images(album_url) save_dir = self.create_save_dir(album.a['title']) for idx, img_url in enumerate(images, 1): self.download_image(img_url, save_dir, idx) self.update_records(album_url) # 其他辅助方法...

这套代码已经处理了大多数异常情况,在实际使用中可以根据需要调整线程数、延迟时间等参数。记得要合理控制请求频率,建议每秒钟不超过2次请求,避免给目标网站造成过大压力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询