欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python使用Scrapy下載圖片的兩種方式

 更新時間:2025年08月22日 10:47:04   作者:一勺菠蘿丶  
Scrapy是一個適用爬取網(wǎng)站數(shù)據(jù)、提取結(jié)構(gòu)性數(shù)據(jù)的應用程序框架,它可以通過定制化的修改來滿足不同的爬蟲需求,本文給大家介紹了Python使用Scrapy下載圖片的兩種方式,需要的朋友可以參考下

在本篇博客中,我們將探討如何使用 Scrapy 框架下載圖片,并詳細解釋兩種下載圖片的方式。

一、項目結(jié)構(gòu)

首先,我們假設項目結(jié)構(gòu)如下:

biantu_down_pic/
├── biantu_down_pic/
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders/
│       ├── __init__.py
│       └── down_pic.py
├── log_file.log
└── scrapy.cfg

二、settings.py 配置

settings.py 中,我們需要進行一些基本配置:

# Scrapy settings for biantu_down_pic project

BOT_NAME = 'biantu_down_pic'

SPIDER_MODULES = ['biantu_down_pic.spiders']
NEWSPIDER_MODULE = 'biantu_down_pic.spiders'

ROBOTSTXT_OBEY = False
LOG_LEVEL = 'WARNING'
LOG_FILE = './log_file.log'

USER_AGENTS_LIST = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.111 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0',
    # 更多 User Agent 可添加
]

DOWNLOADER_MIDDLEWARES = {
    'biantu_down_pic.middlewares.BiantuDownPicDownloaderMiddleware': 543,
}

ITEM_PIPELINES = {
    'biantu_down_pic.pipelines.BiantuDownPicSavePipeline': 300,  # 先下載圖片再保存到數(shù)據(jù)庫
    'biantu_down_pic.pipelines.BiantuDownPicPipeline': 301,
    'biantu_down_pic.pipelines.MysqlPipeline': 302,
}

# 圖片地址配置
IMAGES_STORE = 'D:/ruoyi/pic.baidu.com/uploadPath'

# MySQL 配置
MYSQL_HOST = "localhost"
MYSQL_USER = "drawing-bed"
MYSQL_PASSWORD = "HBt5J7itWJEXe"
MYSQL_DBNAME = "drawing-bed"
MYSQL_PORT = 3306

三、爬蟲文件(down_pic.py)

down_pic.py 文件中,我們定義了爬蟲類 DownPicSpider,用于從網(wǎng)頁 https://pic.baidu.com/ 下載圖片。

代碼示例

import imghdr
import json
import os
import re
from datetime import datetime

import scrapy

from biantu_down_pic.items import BiantuDownPicItem
from biantu_down_pic.settings import IMAGES_STORE
from biantu_down_pic.pipelines import sanitize_filename


class DownPicSpider(scrapy.Spider):
    name = 'down_pic'
    start_urls = ['https://pic.baidu.com/']

    def __init__(self, token=None, map_json=None, *args, **kwargs):
        super(DownPicSpider, self).__init__(*args, **kwargs)
        self.token = token
        self.map_json = json.loads(map_json) if map_json else {}

    def parse(self, response, **kwargs):
        # 從 map_json 獲取必要的信息
        key_id = self.map_json.get('id')
        url = self.map_json.get('url')
        title = self.map_json.get("title")
        # 設置 cookies
        cookies = {i.split('=')[0]: i.split('=')[1] for i in self.token.split('; ')}
        # 發(fā)起請求到詳情頁
        yield scrapy.Request(
            url,
            cookies=cookies,
            callback=self.parse_detail,
            meta={'key_id': key_id, 'url': url, 'cookies': cookies, 'title': title}
        )

    def parse_detail(self, response, **kwargs):
        # 從 URL 中提取圖片 ID
        pic_id = response.url.split('/')[-1].split('.')[0]
        cookies = response.meta['cookies']
        # 構(gòu)建請求源圖片 URL 的地址
        source_url = f'https://pic.baidu.com/e/extend/downpic.php?id={pic_id}'
        # 獲取縮略圖 URL
        thumbnail_url = response.xpath('//*[@id="img"]/img/@src').extract_first()
        thumbnail_url = response.urljoin(thumbnail_url)
        # 將縮略圖 URL 添加到 meta 中
        response.meta['thumbnail_url'] = thumbnail_url
        # 發(fā)送請求獲取源圖片 URL
        yield scrapy.Request(
            source_url,
            cookies=cookies,
            callback=self.parse_source_url,
            meta=response.meta
        )

    def parse_source_url(self, response, **kwargs):
        # 解析響應中的圖片下載鏈接
        pic_data = response.json()
        pic_url = response.urljoin(pic_data['pic'])
        cookies = response.meta['cookies']
        # 發(fā)送請求下載圖片
        yield scrapy.Request(
            pic_url,
            cookies=cookies,
            callback=self.save_image,
            meta=response.meta
        )

    def save_image(self, response, **kwargs):
        # 動態(tài)生成文件保存路徑
        current_time = datetime.now()
        date_path = current_time.strftime('%Y/%m/%d')
        download_dir = os.path.join(IMAGES_STORE, 'pic', date_path).replace('\\', '/')
        # 生成清理后的文件名
        title = response.meta['title']
        pic_name = sanitize_filename(title)
        pic_name = self.clean_filename(pic_name)
        # 根據(jù)響應頭獲取文件擴展名
        content_type = response.headers.get('Content-Type', b'').decode('utf-8')
        extension = self.get_extension(content_type, response.body)
        if not pic_name.lower().endswith(extension):
            pic_name += extension
        file_path = os.path.join(download_dir, pic_name).replace('\\', '/')
        # 確保下載目錄存在
        os.makedirs(download_dir, exist_ok=True)
        # 保存圖片
        with open(file_path, 'wb') as f:
            f.write(response.body)
        # 構(gòu)建 Item 并返回
        item = BiantuDownPicItem()
        item['id'] = response.meta['key_id']
        item['title'] = response.meta['title']
        item['title_min'] = response.meta['title'] + '_min.jpg'
        item['url'] = response.meta['url']
        item['min_url'] = response.meta['thumbnail_url']
        item['download_path'] = download_dir.replace(IMAGES_STORE, '')
        item['max_path'] = file_path.replace(IMAGES_STORE, '/profile')
        yield item

    @staticmethod
    def clean_filename(filename):
        """清理文件名,去除無效字符"""
        return re.sub(r'[<>:"/\\|?*]', '', filename)

    @staticmethod
    def get_extension(content_type, body):
        """根據(jù)內(nèi)容類型或文件內(nèi)容獲取擴展名"""
        if 'image/jpeg' in content_type:
            return '.jpg'
        elif 'image/png' in content_type:
            return '.png'
        elif 'image/jpg' in content_type:
            return '.jpg'
        else:
            return '.' + imghdr.what(None, body)

四、管道文件(pipelines.py)

pipelines.py 文件中,我們定義了兩個管道類,用于處理和保存下載的圖片。

代碼示例

import logging
import re
import scrapy
from scrapy.pipelines.images import ImagesPipeline

log = logging.getLogger(__name__)


class BiantuDownPicPipeline:
    """基礎的 Item 處理管道,僅打印 Item"""

    def process_item(self, item, spider):
        print(item)
        return item


def sanitize_filename(filename):
    """移除文件名中的非法字符,替換為 'X'"""
    return re.sub(r'[<>:"/\\|?*]', 'X', filename)


class BiantuDownPicSavePipeline(ImagesPipeline):
    """自定義圖片下載和保存管道"""

    def get_media_requests(self, item, info):
        """發(fā)送請求去下載縮略圖"""
        min_url = item['min_url']
        print('1. 發(fā)送請求去下載圖片, min_url:', min_url)
        return scrapy.Request(url=min_url)

    def file_path(self, request, response=None, info=None, *, item=None):
        """定義圖片的存儲路徑"""
        print('2. 圖片的存儲路徑')
        filename = sanitize_filename(item['title_min'])
        download_path = f"{item['download_path']}/{filename}"
        return download_path

    def item_completed(self, results, item, info):
        """更新 Item,添加縮略圖的存儲路徑"""
        print(f'3. 對 Item 進行更新, result: {results}')
        if results:
            ok, res = results[0]
            if ok:
                item['min_path'] = '/profile' + res["path"]
        return item


class MysqlPipeline(object):
    """MySQL 數(shù)據(jù)庫管道,暫時保留現(xiàn)狀"""



    def __init__(self, host, user, password, database, port):
        self.host = host
        self.user = user
        self.password = password
        self.database = database
        self.port = port

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            host=crawler.settings.get("MYSQL_HOST"),
            user=crawler.settings['MYSQL_USER'],
            password=crawler.settings['MYSQL_PASSWORD'],
            database=crawler.settings['MYSQL_DBNAME'],
            port=crawler.settings['MYSQL_PORT']
        )

    def open_spider(self, spider):
        """在爬蟲啟動時創(chuàng)建數(shù)據(jù)庫連接"""
        self.conn = pymysql.connect(
            host=self.host,
            user=self.user,
            password=self.password,
            database=self.database,
            charset='utf8',
            port=self.port
        )
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        """處理 Item 并插入數(shù)據(jù)庫"""
        dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        # SQL 語句暫時保留,待更新
        # insert_sql = """
        #     INSERT INTO biz_pic (
        #         url, title, source_url, category_name, size, volume, create_by, create_time
        #     ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
        # """
        # try:
        #     self.cursor.execute(insert_sql, (
        #         item['url'],
        #         item['title'],
        #         item['source_url'],
        #         item['category_name'],
        #         item['size'],
        #         item['volume'],
        #         'admin',
        #         dt
        #     ))
        #     self.conn.commit()
        # except Exception as e:
        #     log.error(f"插入數(shù)據(jù)出錯,{e}")

    def close_spider(self, spider):
        """在爬蟲關閉時關閉數(shù)據(jù)庫連接"""
        self.cursor.close()
        self.conn.close()
        log.warning("爬取數(shù)據(jù)結(jié)束===============================>end")

五、兩種下載方式的區(qū)別和使用場景

在這篇文章中,我們介紹了使用 Scrapy 下載圖片的兩種不同方式:直接鏈接下載和通過下載鏈接下載。接下來,我們將詳細介紹這兩種方式的區(qū)別以及它們適用的場景。

1. 直接鏈接下載

直接鏈接下載是指圖片的 URL 本身就指向圖片文件,可以直接通過 URL 獲取圖片內(nèi)容。

示例代碼

pipelines.py 中的 BiantuDownPicSavePipeline 類中,我們使用直接鏈接下載圖片:

class BiantuDownPicSavePipeline(ImagesPipeline):
    """自定義圖片下載和保存管道"""

    def get_media_requests(self, item, info):
        """發(fā)送請求去下載縮略圖"""
        min_url = item['min_url']
        print('1. 發(fā)送請求去下載圖片, min_url:', min_url)
        return scrapy.Request(url=min_url)

    def file_path(self, request, response=None, info=None, *, item=None):
        """定義圖片的存儲路徑"""
        print('2. 圖片的存儲路徑')
        filename = sanitize_filename(item['title_min'])
        download_path = f"{item['download_path']}/{filename}"
        return download_path

    def item_completed(self, results, item, info):
        """更新 Item,添加縮略圖的存儲路徑"""
        print(f'3. 對 Item 進行更新, result: {results}')
        if results:
            ok, res = results[0]
            if ok:
                item['min_path'] = '/profile' + res["path"]
        return item

使用場景

  • 簡單且常見:適用于絕大多數(shù)公開訪問的圖片文件。
  • 性能較好:直接通過 URL 獲取圖片,無需額外的請求和處理。

2. 通過下載鏈接下載

通過下載鏈接下載是指圖片的 URL 需要通過一個中間鏈接來獲取實際的圖片文件。這種情況通常用于需要驗證或有時效性的下載鏈接。

示例代碼

down_pic.py 中的 DownPicSpider 類中,我們使用通過下載鏈接下載圖片:

class DownPicSpider(scrapy.Spider):
    name = 'down_pic'
    start_urls = ['https://pic.baidu.com/']

    def parse_detail(self, response, **kwargs):
        # 從 URL 中提取圖片 ID
        pic_id = response.url.split('/')[-1].split('.')[0]
        cookies = response.meta['cookies']
        # 構(gòu)建請求源圖片 URL 的地址
        source_url = f'https://pic.baidu.com/e/extend/downpic.php?id={pic_id}'
        # 獲取縮略圖 URL
        thumbnail_url = response.xpath('//*[@id="img"]/img/@src').extract_first()
        thumbnail_url = response.urljoin(thumbnail_url)
        # 將縮略圖 URL 添加到 meta 中
        response.meta['thumbnail_url'] = thumbnail_url
        # 發(fā)送請求獲取源圖片 URL
        yield scrapy.Request(
            source_url,
            cookies=cookies,
            callback=self.parse_source_url,
            meta=response.meta
        )

    def parse_source_url(self, response, **kwargs):
        # 解析響應中的圖片下載鏈接
        pic_data = response.json()
        pic_url = response.urljoin(pic_data['pic'])
        cookies = response.meta['cookies']
        # 發(fā)送請求下載圖片
        yield scrapy.Request(
            pic_url,
            cookies=cookies,
            callback=self.save_image,
            meta=response.meta
        )

使用場景

  • 需要身份驗證或時效性的下載鏈接:適用于需要通過特定請求獲取下載鏈接的情況。
  • 安全性要求較高:適用于下載需要權(quán)限控制的圖片。

總結(jié)

  • 直接鏈接下載:適用于絕大多數(shù)公開訪問的圖片文件,操作簡單且性能較好。
  • 通過下載鏈接下載:適用于需要通過驗證或時效性鏈接獲取圖片的情況,安全性更高但操作稍復雜。

到此這篇關于Python使用Scrapy下載圖片的兩種方式的文章就介紹到這了,更多相關Python Scrapy下載圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • urllib和BeautifulSoup爬取維基百科的詞條簡單實例

    urllib和BeautifulSoup爬取維基百科的詞條簡單實例

    這篇文章主要介紹了urllib和BeautifulSoup爬取維基百科的詞條簡單實例,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • 在Linux命令行中運行Python腳本的流程步驟

    在Linux命令行中運行Python腳本的流程步驟

    Python是一種高級編程語言,被廣泛應用于數(shù)據(jù)科學、機器學習、Web 開發(fā)等領域,在Linux操作系統(tǒng)中,Python是一個默認安裝的解釋器,用戶可以通過命令行界面(CLI)來運行Python腳本,在本文中,我們將詳細介紹如何在Linux命令行中運行Python腳本,需要的朋友可以參考下
    2023-11-11
  • 深入了解Python?Flask框架之藍圖

    深入了解Python?Flask框架之藍圖

    這篇文章主要為大家介紹了Python?Flask框架之藍圖,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • Python PySpider爬蟲框架安裝使用教程

    Python PySpider爬蟲框架安裝使用教程

    PySpider是一個Python編寫的分布式網(wǎng)絡爬蟲框架,它可以幫助開發(fā)者快速構(gòu)建和部署爬蟲,并支持爬蟲任務的分布式運行,PySpider基于Twisted網(wǎng)絡框架和MongoDB數(shù)據(jù)庫,具有高效、穩(wěn)定、易用等特點,同時還提供了一套Web界面,可以方便地查看爬蟲任務的運行狀態(tài)和結(jié)果
    2023-11-11
  • Python中os模塊的12種用法總結(jié)

    Python中os模塊的12種用法總結(jié)

    OS?(?Operating?System?操作系統(tǒng)?)?操作系統(tǒng)模塊;它是屬于python的標準庫,常用于處理文件和目錄(文件夾)的操作。本文為大家總結(jié)了這個模塊的12種用法,希望有所幫助
    2022-08-08
  • Python從列表中隨機選擇元素的多種實現(xiàn)方法

    Python從列表中隨機選擇元素的多種實現(xiàn)方法

    在Python編程中,經(jīng)常會遇到需要從列表中隨機選擇元素的場景,比如游戲開發(fā)中隨機選擇道具、數(shù)據(jù)處理時隨機抽取樣本等,Python提供了多種方法來實現(xiàn)這一功能,不同方法適用于不同的需求,需要的朋友可以參考下
    2025-07-07
  • Python使用vllm處理多模態(tài)數(shù)據(jù)的預處理技巧

    Python使用vllm處理多模態(tài)數(shù)據(jù)的預處理技巧

    本文深入探討了在Python環(huán)境下使用vLLM處理多模態(tài)數(shù)據(jù)的預處理技巧,我們將從基礎概念出發(fā),詳細講解文本、圖像、音頻等多模態(tài)數(shù)據(jù)的預處理方法,重點介紹如何利用vLLM框架高效處理這些數(shù)據(jù),需要的朋友可以參考下
    2025-07-07
  • 淺談Python實時檢測CPU和GPU的功耗

    淺談Python實時檢測CPU和GPU的功耗

    本文主要介紹了淺談Python實時檢測CPU和GPU的功耗,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Python 調(diào)用API發(fā)送郵件

    Python 調(diào)用API發(fā)送郵件

    這篇文章主要介紹了Python 調(diào)用API發(fā)送郵件的方法,幫助大家更好的理解和學習使用python,感興趣的朋友可以了解下
    2021-03-03
  • Python如何用str.format()批量生成網(wǎng)址(豆瓣讀書為例)

    Python如何用str.format()批量生成網(wǎng)址(豆瓣讀書為例)

    這篇文章主要介紹了Python如何用str.format()批量生成網(wǎng)址(豆瓣讀書為例),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論