Skip to main content
 首页 » 编程设计

python之Scrapy:通过管道发送到数据库时包含状态代码为 404 的项目

2025年05月04日23youxin

在 python 2.x 环境中使用 Scrapy,我设置了一个蜘蛛来抓取网页列表,专门查看这些页面是否产生错误,例如 400/404/500。

我编写 scrapy 项目的目的是将所有抓取的结果通过管道存储在 mysql 数据库中。 它有效!我能够成功写入我的数据库。但仅限于成功抓取的页面,HTTP 状态代码为 200。

Scrapy 似乎没有通过管道将 404 页面上的信息发送到数据库中。

下面是蜘蛛代码的摘录,它抓取了两个不存在的网页:

class LandingPage004Spider(scrapy.Spider): 
name='LandingPage004Spider' 
start_urls = [] 
 
def __init__(self): 
    super(LandingPage004Spider,self).__init__() 
    #self.start_urls = unique_landingpages 
    self.start_urls = ['https://www.google.com/doesntexist', 'https://www.google.com/deadpage'] 
 
def parse(self, response): 
    url = response.url 
    url_title = 'Title goes here.' 
    pagesize = len(response.body) 
    HTTP_code = response.status 
    yield {'url': url, "pagesize": pagesize, "HTTP_code": HTTP_code} 

当我运行这个蜘蛛时,我得到以下输出:

[scrapy] DEBUG: Ignoring response <404 https://www.google.com/deadpage>: HTTP status code is not handled or not allowed 
[scrapy] DEBUG: Ignoring response <404 https://www.google.com/doesntexist>: HTTP status code is not handled or not allowed 

现在,我对此进行了大量搜索,看起来这可能是故意的,并且有一种方法可以强制 scrapy 包含 404。我看到有一个选项 dont_filter,但我只能找到有关如何将该代码附加到类似于以下代码语法的说明: yield Request(url="test.com", callback=self.callback, dont_filter = True)

但是我的蜘蛛的结构似乎不允许任何这样的行。

我说的 404 没有被发送到数据库,这是我设计的吗? 有没有办法附加我当前的代码以允许记录 404?

如果有帮助,这里是 pipelines.py 文件:

from sqlalchemy.orm import sessionmaker 
from LandingPageVerifier.models import LandingPagesScrapeResults, db_connect 
 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.engine import create_engine 
 
Base = declarative_base() 
 
class Landingpageverifier004Pipeline(object): 
    def __init__(self): 
        """ 
        Initializes database connection and sessionmaker. 
        """ 
        engine = db_connect() 
        self.Session = sessionmaker(bind=engine) 
 
def process_item(self, item, spider): 
    session = self.Session() 
    landingpage_scrape_results = LandingPagesScrapeResults() 
    landingpage_scrape_results.url = item["url"] 
    landingpage_scrape_results.client_id = 1 
    landingpage_scrape_results.HTTP_code = item["HTTP_code"] 
    landingpage_scrape_results.page_size = item["pagesize"] 
 
    try: 
        session.add(landingpage_scrape_results) 
        session.commit() 
    except: 
        session.rollback() 
        raise 
    finally: 
        session.close() 
 
    return item 

以及我的 models.py 文件的摘录:

class LandingPagesScrapeResults(Base): 
    __tablename__ = 'landingpages_scrape_results' 
    id = Column(Integer(), primary_key=True) 
    client_id = Column(Integer(), ForeignKey('landingpages_clients.id')) 
    url = Column(String(512), nullable=True) 
    url_shortener = Column(String(32), nullable=True) 
    url_title = Column(String(256), nullable=True) 
    page_size = Column(Integer(), nullable=True) 
    created_on = Column(DateTime(),default=datetime.datetime.now) 
    HTTP_code = Column(String(4), nullable=True) 
    err_small = Column(String(1), nullable=True) 
    err_has_not_found = Column(String(1), nullable=True) 
    err_has_error = Column(String(1), nullable=True) 
    err_has_nolongeravailable  = Column(String(1), nullable=True) 
    err_no_service_specials = Column(String(1), nullable=True) 

请您参考如下方法:

@stranac 当然给出了一个很好的答案,但您也可以直接使用 errback 请求属性来处理这个问题,它将捕获所有错误的响应,特别是在您需要的请求中:

def parse(self, response): 
    yield Request( 
        'http://httpbin.org/status/404',  
        errback=self.parse_error,  
        callback=self.parse_item, 
    ) 
 
def parse_error(self, failure): 
    if failure.value.response.status == 404: 
        # insert item as a bad response 
 
def parse_item(self, response): 
    # insert item as good response 

或者您当然也可以始终使用中间件,以便在收到各种响应/请求后立即捕获。