Python3实现Yande.re图片爬虫,适合新手边学边写

Yande.re 图片爬虫

前言

每天打开电脑第一件事,就是打开Y 站,看看又更新了哪些图片、其中又有哪些适合作为壁纸

日久天长,总会感觉浪费时间精力,每天都要在一堆图片里找 PC 壁纸

这可不符合我作为一个码农的身份

正好最近想学学Python3,于是一边看着廖学峰的 Python 教程一边撸出来这个项目。写得很差,轻喷

本项目基于Win7Python3.5.2开发,其他环境下未测试

功能

  • 支持从指定的开始页码爬取到结束页码
  • 也支持从第一页爬取到上一次开始爬取的位置
  • 支持设置爬取的图片类型(全部、横图、竖图、正方形)
  • 支持最大或最小图片尺寸宽高比限制
  • 按照当天的日期创建目录并存放爬取的图片
  • 爬取结束后会在图片目录下生成日志文件

如何使用

必须 编辑Function.py5行,将该变量的值设为自己想要的目录,程序将会自动创建,路径必须以斜杠结尾

  • 方案一:如果想要从开始页码爬到结束页码,请修改index.py12行和第15行的两个变量;
  • 方案二:如果想要从开始页码爬取到上一次开始爬取的位置,请修改index.py15行的值为0。还有last_start_id.data的内容,改为某张图片的 id 即可。爬到此图片时程序将停止。该方案下推荐将开始页码设为1,相当于每次执行都只从新增的图片中爬取

例如某图片的详情页 Url 为:https://yande.re/post/show/346737,则图片 id 为346737

然后命令行执行python index.py即可( Windows 下)。 Linux 下可直接执行

注意事项

值得一提的是,无论使用哪种方案运行,last_start_id.data的内容都会被自动修改为爬取到的第一张图片的 id

这样做的目的是为了实现方案二,相当于每次执行都只从新增的图片中爬取。比较适合设置为自动运行之类的

项目地址

https://github.com/mokeyjay/Yandere-crawler


Python3实现Yande.re图片爬虫,适合新手边学边写

5 回复

酷!


我来写一个适合新手的Yande.re图片爬虫,从基础开始一步步实现。

import requests
import os
from bs4 import BeautifulSoup
import time
from urllib.parse import urljoin
import re

class YandereCrawler:
    def __init__(self, save_dir='yandere_images'):
        self.base_url = 'https://yande.re'
        self.save_dir = save_dir
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        })
        
        # 创建保存目录
        if not os.path.exists(save_dir):
            os.makedirs(save_dir)
    
    def get_page_images(self, page_url):
        """获取单页的所有图片链接"""
        try:
            response = self.session.get(page_url, timeout=10)
            response.raise_for_status()
            
            soup = BeautifulSoup(response.text, 'html.parser')
            image_links = []
            
            # 查找所有图片缩略图链接
            for img in soup.find_all('a', class_='thumb'):
                if img and img.get('href'):
                    detail_url = urljoin(self.base_url, img['href'])
                    # 获取详情页中的大图
                    image_url = self.get_image_from_detail(detail_url)
                    if image_url:
                        image_links.append(image_url)
            
            return image_links
            
        except requests.RequestException as e:
            print(f"获取页面失败: {e}")
            return []
    
    def get_image_from_detail(self, detail_url):
        """从详情页获取大图链接"""
        try:
            response = self.session.get(detail_url, timeout=10)
            response.raise_for_status()
            
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 查找大图链接
            img_tag = soup.find('img', id='image')
            if img_tag and img_tag.get('src'):
                return urljoin(self.base_url, img_tag['src'])
            
            # 备用查找方式
            img_tag = soup.find('a', class_='original-file-changed')
            if img_tag and img_tag.get('href'):
                return urljoin(self.base_url, img_tag['href'])
            
            return None
            
        except requests.RequestException as e:
            print(f"获取详情页失败: {e}")
            return None
    
    def download_image(self, image_url, filename=None):
        """下载单张图片"""
        try:
            response = self.session.get(image_url, timeout=30)
            response.raise_for_status()
            
            # 如果没有指定文件名,从URL提取
            if not filename:
                filename = image_url.split('/')[-1]
                # 清理文件名
                filename = re.sub(r'[^\w\.\-]', '_', filename)
            
            save_path = os.path.join(self.save_dir, filename)
            
            # 保存图片
            with open(save_path, 'wb') as f:
                f.write(response.content)
            
            print(f"已下载: {filename}")
            return True
            
        except requests.RequestException as e:
            print(f"下载失败 {image_url}: {e}")
            return False
    
    def crawl_by_tags(self, tags, pages=1):
        """根据标签爬取多页图片"""
        all_images = []
        
        for page in range(1, pages + 1):
            print(f"正在爬取第 {page} 页...")
            
            # 构建搜索URL
            tag_param = '+'.join(tags)
            page_url = f"{self.base_url}/post?tags={tag_param}&page={page}"
            
            image_urls = self.get_page_images(page_url)
            all_images.extend(image_urls)
            
            # 避免请求过快
            time.sleep(1)
        
        return all_images
    
    def crawl_by_page_range(self, start_page=1, end_page=3):
        """爬取指定页数范围的图片"""
        all_images = []
        
        for page in range(start_page, end_page + 1):
            print(f"正在爬取第 {page} 页...")
            
            page_url = f"{self.base_url}/post?page={page}"
            image_urls = self.get_page_images(page_url)
            all_images.extend(image_urls)
            
            # 下载当前页的所有图片
            for img_url in image_urls:
                self.download_image(img_url)
                time.sleep(0.5)  # 避免请求过快
            
            time.sleep(1)
        
        return all_images

# 使用示例
if __name__ == "__main__":
    # 创建爬虫实例
    crawler = YandereCrawler(save_dir='yandere_downloads')
    
    # 方法1: 爬取指定页数
    print("=== 方法1: 爬取前3页 ===")
    crawler.crawl_by_page_range(start_page=1, end_page=3)
    
    # 方法2: 根据标签爬取
    print("\n=== 方法2: 根据标签爬取 ===")
    tags = ['solo', 'rating:safe']  # 安全评级的单人图片
    image_urls = crawler.crawl_by_tags(tags, pages=2)
    
    # 批量下载找到的图片
    print(f"\n找到 {len(image_urls)} 张图片,开始下载...")
    for i, img_url in enumerate(image_urls, 1):
        print(f"下载进度: {i}/{len(image_urls)}")
        crawler.download_image(img_url)
        time.sleep(0.5)

这个爬虫包含了几个关键部分:

  1. 基础请求:使用requests.Session保持会话,设置User-Agent模拟浏览器
  2. 页面解析:用BeautifulSoup解析HTML,提取图片链接
  3. 图片下载:从详情页获取大图链接并下载保存
  4. 两种爬取模式:按页数爬取和按标签搜索爬取
  5. 错误处理:基本的异常捕获和重试机制

代码结构清晰,每个函数都有明确的功能,适合新手学习HTTP请求、HTML解析、文件操作等基础概念。运行前需要安装requests和beautifulsoup4库。

总结:从基础请求开始,逐步实现完整爬虫功能。

我在写这个程序的时候也注意到了……并发会导致被禁止访问一阵子,所以最终成品是单线程的……跟我手动访问也差不多啦

66666666,大神给跪

回到顶部