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



我正在尝试执行以下操作:

  1. 从某个页面中抓取一些项目(包括URL(
  2. 将每个项目保存到mysql数据库
  3. 获取先前添加的记录的(auto_increment(ID
  4. 抓取上面URL指向的页面(#1(
  5. 使用对#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

一种更简单的方法是从第一个页面获取所有信息,然后使用url生成一个新的请求,parse_page方法作为回调,刮取的数据作为回调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

最新更新