尝试使用django存储爬取的文件

本文介绍了如何使用Django的ORM Model管理和保存从网络下载的文件资源,包括图片、音频等,通过两种方法:一是先保存到本地再关联;二是直接使用ContentFile处理二进制数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从网上直接爬取资源后,如果资源是文件,比如图片、音频等,返回的数据是二进制数组,如果我们要保存,一般都是直接新开一个和资源类型相同的文件,并将得到的二进制数据直接写进文件。

如果我们需要让django的ORM Model 来管理我们下载的资源,那么model中需要有FileField这个字段,并且我们需要将要保存的文件和这个字段关联起来。

def _upload_to(instance, filename):
    pass

class NetSourceFile(models.Model):
    name = models.CharField(max_length=180)
    original_url = models.CharField(max_length=200)
    local_url = models.FileField(upload_to=_upload_to, max_length=200)

    def __str__(self):
        return "{}".format(self.name)

如上所示,下载的资源我们需要和local_url这个字段关联起来,在网上找了一大堆资料后,目前找到两种方式进行关联:

一种是先将文件保存到本地,在用打开本地文件的方式来进行关联关联,这种方式易懂,也简单粗暴。

import requests


url = 'http://xxxx.png'
source = requests.get(url)
if not source.status_code == 200 or not source.content:
    return

with open('temp.png', 'wb') as f:
    f.write(source.content)

reoppen = open('your_temp_path/xxx.png', 'rb')
django_file = File(reopen)
instance = NetSourceFile(
    name=file_name,
    original_url=url,
    local_url=django_file,
)
instance.save()

        
        

另一种是使用ContentFile,不用存临时文件,直接将二进制数组作为参数放在ContentFile里面

import requests
from django.core.files.base import ContentFile


url = 'http://xxxx.png'
source = requests.get(url)
if not source.status_code == 200 or not source.content:
    return

file_name ='xxx.png'
upload_file = ContentFile(source.content, name=file_name)
instance = NetSourceFile(
    name=file_name,
    original_url=url,
    local_url=upload_file,
)
instance.save()

        
        
以上是目前找到的两种保存方式,如果还有其它方式的,欢迎分享。

参考资源: https://docs.djangoproject.com/en/2.1/ref/files/file/#the-file-class

<think>嗯,用户现在想了解爬虫数据导入数据库的常见错误和解决方案。我之前在系统指令中提到过Scrapy存储问题和MySQL乱码的引用,正好可以结合起来。用户可能正在开发一个爬虫项目,遇到了数据入库的困难。从ta提问的方式看,ta应该有一定技术基础,但可能刚接触数据库交互环节。深层需求可能是想系统性地预防问题,而不仅仅是解决当前遇到的某个具体错误。需要分几个层面来组织回答:首先是编码问题,这是最常见的乱码根源;其次是数据类型不匹配,特别是文本超长和数值格式;然后是重复数据处理,涉及业务逻辑;最后是性能瓶颈和连接问题。每个点都要给出可操作的解决方案。特别注意要强调预防措施,比如在爬虫管道里添加实时验证,因为等数据入库后再发现问题就晚了。幂等性处理那块可以引用之前提到的乐观锁方案,但要用爬虫场景的例子说明。对了,还要提醒用户注意SQL注入风险。很多爬虫开发者会直接拼接SQL语句,特别是新手。给出参数化查询的代码示例很重要。引用材料里的MySQL乱码解决方案很实用,但需要补充现代编码标准(比如全面转向UTF-8mb4)。scrapy的itemexporter方案也比直接写SQL更可靠,值得重点推荐。</think> 好的,基于您想要了解“爬虫数据导入数据库时常见错误及其解决方法”,并结合爬虫开发的实际痛点,以下是总结的常见错误类型及其针对性解决方案: **爬虫数据导入数据库常见错误及解决方案** 1. **编码乱码问题** * **错误描述:** 数据库中出现中文字符或其他非ASCII字符显示为乱码(如 `???`、 `我们` 等)。这是最常见的问题之一。 * **主要原因:** * **爬取源编码不一致:** 目标网页使用的编码(如 GBK, GB2312, Big5, UTF-8 等)与数据库配置的编码不一致。 * **连接字符集设置错误:** 数据库连接时(或在ORM框架配置中)未正确设置客户端字符集为 UTF-8。 * **数据库/表/字段字符集设置错误:** 数据库本身、目标表或目标字段设置的字符集(如 `latin1`)不支持存储中文或未正确设置为 `utf8` 或 `utf8mb4`。 * **解决方案:** * **统一源头编码:** 在爬虫解析阶段,务必准确定位网页编码(Scrapy 的 `response.encoding` 或 `response.text` 自动检测通常较好),并将所有文本数据**尽早统一转换为 UTF-8 编码**存储在程序中。 * **配置数据库连接字符集:** * **直连数据库:** 在创建数据库连接字符串时显式指定字符集(如 MySQL: `charset='utf8mb4'`)。 * **使用ORM/框架:** 在框架配置文件中设置数据库连接的 `charset` / `encoding` 选项为 `utf8mb4`。 * **检查数据库字符集:** * 确保数据库、目标表、目标字段的字符集都设置为 `utf8mb4`(强烈推荐 `utf8mb4` 而非 `utf8`,以完整支持所有Unicode字符,包括表情符号)。 * MySQL示例检查和修改(修改需谨慎,可能需备份重建表): ```sql SHOW CREATE DATABASE `your_database`; -- 查看数据库 SHOW CREATE TABLE `your_table`; -- 查看表 ALTER DATABASE `your_database` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; -- 修改数据库 ALTER TABLE `your_table` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 转换表及所有字段 ``` * **处理特殊字符:** 对于网页中可能存在的非法字符或不可解码字符,在清洗阶段进行过滤或替换(使用 `replace` 或正则表达式)[^3]。 2. **数据类型不匹配** * **错误描述:** 数据无法插入数据库,报告类似 `Data too long for column 'xxx'`、 `Incorrect integer value`、`Invalid datetime format` 等错误。 * **主要原因:** * **字符串超长:** 爬取的文本长度超过了数据库中定义字段的长度(`VARCHAR(N)` 或 `TEXT`)。 * **格式错误:** 爬取的“数字”字符串包含非数字字符(如货币符号 `¥100`)、时间日期字符串格式与数据库要求不符、布尔值表示方式不一致等。 * **空值/NULL处理:** 数据库字段定义为 `NOT NULL`,但爬取的数据中缺少该字段的值。 * **解决方案:** * **严格数据清洗与验证:** * 在入库前进行**数据清洗**:移除数字中的非数字字符、统一时间格式、将布尔值(`是`/`否`)转换为`True`/`False`或`1`/`0`等。 * 进行**数据验证**:检查字符串长度并截断(或使用更大的字段类型如 `TEXT` / `LONGTEXT`)、检查数值能否转换、检查时间能否解析、检查必填项是否为空。 * **合理设计数据库表结构:** * 根据爬取数据的预期范围,选择足够大的字段类型(如对于描述性文本,优先考虑 `TEXT` 类型而非 `VARCHAR(255)`)。 * 谨慎使用 `NOT NULL` 约束,确保数据源可能缺失的字段允许为 `NULL`。 * 日期时间字段使用标准的 `DATE` / `DATETIME` / `TIMESTAMP` 类型,字符串字段使用 `CHAR` / `VARCHAR` / `TEXT` 类型等。 * **利用ORM或库进行自动转换:** 如果使用 ORM (如 SQLAlchemy, Django ORM),可以利用其字段类型系统自动处理大部分Python对象到数据库类型的转换,减少手动工作量。 3. **数据重复插入** * **错误描述:** 重复运行爬虫或重试失败请求时,导致相同的数据记录被多次插入数据库。 * **主要原因:** 缺乏检测唯一记录并进行**幂等操作**的机制。 * **解决方案:** * **在数据库中定义唯一约束/索引:** 为能唯一标识一条记录的一个或多个字段创建 `UNIQUE CONSTRAINT` 或 `UNIQUE INDEX`。这是最可靠、最推荐的方式。当尝试插入重复数据时,数据库会抛出唯一键冲突异常 (`IntegrityError`)。 * **实现“插入或更新”逻辑:** * **`UPSERT` / `ON DUPLICATE KEY UPDATE` (MySQL):** 使用数据库提供的语法,在插入时如果唯一键冲突,则更新其他字段。 * **`INSERT ... ON CONFLICT ... DO UPDATE` (PostgreSQL):** PostgreSQL 的 `UPSERT` 语法。 * **ORM的 `merge()` 或等效方法:** ORM 框架通常提供 `session.merge()` (SQLAlchemy) 或 `update_or_create()` (Django) 等方法实现此功能。 * **程序逻辑判重:** * **在爬虫内存中维护已爬取URL集合:** 对于基于 URL 唯一性的爬取,可以在 Scrapy 中利用内置的重复过滤器或自定义 `DupeFilter`。 * **利用缓存/布隆过滤器:** 对于大规模数据,可使用 Redis 等缓存存储部分键值或布隆过滤器来判断是否处理过某条记录(存在误判率)。 * **利用乐观锁进行版本控制:** 对于需要防止覆盖最新更新的场景,可以在表中添加版本号字段,更新时判断版本号是否一致,避免并发覆盖[^4]。 4. **批量插入性能问题与连接异常** * **错误描述:** 导入大量数据时速度非常慢;导入过程中偶现数据库连接超时 (`OperationalError`) 或断开 (`InterfaceError`);数据库服务器负载激增。 * **主要原因:** * **逐条插入:** 使用大量单独的 `INSERT` 语句性能极低。 * **事务范围过大或过小:** 每条插入都单独提交事务开销大;但一次性提交几十万条事务,又可能导致超大事务引起锁表或日志膨胀。 * **数据库连接未复用:** 频繁打开和关闭数据库连接(如每条记录连接一次)开销巨大。 * **网络问题:** 爬虫主机与数据库主机之间的网络不稳定。 * **数据库配置限制:** `max_allowed_packet`(MySQL)设置过小,导致大数据量插入失败。 * **解决方案:** * **使用批量插入:** * 构造 `INSERT INTO table VALUES (...), (...), (...) ...` 语句,一次性插入多条(如每次 100-1000 条,需根据数据大小和网络测试调整)。 * 使用 ORM 框架提供的 `bulk_save_objects()` (SQLAlchemy) 或 `bulk_create()` (Django) 方法。 * 使用数据库特定的高效导入工具(如 MySQL 的 `LOAD DATA INFILE`, PostgreSQL 的 `COPY` 命令)。 * **合理控制事务:** * **显式事务提交:** 不要每条插入都自动提交(`autocommit=1`)。将一批记录(如 100-1000 条)放入一个事务中统一提交 (`COMMIT`)。既减少提交次数,也避免超大事务。在 Scrapy 中,可以在 Item Pipeline 的 `process_item` 里收集Item,在 `close_spider` 或按批次调用 `flush()` 时批量插入并提交。 * **使用连接池:** 通过数据库驱动自带的连接池或 ORM 框架管理的连接池,复用数据库连接,避免频繁开关连接。配置合理的连接池大小。 * **优化数据库配置:** * 适当调大 `max_allowed_packet`(MySQL)。 * 确保数据库表有合适的索引(避免全表扫描判断唯一性),但同时注意过多索引会降低写入速度。索引应在建立唯一约束后自然存在,无需特意为插入优化添加额外索引。 * **处理超时与重试:** 在代码中加入健壮的错误处理机制,捕获连接超时/断开错误,并进行指数退避重试。 5. **SQL注入风险** * **错误描述:** 如果处理不当,爬取的恶意构造数据可能通过拼接SQL语句的方式注入恶意代码,导致数据泄露、篡改或删除。 * **主要原因:** 使用原始字符串拼接的方式构造SQL语句。 * **解决方案:** * **永远不要使用字符串拼接SQL!** * **使用参数化查询 (`?` / `%s` 占位符):** 将SQL语句与数据分离,数据库驱动库会自动进行转义处理。 ```python # Python (示例使用 sqlite3) cursor.execute("INSERT INTO table (title, url) VALUES (?, ?)", (item['title'], item['url'])) ``` * **使用ORM框架:** ORM 框架天然支持参数化查询,消除手动拼接的风险。 **最佳实践总结** 1. **尽早统一编码:** 获取响应后立即处理编码问题,程序内部统一使用UTF-8。 2. **严格清洗验证:** 入库前的数据清洗和验证是保证数据质量和避免导入错误的关键环节。 3. **定义数据库约束:** 合理定义字段类型、长度、唯一约束、外键约束,让数据库成为数据质量的最后一道防线。 4. **幂等性设计:** 使用唯一索引/约束是实现幂等导入的基础,配合 `UPSERT` 或“插入前检查”机制。 5. **性能优化:** 采用批量插入、合理管理事务、使用连接池。 6. **使用ORM/高效工具:** 利用 ORM 简化操作,提高开发效率和安全性;在数据量极大时考虑数据库专有导入命令。 7. **参数化查询:** 坚决杜绝拼接SQL,防御SQL注入。 8. **完善的日志记录与错误处理:** 详细记录导入过程、成功和失败的记录及其原因(包括捕获的数据库异常),便于定位问题。实现错误重试机制。 遵循这些原则,能有效解决绝大多数爬虫数据导入数据库过程中的常见问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值