Scrapy回调问题:要抓取项目的后续页面,我需要数据库中此项目的(auto_increment)ID

at0kjp5o  于 2022-11-09  发布在  其他
关注(0)|答案(1)|浏览(123)

我正在尝试以下操作:
1.从一些页面中抓取一些项目(包括URL)。
1.保存每个项目到一个mysql数据库
1.获取先前添加的记录的(auto_increment)ID
1.抓取上述URL指向的页面(#1)
1.保存此页上的所有项目,并引用(外键)到#3中定义的ID
在我看来,这是一个非常常见的问题,应该有一个相当简单的解决方案。
“item_scraped”信号看起来像是一个显而易见的解决方案,因为它提供了一个回调函数,用于在项目被完全处理时进行回调。
但是,似乎不可能从回调中启动另一个请求。
我在这里读到一些人建议使用Spider中间件,但我不知道如何使用,特别是因为Spider中间件本身不应该启动请求。
我在Python 3.8上使用的是Scrapy 2.6.2。
谢谢你的帮助。
下面是我的简化代码,没有错误处理等。
蜘蛛

import scrapy
from scrapy import signals

class MySpider(scrapy.Spider):
    name = 'MySpider'
    allowed_domains = ['www.somedomain.com']
    start_urls = [
        'https://www.somedomain.com/someurl/', 
        ]

    @classmethod
    def from_crawler(cls, crawler, *args,**kwargs):
        spider = cls()
        # requests the callback once an item is scraped
        crawler.signals.connect(spider.item_scraped, signals.item_scraped)
        return spider

    def parse(self, response):
        for node in response.xpath(".//tr/td[@class='foo']"):
            yield {
                'a': ...
                'b': ...
                'url': ...
            }

    def item_scraped(self, item, response, spider):

### 

### UNFORTUNATELY THIS IS NOT POSSIBLE

### 

        # forwards the new ID as a meta variable
        yield Request(item['url'], meta={'id':item['id']}, callback=self.parse_page)

    def parse_page(self, response):
        for node in response.xpath("//div[@class='soemthing']//a"):
            yield {
                'id': response.meta['id'],
                'title': ...
            }

和管道:

import mysql.connector

class WinebotPipeline(object):

    def __init__(self):
        self.conf = {'host': ..., 'user': ..., 'password': ..., 'database': ...}
        self.connection = self.mysql_connect()
        self.cursor = self.connection.cursor()

    def mysql_connect(self):
        return mysql.connector.connect(**self.conf)

    def process_item(self, item, spider):
        sql = "insert into `some_table` (`a`, `b`, `url`) values (%s, %s, %s)" 
        self.cursor.execute(sql, list(item.values()))
        self.connection.commit()

        # id of last inserted item
        item['id'] = self.cursor.lastrowid
        return item
jfgube3f

jfgube3f1#

一个更简单的方法是从第一个页面获取所有的信息,然后使用url生成一个新的请求,用parse_page方法作为回调函数,用scraped数据作为回调函数kwargs,然后从第二个url中获取必要的信息,然后将其添加到第一个页面的结果中,生成完整的条目。然后,您可以一次完成所有数据库条目。
蜘蛛

import scrapy
from scrapy import signals

class MySpider(scrapy.Spider):
    name = 'MySpider'
    allowed_domains = ['www.somedomain.com']
    start_urls = [
        'https://www.somedomain.com/someurl/', 
        ]

    def parse(self, response):
        for node in response.xpath(".//tr/td[@class='foo']"):
            cb_kwargs = {'a': ..., 'b': ...,   'url': ...}
            yield scrapy.Request(cb_kwargs['url'], 
                                 callback=self.parse_page, 
                                 cb_kwargs=cb_kwargs)

    def parse_page(self, response,**kwargs):
        for node in response.xpath("//div[@class='soemthing']//a"):
            kwargs.update({'title': ...})
            yield kwargs

管道

import mysql.connector

class WinebotPipeline(object):

    def __init__(self):
        self.conf = {'host': ..., 'user': ..., 'password': ..., 'database': ...}
        self.connection = self.mysql_connect()
        self.cursor = self.connection.cursor()

    def mysql_connect(self):
        return mysql.connector.connect(**self.conf)

    def process_item(self, item, spider):
        sql = "insert into `some_table` (`a`, `b`, `url`, 'title') values (%s, %s, %s, %s)" 
        self.cursor.execute(sql, list(item.values()))
        self.connection.commit()
        return item

相关问题