python爬虫爬取数据存储进数据库的问题

一直说我主键已存在,无法进行存储

我做的爬虫是csdn爬虫,针对于论坛一个版块,爬取某几页的所有帖子
我用的是flask-sqlalchemy来进行操作数据库,下面是三个需要用到的模型:

class Topic(db.Model):
     answer = relationship('Answer', backref='topic', lazy='dynamic')
     author_id = Column(String(30), ForeignKey('user.id'))
     id=Column(String(30),primary_key=True)
     title = Column(String(30))
     author_name=Column(String(30))
     create_time = Column('create_time', Integer)
     answer_nums=Column(Integer,default=0)
     content=Column(Text)
     click_nums=Column(String(30),default='0')
     parised_nums=Column(Integer,default=0)
     score=Column(Integer,default=0)
     status=Column(String(30))
     jtl=Column(String(30),default='0.0')

**_上面是帖子模型,跟answer模型相关联,answer模型就是一个帖子内的所有回答,而同时author_id是作为外键跟user模型相关联
**_

class Answer(db.Model):
    id=Column(String(30),primary_key=True)
    topic_name=Column(String(30))
    author_name=Column(String(30))
    author_id=Column(String(30))
    content=Column(Text)
    create_time = Column('create_time', Integer)
    parised_nums=Column(Integer,default=0)
    topic_id=Column(String(30),ForeignKey('topic.id'))

上面是针对每一个回答的模型

class User(db.Model):
    topic=relationship('Topic',backref='user',lazy='dynamic')
    id=Column(String(30),primary_key=True)
    click_nums=Column(String(30),default='0')
    original_nums=Column(Integer,default=0)        #原创数
    forward_nums=Column(Integer,default=0)         #转发数
    rate=Column(Integer,default=-1)               #排名
    answer_nums=Column(Integer,default=0)     #评论数
    parised_nums=Column(Integer,default=0)    #获赞数
    desc=Column(Text)                      #描述
    industry=Column(String(40))             #工作行业
    location=Column(String(40))
    follower_nums=Column(Integer,default=0)    #粉丝数
    following_nums=Column(Integer,default=0)   #关注数
    level=Column(Integer)

上面就是用到的三大模型:
下面是进行存储数据的代码:

   if page == 0:
      html = requests.get('https://bbs.csdn.net/forums/Mobile/recommend').text
   else:
       html=requests.get('https://bbs.csdn.net/forums/Mobile/recommend',params={'page':page}).text
   bsoj = BeautifulSoup(html, 'lxml')
   tags= bsoj.find('div', class_='forums_table_c').tbody.find_all('tr')
   '''
   爬取这一页的帖子,至于第几页根据传进来的page所定义
   tags就是里面帖子的集合
   '''
   for tag in tags:
      status=self.get_status(tag)
      score=self.get_score(tag)
      answer_nums,click_nums=self.get_click_nums_and_answer_nums(tag)
      '''
      上面这三个是需要爬取的几个东西,不需要理会
      '''
      url='https://bbs.csdn.net'+self.get_url(tag)
      '''
      这个url就是每一个帖子的url
      '''
      topic=Topic(url,score,status,click_nums,int(answer_nums))
      topic_db = Topic_Model(topic)
      '''
      初始化topic,这个topic_db就是topic模型的对象
      '''
      user = User(topic.author_id)
      user_db = User_Model(user)
      '''
      user就是user模型的对象

      '''
      self.onhand(url,topic,topic_db,user_db,user)





 def onhand(self,url,topic,topic_db,user_db,user):
    html=requests.get(url).text
    bsoj=BeautifulSoup(html,'lxml')
    tags=bsoj.find_all('div',class_='mod_topic_wrap post')
    answers=[]
    '''
    这一步是为了抓取一个帖子内所有的回答
    '''
    for tag in tags:
       answer=Answer(topic,tag)
       answer_db=Answer_Model(answer)
       answers.append(answer_db)
     '''
     抓取所有回答,并将每一个回答实例化一个Answer模型的对象
     '''

    topic_db.answer=answers
    '''
    关联数据库,将所有的answer对象都放在topic里面
    '''
    user_db.topic.append(topic_db)
    '''
    user与topic关联

    这里是有问题的,因为如果user已经存在再数据库里,那么就不会提交,那么这个topic增加就没意义了,但是我不知道如何解决
    '''
    if User_Model.query.filter_by(id=user.id).first() is None:
           db.session.add(user_db)
           db.session.commit()
     '''
     判断是否要存储到数据库里
     '''
    db.session.add(topic_db)
    db.session.commit()

    for data in answers:
       db.session.add(data)
       db.session.commit()
        '''
        将answer集合里的所有answer提交到数据库中
        '''

下面是报错信息:
图片说明

明明已经进行判断了,如果存在就不会进行存储,照样报错了,而且奇怪的是我debug时是这一句出现了错误:

db.session.add(topic_db)
    db.session.commit()

不知道如何解决,求各位大佬帮忙

3个回答

首先,我建议你主键最好不要设在userId上。让ID自增长。然后把userId作为一个普通的字段。
其次,我个人建议也不要设置外键关系。你可以通过把某一张表的ID放到另一张表里作为关联,但是不建议设置外检关系。
如果能做到这两样,应该能解决很多问题。
最后,如果非要把userId或者其他的ID设唯一索引,那么最好用Set把这个ID缓存下来,在存之前进行筛选。又或者把要存的的ID在库里查一遍。记得加索引。
又或者用saveOrUpdate()去做。

那么你检查下你的数据库里面userid是不是已经有这个用户id了,你是爬帖子又不是爬用户,为什么把用户名作为主键?

if User_Model.query.filter_by(id=user.id).first() is None:改为if not User_Model.query.filter_by(id=user.id).first():试试;

至于你说的debug问题出在topic的位置,应该只是编译器位置标识的不对吧,栈里面显示是插入user表时出错;

不过话说回来,虽然应该相信csdn用户id不会重复,还是不建议你用用户id做主键...

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问