6

我想在使用scrapy爬行时跳过一些文件类型链接.exe .zip .pdf,但不想使用带有特定url常规的规则。如何?

更新:

因此,当正文尚未下载时,很难决定是否仅通过 Content-Type 响应此链接。我更改为在下载器中间件中删除 url。谢谢彼得和利奥。

4

3 回答 3

15

如果你转到 Scrapy 根目录中的 linkextractor.py,你会看到以下内容:

"""
Common code and definitions used by Link extractors (located in
scrapy.contrib.linkextractor).
"""

# common file extensions that are not followed if they occur in links
IGNORED_EXTENSIONS = [
    # images
    'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif',
    'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg',

    # audio
    'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff',

    # video
    '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',
    'm4a',

    # other
    'css', 'pdf', 'doc', 'exe', 'bin', 'rss', 'zip', 'rar',
]

但是,由于这适用于链接提取器(并且您不想使用规则),我不确定这是否会解决您的问题(我刚刚意识到您指定您不想使用规则。我以为您有询问如何更改文件扩展名限制而不需要直接在规则中指定)。

好消息是,您还可以构建自己的下载器中间件,并将任何/所有请求丢弃到具有不良扩展名的 url。请参阅下载器中间件

您可以通过访问对象的 url 属性来获取请求request的 url,如下所示:request.url

基本上,在字符串末尾搜索“.exe”或您要删除的任何扩展名,如果它包含所述扩展名,则返回IgnoreRequest异常,请求将立即被删除。

更新

为了在下载请求之前处理请求,您需要确保在自定义下载器中间件中定义“process_request”方法。

根据 Scrapy 文档

process_request

每个通过下载中间件的请求都会调用此方法。

process_request() 应该返回 None、Response 对象或 Request 对象。

如果它返回 None,Scrapy 将继续处理这个请求,执行所有其他中间件,直到最后,适当的下载器处理程序被称为执行的请求(并下载它的响应)。

如果它返回一个 Response 对象,Scrapy 不会费心调用任何其他请求或异常中间件,或适当的下载函数;它会返回那个响应。响应中间件总是在每个响应上被调用。

如果它返回一个 Request 对象,则返回的请求将被重新调度(在调度程序中)以供将来下载。将始终调用原始请求的回调。如果新请求有回调,它将在下载响应时调用,然后该回调的输出将传递给原始回调。如果新请求没有回调,则下载的响应将仅传递给原始请求回调。

如果它返回一个 IgnoreRequest 异常,整个请求将被完全丢弃,并且它的回调永远不会被调用。

所以本质上,只需创建一个下载器类,添加一个方法类process_request,它以请求对象和蜘蛛对象为参数。如果 url 包含不需要的扩展名,则返回 IgnoreRequest 异常。

这一切都应该在页面被下载之前发生。但是,如果您想要处理响应标头,则必须向网页发出请求。

您始终可以在下载器中同时实现 process_request 和 process_response 方法,其想法是立即删除明显的扩展名,并且如果由于某种原因 url 不包含文件扩展名,则请求将被处理并被捕获process_request 方法(因为您可以在标题中验证)?

于 2012-08-29T03:53:17.777 回答
3

.zip and .pdf are ignored by scrapy by default.

As a general rule you can either configure a rule to include only urls that match your regexp (.htm* in this case):

rules = (Rule(SgmlLinkExtractor(allow=('\.htm')), callback='parse_page', follow=True, ), )

or exclude the ones that match a regexp:

rules = (Rule(SgmlLinkExtractor(allow=('.*'), deny=('\.pdf', '\.zip')), callback='parse_page', follow=True, ), )

Read the documentation for more information.

于 2012-08-28T06:33:09.913 回答
2

我构建了这个中间件来排除任何不在正则表达式白名单中的响应类型:

from scrapy.http.response.html import HtmlResponse
from scrapy.exceptions import IgnoreRequest
from scrapy import log
import re

class FilterResponses(object):
    """Limit the HTTP response types that Scrapy dowloads."""

    @staticmethod
    def is_valid_response(type_whitelist, content_type_header):
        for type_regex in type_whitelist:
            if re.search(type_regex, content_type_header):
                return True
        return False


    def process_response(self, request, response, spider):
        """
        Only allow HTTP response types that that match the given list of 
        filtering regexs
        """
        # to specify on a per-spider basis
        # type_whitelist = getattr(spider, "response_type_whitelist", None)
        type_whitelist = (r'text', )
        content_type_header = response.headers.get('content-type', None)
        if not content_type_header or not type_whitelist:
            return response

        if self.is_valid_response(type_whitelist, content_type_header):
            return response
        else:
            msg = "Ignoring request {}, content-type was not in whitelist".format(response.url)
            log.msg(msg, level=log.INFO)
            raise IgnoreRequest()

要使用它,请将其添加到 settings.py:

DOWNLOADER_MIDDLEWARES = {
    '[project_name].middlewares.FilterResponses': 999,
}
于 2014-05-12T20:02:00.573 回答