ValueError:mysql scrapy管道中不支持的格式字符

Posted

技术标签:

【中文标题】ValueError:mysql scrapy管道中不支持的格式字符【英文标题】:ValueError: unsupported format character in mysql scrapy pipline 【发布时间】:2018-10-12 04:31:32 【问题描述】:

我正在开发一个爬虫,这个问题真的很困扰我,因为我已经被这个问题困住了好几天了。

当我使用“?”时,这个占位符功能可以正常工作而不是 SQLite 数据库的“%s”。但是在使用“?”时随着数据库切换到mysql,它显示:

"TypeError: 在字符串格式化期间并非所有参数都被转换 "

即使我付出了很多努力来修改代码和更改占位符(应该是?)它仍然显示:

" query = query % self._escape_args(args, conn) ValueError: unsupported format character ',' "

更具体地说:

Traceback (most recent call last):

  File "/usr/lib64/python3.4/dist-packages/twisted/internet/defer.py", line 653, in _runCallbacks
    current.result = callback(current.result, *args, **kw)

File "/home/ec2-user/lulu_testing/get_download_file/hello_scrapy/hello/hello/pipelines.py", line 42, in process_item
    self.cur.execute(insert_query, insert_values)

File "/usr/lib/python3.4/dist-packages/pymysql/cursors.py", line 163, in execute
    query = self.mogrify(query, args)

File "/usr/lib/python3.4/dist-packages/pymysql/cursors.py", line 142, in mogrify
    query = query % self._escape_args(args, conn)

ValueError: unsupported format character ',' (0x2c) at index 94

mysql 版本的管道

import pymysql
import scrapy
from hello.items import HelloItem

class HelloPipeline(object):

def __init__(self):#

    self.conn = pymysql.connect(host="localhost", port=3306, user="root", passwd="lulu", db="test", charset="utf8", use_unicode=True)
    self.cur = self.conn.cursor()


    self.cur.execute("drop table IF EXISTS test;")
    self.conn.commit()

    self.cur.execute("create table if not EXISTS table_test_4(test0 text, test1 text, test2 text, test3 text,test4 text, test5 text, test6 text, test7 text, test8 text, test9 text);")
    self.conn.commit()

    #pass


def process_item(self, item, spider):#

    col = ",".join(item.keys())
    placeholders = ",".join(len(item) * "%s")

    insert_query = "INSERT INTO test_table_4(0) VALUES(1);".format(col,placeholders)

    insert_values = tuple(item.values())


    self.cur.execute(insert_query, insert_values)

    return item

def close_spider(self, spider):#
    self.cur.close()
    self.conn.close()
    #pass

SQLite 版本(我使用的是 b4)

import sqlite3
import scrapy
from hello.items import HelloItem

class HelloPipeline(object):

def open_spider(self, spider):#
    self.conn = sqlite3.connect("test_database_ver_2018_03_31.sqlite")
    self.cur = self.conn.cursor()
    self.cur.execute("create table if not exists test_table(test0 text, test1 text, test2 text, test3 text,test4 text, test5 text, test6 text, test7 text, test8 text, test9 text);")        
    #pass

def close_spider(self, spider):#
    self.conn.commit()
    self.conn.close()
    #pass

def process_item(self, item, spider):#

    col = ",".join(item.keys())       
    placeholders = ",".join(len(item) * "?")
    sql = "insert into test_table() values()"


    self.cur.execute(sql.format(col, placeholders), tuple(item.values()))


    return item

scrapy爬虫主程序的数据设置

    testitem = HelloItem()

    testitem["test0"] = house_detail.select(".houseInfoTitle")[0].text        
    testitem["test1"] = house_detail.select(".pageView")[0].text 
    testitem["test2"] = house_detail.select(".detailInfo")[0].text
    testitem["test3"] = house_detail.select(".houseIntro")[0].text
    testitem["test4"] = house_detail.select(".lifeBox")[0].text
    testitem["test5"] = house_detail.select(".labelList")[0].text
    testitem["test6"] = house_detail.select(".facility")[0].text
    testitem["test7"] = str(house_detail.select(".userInfo"))
    testitem["test8"] = str(house_detail.select(".banner"))
    testitem["test9"] = str(house_detail.select("#show"))

    return testitem

项目设置

import scrapy


class HelloItem(scrapy.Item):

test0 = scrapy.Field()
test1 = scrapy.Field()
test2 = scrapy.Field()
test3 = scrapy.Field()
test4 = scrapy.Field()
test5 = scrapy.Field()
test6 = scrapy.Field()
test7 = scrapy.Field()
test8 = scrapy.Field()
test9 = scrapy.Field()

【问题讨论】:

您使用的是 MS SQL Server 还是 MySQL? 我正在使用 mysqld Ver 5.5.59 for Linux on x86_64 (MySQL Community Server (GPL)) 【参考方案1】:

问题在于这一行:

placeholders = ",".join(len(item) * "%s")

没有达到你的预期。

>>> item = 'a': 1, 'b': 2, 'c': 3
>>> placeholders = ",".join(len(item) * "%s")
>>> print(placeholders)
%,s,%,s,%,s     

",".join(len(item) * "%s") 做了两件事 - 计算 len(item) * "%s",然后将结果与 ',' 连接。

len(item) * '%s' 的结果是字符串(或可迭代'%s%s%s'str.join(iterable) 返回一个由 iterable separated by the string that provides the method 的所有元素组成的字符串。所以调用的结果

','.join('%s%s%s')

'%,s,%,s,%,s',不是'%s,%s,%s'

你想做的事

>>> ",".join(len(item) * ["%s"])
'%s,%s,%s'

>>> ",".join('%s' for _ in item)
'%s,%s,%s'

这样str.join 就在'%s' 字符串的可迭代对象上运行,而不是像'%s%s%s' 这样的单个字符串。 `

【讨论】:

非常感谢你,我才发现,你的最终解决方案太酷了,你怎么知道循环将与 join 函数一起工作并创建一个奇妙的过程? join 方法通常传递一个要加入的字符串列表,所以如果你没有传递一个列表,那么你需要在方法中创建一个列表 - 比如 len(item) * ['%s'] -或生成要与生成器理解连接的项目流 - 例如'%s' for _ in item 我从来不知道这种(_ for _ in _)这种申请会奏效,这其中的逻辑是什么?我发现for循环也可以使用列表实体的数量,例如 ",".join('%s' for _ in item) as",".join('%s' for _ in ( x,x,x)) 这是一种传统的方式来表明您没有真正使用循环计数器变量 - 请参阅***.com/q/5893163/5320906

以上是关于ValueError:mysql scrapy管道中不支持的格式字符的主要内容,如果未能解决你的问题,请参考以下文章

Scrapy mysql管道错误

爬虫--Scrapy-持久化存储操作2

ValueError: Invalid \escape: 当在 Scrapy 中读取 json 作为响应时

#yyds干货盘点# python scrapy 管道学习,并拿在行练手爬虫项目

python scrapy 管道学习,并拿在行练手爬虫项目

python scrapy 管道学习,并拿在行练手爬虫项目