from scrapy import Request
from scrapy.spiders import Spider
from ..items import BookItem
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
import logging
import os

class bookSpider(Spider):
    name = 'books'

    def start_requests(self):
        url = 'https://www.qidian.com/finish/'
        yield Request(url)

    def parse(self, response):
        li_selector = response.css('ul.all-img-list.cf > li')
        for selector in li_selector:
            item = BookItem()
            item['name'] = selector.css('div h2 a::text').get()
            item['price'] = selector.css('div p.intro::text').get().strip()
            img_url = selector.css('div .book-img-box img::attr(src)').get()
            if img_url:
                img_url = response.urljoin(img_url)  # 将图片url相对路径转化为绝对路径
                item['image_urls'] = [img_url]
            yield item

        next_url = response.css('.lbf-pagination-next::attr(href)').get()  # 获取下一页URL
        if next_url:
            yield response.follow(next_url, self.parse)  # 直接跟随URL请求下一页并解析

class BookPipeline:
    def process_item(self, item, spider):
        with open('书籍信息.txt', 'a', encoding='utf-8') as f:
            if not f.tell():
                f.write('书籍名,信息' + '\n')
            str1 = item['name'] + ',' + item['price'] + '\n'
            f.write(str1)
        return item

class SaveImagePipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        for image_url in item.get('image_urls', []):
            yield Request(image_url, meta={'item': item})

    def item_completed(self, results, item, info):
        item = super().item_completed(results, item, info)
        if 'image_urls' in item:
            if not results[0][0]:
                raise DropItem('图片未下载')
        return item

    def file_path(self, request, response=None, info=None):
        # 返回图片名称
        return os.path.basename(request.url)

    def thumb_path(self, request, thumb_id, response=None, info=None):
        # 返回缩略图名称
        return f'thumbs/{thumb_id}/{self.file_path(request)}'

logger = logging.getLogger('SavelmagePipeline')

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

IMAGES_STORE = 'D:/pyth项目/book/img'
IMAGES_THUMBS = {
    'small': (10, 10),
    'big': (50, 50)
}
IMAGES_MIN_WIDTH = 5
IMAGES_MIN_HEIGHT = 5

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'book.pipelines.BookPipeline': 300,
    'book.pipelines.SaveImagePipeline': 400
}

cmdline.execute('scrapy crawl books'.split())

修改后的代码的关键点:

  1. 修改 Item 字段:BookItem 类中,将 img_url 字段改为 image_urls 字段,并将其设置为列表类型。
  2. 处理图片 URL:parse 函数中,将获取到的图片 URL 加入到 item['image_urls'] 列表中。
  3. 使用 ImagesPipeline: 使用 ImagesPipeline 来下载图片,并设置 get_media_requests 方法,用于生成图片下载请求。
  4. 处理图片下载结果: 使用 item_completed 方法处理图片下载结果,如果图片未下载成功,则抛出 DropItem 异常。
  5. 设置图片存储路径:settings.py 文件中设置 IMAGES_STORE 来指定图片存储路径。

修改后的代码解决了以下问题:

  1. 使用 ImagesPipeline 下载图片,而不是直接使用 requests 库下载图片。
  2. 使用 image_urls 字段存储多个图片 URL,而不是单个 URL。
  3. item_completed 方法中检查图片下载结果,并处理下载失败的情况。

运行修改后的代码:

  1. 确保 D:/pyth项目/book/img 目录存在。
  2. 运行 scrapy crawl books 命令。

执行上述步骤后,代码将能够成功下载小说封面图片,并将其保存在指定的目录中。

使用 Scrapy 爬取起点中文网完结小说并下载图片

原文地址: https://www.cveoy.top/t/topic/n3Tm 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录