If 语句仅将新值写入 Scrapy 中的 PostgreSQL 数据库

If statement to only write new values to PostgreSQL db in Scrapy

我有一个 Scrapy 蜘蛛,它使用 psycopg2 将抓取的数据写入 PostgreSQL 数据库。我有 Scrapyd 运行 和物品出口商,一切都设置好了。我正在为 post url、标题和创建日期抓取 craigslist 的劳动部分。我想在新的 post 上创建通知,因此我将 PostgreSQL 数据库中的 url 字段设为主键。

我尝试的第一件事是一个 try 块(它在我 运行 使用请求和 BeautifulSoup.

的抓取器中工作
        try:
            cur.execute( 'INSERT INTO postgres.public.clist (title, url, created, time) VALUES (%s, %s, %s, %s)', (title, url, pdate, pdate))
            print('notification')
        except:
            pass
        finally:
            conn.commit()

Scrapy 引擎似乎从不抛出异常,因为它总是尝试 INSERT INTO 数据库。蜘蛛的第二遍将从 psycopg2 抛出一堆错误,因为 url 字段不是唯一的。

psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "clist_url_uindex"
DETAIL:  Key (url)=(https://delaware.craigslist.org/lbg/d/wilmington-truck-cargo-vans-owners-make/6959980210.html) already exists.

接下来我试了

def process_item(self, item, spider):

    cdate = datetime.strptime(item['dtime'][0], '%Y-%m-%d %H:%M')
    item_title = item['title'][0]
    item_url = item['url'][0]
    query = 'select * from postgres.public.clist where url = %s'
    self.cur.execute(query, (item_url, ))
    results = self.cur.rowcount
    if results is not 0:
       self.cur.execute( "insert into postgres.public.clist(title, url, created, time) values(%s,%s, %s, %s)", (item_title, item_url, cdate, cdate) )
    else:
       pass
    self.connection.commit()

它仍然尝试写入每条记录,但我收到一个错误,因为 url 字段不是唯一的。

我不明白为什么这些都不起作用,尤其是在 Scrapy 环境之外工作的 try 块。

我什至在 middlewares.py 文件中看到了 process_spider_exception,它已经包含 pass

有人能为我指明正确的方向,说明为什么这不起作用吗?

您的代码显示 "Do a lookup of the number of times this url exists in the database. If that number is not zero, then insert the url, otherwise do nothing"。

逻辑反了。您只想在计数 = 0 时执行插入操作。

附带说明一下,您应该查看 ON DUPLICATE KEY UPDATE

所以我弄清楚了我的问题,虽然我的 if 语句的逻辑在我发布时是倒退的,但我也以另一种方式使用它,但它仍然无法正常工作。

正如我在上面的评论中所说,我需要 raise DropItem 否则项目管道将继续处理它。一旦我弄明白了这一点,我仍然有问题,因为我犯了我认为是一个菜鸟错误的错误,也许为什么只有一个人发表评论。

虽然在处理 Scrapy 时这对大多数人来说似乎是显而易见的(现在我明白了,这对我来说也是如此),并且您的蜘蛛 运行 在 Scrapyd 上。如果您更改了蜘蛛、管道、中间件等的代码。您必须重新部署蜘蛛才能使用新代码。

我想出来了,因为我决定完全改变管道的逻辑,将项目处理成 csv 文件,然后当蜘蛛关闭时,在 pandas 数据库中打开 .csv 文件,然后 drop_duplicates()。然后使用 pandas to_csv() 保存 .csv 文件。我打算在调用蜘蛛程序的主程序中将 .csv 读入数据库。

将所有这些代码放入并保存后,我 运行 我的蜘蛛。快速打开日志,尽管我当前的项目中没有 sql 代码(至少保存在本地),但它仍然给出 sql 错误。没多久我就把2和2放在一起了

TL;DR

当编辑部署到 Scrapyd 的爬虫代码时,您必须在保存新代码后再次部署爬虫。我希望这有助于将某人从我为此经历的无数小时的挫败感中解救出来。

编辑:添加我的有效 if 语句:

        if results is not 0:
            raise DropItem('item') #text inside '' gets put in log
        else:
            self.cur.execute( "insert into postgres.public.clist(title, url, created, time) values(%s,%s, %s, %s)",                        (item_title, item_url, cdate, cdate) )
            self.connection.commit()