我是scrapy的新手,它是我所知道的惊人的爬虫框架!
在我的项目中,我发送了超过90,000个请求,但其中一些请求失败了。 我将日志级别设置为INFO,我只能看到一些统计信息,但没有详细信息。
2012-12-05 21:03:04+0800 [pd_spider] INFO: Dumping spider stats:
{'downloader/exception_count': 1,
'downloader/exception_type_count/twisted.internet.error.ConnectionDone': 1,
'downloader/request_bytes': 46282582,
'downloader/request_count': 92383,
'downloader/request_method_count/GET': 92383,
'downloader/response_bytes': 123766459,
'downloader/response_count': 92382,
'downloader/response_status_count/200': 92382,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2012, 12, 5, 13, 3, 4, 836000),
'item_scraped_count': 46191,
'request_depth_max': 1,
'scheduler/memory_enqueued': 92383,
'start_time': datetime.datetime(2012, 12, 5, 12, 23, 25, 427000)}
有没有办法获得更多细节报告?例如,显示那些失败的URL。谢谢!
答案 0 :(得分:48)
是的,这是可能的。
我在我的蜘蛛类中添加了一个failed_urls列表,如果响应的状态为404,则会向其添加url(这将需要扩展以涵盖其他错误状态)。
然后我添加了一个句柄,将列表连接成一个字符串,并在蜘蛛关闭时将其添加到统计数据中。
根据您的评论,可以跟踪扭曲的错误。
from scrapy.spider import BaseSpider
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
class MySpider(BaseSpider):
handle_httpstatus_list = [404]
name = "myspider"
allowed_domains = ["example.com"]
start_urls = [
'http://www.example.com/thisurlexists.html',
'http://www.example.com/thisurldoesnotexist.html',
'http://www.example.com/neitherdoesthisone.html'
]
def __init__(self, category=None):
self.failed_urls = []
def parse(self, response):
if response.status == 404:
self.crawler.stats.inc_value('failed_url_count')
self.failed_urls.append(response.url)
def handle_spider_closed(spider, reason):
self.crawler.stats.set_value('failed_urls', ','.join(spider.failed_urls))
def process_exception(self, response, exception, spider):
ex_class = "%s.%s" % (exception.__class__.__module__, exception.__class__.__name__)
self.crawler.stats.inc_value('downloader/exception_count', spider=spider)
self.crawler.stats.inc_value('downloader/exception_type_count/%s' % ex_class, spider=spider)
dispatcher.connect(handle_spider_closed, signals.spider_closed)
输出(下载器/ exception_count *统计信息仅在实际抛出异常时出现 - 我通过在关闭无线适配器后尝试运行蜘蛛来模拟它们):
2012-12-10 11:15:26+0000 [myspider] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 15,
'downloader/exception_type_count/twisted.internet.error.DNSLookupError': 15,
'downloader/request_bytes': 717,
'downloader/request_count': 3,
'downloader/request_method_count/GET': 3,
'downloader/response_bytes': 15209,
'downloader/response_count': 3,
'downloader/response_status_count/200': 1,
'downloader/response_status_count/404': 2,
'failed_url_count': 2,
'failed_urls': 'http://www.example.com/thisurldoesnotexist.html, http://www.example.com/neitherdoesthisone.html'
'finish_reason': 'finished',
'finish_time': datetime.datetime(2012, 12, 10, 11, 15, 26, 874000),
'log_count/DEBUG': 9,
'log_count/ERROR': 2,
'log_count/INFO': 4,
'response_received_count': 3,
'scheduler/dequeued': 3,
'scheduler/dequeued/memory': 3,
'scheduler/enqueued': 3,
'scheduler/enqueued/memory': 3,
'spider_exceptions/NameError': 2,
'start_time': datetime.datetime(2012, 12, 10, 11, 15, 26, 560000)}
答案 1 :(得分:15)
这是另一个如何处理和收集404错误的例子(检查github帮助页面):
from scrapy.selector import HtmlXPathSelector
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.item import Item, Field
class GitHubLinkItem(Item):
url = Field()
referer = Field()
status = Field()
class GithubHelpSpider(CrawlSpider):
name = "github_help"
allowed_domains = ["help.github.com"]
start_urls = ["https://help.github.com", ]
handle_httpstatus_list = [404]
rules = (Rule(SgmlLinkExtractor(), callback='parse_item', follow=True),)
def parse_item(self, response):
if response.status == 404:
item = GitHubLinkItem()
item['url'] = response.url
item['referer'] = response.request.headers.get('Referer')
item['status'] = response.status
return item
只需使用scrapy runspider
运行-o output.json
,然后查看output.json
文件中的项目列表。
答案 2 :(得分:13)
来自@Talvalin和@alecxe的答案对我有很大的帮助,但他们似乎没有捕获不生成响应对象的下载事件(例如,twisted.internet.error.TimeoutError
和twisted.web.http.PotentialDataLoss
)。这些错误在运行结束时显示在stats转储中,但没有任何元信息。
当我发现here时,stats.py中间件会跟踪错误,这些中间件是在DownloaderStats
类process_exception
方法中捕获的,特别是{{1}变量,根据需要递增每个错误类型,然后在运行结束时转储计数。
要将此类错误与来自相应请求对象的信息相匹配,您可以为每个请求添加唯一ID(通过ex_class
),然后将其添加到request.meta
process_exception
方法中:
stats.py
这将为每个基于下载程序的错误生成唯一字符串,而不会附带响应。然后,您可以将已更改的self.stats.set_value('downloader/my_errs/{0}'.format(request.meta), ex_class)
保存为其他内容(例如stats.py
),将其添加到下载器中间件(具有正确的优先级),并禁用库存my_stats.py
:
stats.py
运行结束时的输出如下所示(这里使用元信息,其中每个请求url映射到group_id,member_id用斜杠分隔,如DOWNLOADER_MIDDLEWARES = {
'myproject.my_stats.MyDownloaderStats': 850,
'scrapy.downloadermiddleware.stats.DownloaderStats': None,
}
):
'0/14'
This answer处理非基于下载程序的错误。
答案 3 :(得分:10)
Scrapy默认忽略404并且不解析它。如果您在回复时收到错误代码404,则可以通过非常简单的方式处理此问题。
在 settings.py 中,写一下:
let contacts = swiftyJsonVar["contacts"].arrayValue
let allMobilePhones = contacts.map { $0["phone"]["mobile"].stringValue }
print(allMobilePhones)
然后在您的解析函数中处理响应状态代码:
HTTPERROR_ALLOWED_CODES = [404,403]
答案 4 :(得分:5)
从scrapy 0.24.6开始,alecxe建议的方法不会捕获起始URL的错误。要使用起始网址记录错误,您需要覆盖parse_start_urls
。为此目的调整alexce的答案,你会得到:
from scrapy.selector import HtmlXPathSelector
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.item import Item, Field
class GitHubLinkItem(Item):
url = Field()
referer = Field()
status = Field()
class GithubHelpSpider(CrawlSpider):
name = "github_help"
allowed_domains = ["help.github.com"]
start_urls = ["https://help.github.com", ]
handle_httpstatus_list = [404]
rules = (Rule(SgmlLinkExtractor(), callback='parse_item', follow=True),)
def parse_start_url(self, response):
return self.handle_response(response)
def parse_item(self, response):
return self.handle_response(response)
def handle_response(self, response):
if response.status == 404:
item = GitHubLinkItem()
item['url'] = response.url
item['referer'] = response.request.headers.get('Referer')
item['status'] = response.status
return item
答案 5 :(得分:5)
这是此问题的更新。我遇到了类似的问题,需要使用scrapy信号来调用我的管道中的函数。我已经编辑了@ Talvalin的代码,但是为了更清晰一点,我想回答一下。
基本上,你应该将self添加为handle_spider_closed的参数。 您还应该在init中调用调度程序,以便可以将spider实例(self)传递给handleing方法。
from scrapy.spider import Spider
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
class MySpider(Spider):
handle_httpstatus_list = [404]
name = "myspider"
allowed_domains = ["example.com"]
start_urls = [
'http://www.example.com/thisurlexists.html',
'http://www.example.com/thisurldoesnotexist.html',
'http://www.example.com/neitherdoesthisone.html'
]
def __init__(self, category=None):
self.failed_urls = []
# the dispatcher is now called in init
dispatcher.connect(self.handle_spider_closed,signals.spider_closed)
def parse(self, response):
if response.status == 404:
self.crawler.stats.inc_value('failed_url_count')
self.failed_urls.append(response.url)
def handle_spider_closed(self, spider, reason): # added self
self.crawler.stats.set_value('failed_urls',','.join(spider.failed_urls))
def process_exception(self, response, exception, spider):
ex_class = "%s.%s" % (exception.__class__.__module__, exception.__class__.__name__)
self.crawler.stats.inc_value('downloader/exception_count', spider=spider)
self.crawler.stats.inc_value('downloader/exception_type_count/%s' % ex_class, spider=spider)
我希望这可以帮助将来遇到同样问题的任何人。
答案 6 :(得分:1)
除了其中一些答案之外,如果你想跟踪Twisted错误,我会看一下使用Request对象的errback
参数,你可以在其上设置一个回调函数来调用{ {3}}请求失败。
除了url之外,此方法还允许您跟踪故障类型。
然后,您可以使用以下网址记录网址:failure.request.url
(其中failure
是传递到Failure
的Twisted errback
对象。)
# these would be in a Spider
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url, callback=self.parse,
errback=self.handle_error)
def handle_error(self, failure):
url = failure.request.url
logging.error('Failure type: %s, URL: %s', failure.type,
url)
Scrapy文档提供了如何完成此操作的完整示例,除了对Scrapy记录器的调用现在是Twisted Failure,所以我调整了我的示例以使用内置的depreciated内置的Python ):
答案 7 :(得分:1)
您可以通过两种方式捕获失败的网址。
使用errback定义scrapy请求
class TestSpider(scrapy.Spider):
def start_requests(self):
yield scrapy.Request(url, callback=self.parse, errback=self.errback)
def errback(self, failure):
'''handle failed url (failure.request.url)'''
pass
使用signals.item_dropped
class TestSpider(scrapy.Spider):
def __init__(self):
crawler.signals.connect(self.request_dropped, signal=signals.request_dropped)
def request_dropped(self, request, spider):
'''handle failed url (request.url)'''
pass
[!注意] 使用errback的scrapy请求无法捕获某些自动重试失败,例如设置中的连接错误RETRY_HTTP_CODES。
答案 8 :(得分:0)
默认情况下,Scrapy基本忽略404错误,它是在httperror中间件中定义的。
因此,将 HTTPERROR_ALLOW_ALL = True 添加到您的设置文件。
此后,您可以通过解析函数访问 response.status 。
您可以这样处理。
def parse(self,response):
if response.status==404:
print(response.status)
else:
do something