我在 SO 上发现了类似的问题,但我无法将其拼凑起来使其发挥作用。
我正在从一个网站上抓取数据,其中也有图像。我的
items.py
看起来像这样:
import scrapy
class BookPipeline(scrapy.Item):
title = scrapy.Field()
author = scrapy.Field()
...
image_urls = scrapy.Field()
images = scrapy.Field()
在
my_spider.py
中如下:
class MySpider(scrapy.Spider):
...
custom_settings = {
'ITEM_PIPELINES': {
'project.pipelines.BookPipeline': 400,
'project.pipelines.CustomImageNamePipeline': 1
},
'IMAGES_STORE': 'book_images'
}
...
当我运行蜘蛛时,它会将图像保存到
book_images
文件夹中,这很好。
不过,我想要实现的是将图像保存到
book_images/ID-OF-JUST-SAVED-BOOK-IN-DATABASE
,因此文件将保存在这种结构中:
book_images/323/some-hash-name.jpg
book_images/323/another-hash-name.jpg
book_images/323/different-hash-name.jpg
book_images/5211/hash-name.jpg
我在自定义管道中看到了一些代码片段,但不幸的是我无法使其工作。
另外,我还不知道 - 是先用Scrapy下载图片,然后在数据库中创建记录,还是反过来?
编辑:我尝试过这样的事情:
pipeline.py
import scrapy
from scrapy.pipelines.images import ImagesPipeline
import os
class BookPipeline:
...
class CustomImageNamePipeline(ImagesPipeline):
def get_media_requests(self, item, info):
return [scrapy.Request(x, meta={'image_dir': item["uni_id"]})
for x in item.get('image_urls', [])]
def file_path(self, request, response=None, info=None, *, item=None):
url = request.url
media_guid = hashlib.sha1(to_bytes(url)).hexdigest()
media_ext = os.path.splitext(url)[1]
return f'{request.meta["image_dir"]}/%s%s' % (media_guid, media_ext)
但是没有保存文件,也没有错误消息。此外,控制台中没有提及任何下载的文件。
为此,您需要创建两个管道;一个用于将数据保存到数据库并获取插入记录的 ID,另一个是图像管道。执行顺序取决于
ITEM_PIPELINES
定义中的优先级设置。在这种情况下,您需要数据库管道的数量小于图像管道的数量,即
ITEM_PIPELINES = {
"project.pipelines.SQLiteDBPipeline": 300,
"project.pipelines.CustomImageNamePipeline": 400,
}
在数据库管道的
process_item
方法中将项目保存到数据库并将返回的 id 添加到项目定义中。使用 sqlite 的示例如下:
import sqlite3
class SQLiteDBPipeline:
def __init__(self) -> None:
self.conn = sqlite3.connect("sqlite.db")
def process_item(self, item, spider):
cur = self.conn.cursor()
# your code to insert into database goes here
cur.execute("SQL QUERY HERE")
id = cur.lastrowid
item["id"] = id
cur.close()
return item
在图像管道中,使用 id 值创建所需的文件路径,例如
import hashlib
from scrapy.pipelines.images import ImagesPipeline
class CustomImageNamePipeline(ImagesPipeline):
def file_path(self, request, response=None, info=None, *, item=None):
# create a hash using the image url
image_url_hash = hashlib.shake_256(request.url.encode()).hexdigest(16)
return f"{item['id']}/{image_url_hash}.jpg"
注意:将
id
作为项目定义中的字段包含在内,以便上述代码正常工作。
import scrapy
class BookItem(scrapy.Item):
id = scrapy.Field()
title = scrapy.Field()
author = scrapy.Field()
...
image_urls = scrapy.Field()
images = scrapy.Field()