在Scrapy中向MySQL数据库写入数据项

21

我是Scrapy的新手,我有一个爬虫代码

class Example_spider(BaseSpider):
   name = "example"
   allowed_domains = ["www.example.com"]

   def start_requests(self):
       yield self.make_requests_from_url("http://www.example.com/bookstore/new")

   def parse(self, response):
       hxs = HtmlXPathSelector(response)
       urls = hxs.select('//div[@class="bookListingBookTitle"]/a/@href').extract()
       for i in urls:
           yield Request(urljoin("http://www.example.com/", i[1:]), callback=self.parse_url)

   def parse_url(self, response):
           hxs = HtmlXPathSelector(response)
           main =   hxs.select('//div[@id="bookshelf-bg"]')
           items = []
           for i in main:
           item = Exampleitem()
           item['book_name'] = i.select('div[@class="slickwrap full"]/div[@id="bookstore_detail"]/div[@class="book_listing clearfix"]/div[@class="bookstore_right"]/div[@class="title_and_byline"]/p[@class="book_title"]/text()')[0].extract()
           item['price'] = i.select('div[@id="book-sidebar-modules"]/div[@class="add_to_cart_wrapper slickshadow"]/div[@class="panes"]/div[@class="pane clearfix"]/div[@class="inner"]/div[@class="add_to_cart 0"]/form/div[@class="line-item"]/div[@class="line-item-price"]/text()').extract()
           items.append(item)
       return items

管道代码如下:

class examplePipeline(object):

    def __init__(self):               
        self.dbpool = adbapi.ConnectionPool('MySQLdb',
                db='blurb',
                user='root',
                passwd='redhat',
                cursorclass=MySQLdb.cursors.DictCursor,
                charset='utf8',
                use_unicode=True
            )
def process_item(self, spider, item):
    # run db query in thread pool
    assert isinstance(item, Exampleitem)
    query = self.dbpool.runInteraction(self._conditional_insert, item)
    query.addErrback(self.handle_error)
    return item
def _conditional_insert(self, tx, item):
    print "db connected-=========>"
    # create record if doesn't exist. 
    tx.execute("select * from example_book_store where book_name = %s", (item['book_name']) )
    result = tx.fetchone()
    if result:
        log.msg("Item already stored in db: %s" % item, level=log.DEBUG)
    else:
        tx.execute("""INSERT INTO example_book_store (book_name,price)
                    VALUES (%s,%s)""",   
                            (item['book_name'],item['price'])
                    )
        log.msg("Item stored in db: %s" % item, level=log.DEBUG)            

def handle_error(self, e):
    log.err(e)          

运行后,我遇到了以下错误。
exceptions.NameError: global name 'Exampleitem' is not defined

当我在process_item方法中添加以下代码时,出现了上述错误。
assert isinstance(item, Exampleitem)

没有添加这行代码,我会得到什么错误信息?
**exceptions.TypeError: 'Example_spider' object is not subscriptable

有人能让这段代码运行起来,并确保所有项目都保存到数据库中吗?
3个回答

38

尝试在您的管道中使用以下代码

import sys
import MySQLdb
import hashlib
from scrapy.exceptions import DropItem
from scrapy.http import Request

class MySQLStorePipeline(object):
    def __init__(self):
        self.conn = MySQLdb.connect('host', 'user', 'passwd', 
                                    'dbname', charset="utf8",
                                    use_unicode=True)
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):    
        try:
            self.cursor.execute("""INSERT INTO example_book_store (book_name, price)  
                        VALUES (%s, %s)""", 
                       (item['book_name'].encode('utf-8'), 
                        item['price'].encode('utf-8')))            
            self.conn.commit()            
        except MySQLdb.Error, e:
            print "Error %d: %s" % (e.args[0], e.args[1])
        return item

我已经更新了上面的代码,但是遇到了以下错误,我无法使用它进行检查。(1064,“您的SQL语法有误;请检查与您的MySQL服务器版本相对应的手册,以获取正确的语法使用方式') - Shiva Krishna Bavandla
(1241, '操作数应该只包含1列') - Shiva Krishna Bavandla
8
如果你遇到了“关键字参数之后还有非关键字参数”的错误,使用以下代码: self.conn = MySQLdb.connect(user='dbuser', passwd='dbpasswd', db='dbname', host='dbhost', charset="utf8", use_unicode=True)来解决。请确保不改变原意,并且使翻译更加易懂。 - Michael Nguyen
8
错误的解决方案,与Scrapy异步IO和Twisted完全相矛盾。正确的方法请参见https://github.com/darkrho/dirbot-mysql。 - Guy Gavriely

1

你的 process_item 方法应该声明为:def process_item(self, item, spider): 而不是 def process_item(self, spider, item):,你把参数顺序搞反了。

这个异常:exceptions.NameError: global name 'Exampleitem' is not defined 表示你没有在管道中导入 Exampleitem。 尝试添加:from myspiders.myitems import Exampleitem (当然要正确填写名称/路径)。


谢谢,我得到了输出,但它显示了""(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '))' at line 2" ""。 - Shiva Krishna Bavandla
"并且""(1241,“操作数应该只包含1列”)""。项目未保存在数据库中。我写的查询中是否有错误,我没有发现任何错误。" - Shiva Krishna Bavandla
尝试将以下代码更改为:tx.execute("select book_name from example_book_store where book_name = %s", (item['book_name'], ) ),而不是 tx.execute("select * from example_book_store where book_name = %s", (item['book_name']) ) - Sjaak Trekhaak
关于SQL问题,最好提出一个关于SQL的具体问题。这需要更多的信息(例如错误发生在哪一行),而这些信息无法在评论中描述清楚。 - Sjaak Trekhaak

1
我认为这种方式更好,更简洁:

#Item
class pictureItem(scrapy.Item):
    topic_id=scrapy.Field()
    url=scrapy.Field()

#SQL
self.save_picture="insert into picture(`url`,`id`) values(%(url)s,%(id)s);"

#usage
cur.execute(self.save_picture,dict(item))

就像这样

cur.execute("insert into picture(`url`,`id`) values(%(url)s,%(id)s)" % {"url":someurl,"id":1})

原因(您可以在Scrapy中阅读更多关于项目的信息)

Field类只是内置字典类的别名,不提供任何额外的功能或属性。换句话说,Field对象是普通的Python字典。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接