やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Pythonでニュース取得してSQLite3DBに登録する(一意制約エラー時)

 コンフリクトを変更した。

成果物

やりたいこと

 更新日時とURLが一致したら同一記事と判断して登録しないようにしたい。

実装

 insert時にコンフリクトさせる。

バグ

 insert or failだと一意制約エラーになったら、そこで中断されてしまい、それ以降の記事も登録されない。これが不都合なときがある。たとえば異なるカテゴリのRSSを2回に分けて取り込むとき。1回目と2回目で重複するニュースがあったが、それ以降には未登録なニュースがあるとき。最初に重複があるので以降は取り込まれない。

    def __insert_sql(self): 
        return 'insert or fail into news(published,url,title,body) values(?,?,?,?)'

修正

 そこで、insert or ignoreにしてみた。こちらによると、制約違反したところはスキップされて継続されるとある。これで最初のほうに一意制約エラーがあっても、それ以降に未登録があれば登録してくれるはず。

    def __insert_sql(self): 
        return 'insert or ignore into news(published,url,title,body) values(?,?,?,?)'

 この変更に伴い、以下の一意制約エラー時はpassするコードは不要となったので削除した。

        except sqlite3.IntegrityError as err_sql_integ:
            import traceback
            import sys
            msg = str(err_sql_integ.with_traceback(sys.exc_info()[2])).lower() # UNIQUE constraint failed: news.published, news.url
            # DB既存と重複した時点で中断する
            if ('UNIQUE'.lower() in msg and 'published' in msg and 'url' in msg): pass
            # それ以外ならエラー表示&ロールバックする
            else: 
                traceback.print_exc()
                self.conn.rollback() 

所感

 SQLite3の機能を使えば、Pythonコードがどんどん削れていく。いいね。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux