Scrapy正在跟踪和抓取不允许的链接

6 投票
1 回答
3813 浏览
提问于 2025-04-17 08:31

我有一个叫CrawlSpider的程序,它可以跟踪特定的链接,并从一个新闻杂志上抓取内容。这个杂志的每一期链接都是这样的格式:

http://example.com/YYYY/DDDD/index.htm,其中YYYY代表年份,DDDD是三位或四位的期号。

我只想抓取从928期开始的内容,下面是我的规则。我连接网站、抓取链接和提取内容都没有问题(所以我没有把其他代码放上来)。但是,这个爬虫似乎总是想跟踪不允许的链接。它试图抓取377期、398期等等,还跟踪了“culture.htm”和“feature.htm”的链接。这导致了很多错误,虽然这些错误不是特别重要,但却需要花很多时间来清理数据。有没有人能告诉我,问题出在哪里?

class crawlerNameSpider(CrawlSpider):
name = 'crawler'
allowed_domains = ["example.com"]
start_urls = ["http://example.com/issues.htm"]

rules = (
        Rule(SgmlLinkExtractor(allow = ('\d\d\d\d/(92[8-9]|9[3-9][0-9]|\d\d\d\d)/index\.htm', )), follow = True),
        Rule(SgmlLinkExtractor(allow = ('fr[0-9].htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(allow = ('eg[0-9]*.htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(allow = ('ec[0-9]*.htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(allow = ('op[0-9]*.htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(allow = ('sc[0-9]*.htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(allow = ('re[0-9]*.htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(allow = ('in[0-9]*.htm', )), callback = 'parse_item'),
        Rule(SgmlLinkExtractor(deny = ('culture.htm', )), ),
        Rule(SgmlLinkExtractor(deny = ('feature.htm', )), ),
    )

补充:我用一个更简单的正则表达式修复了2009、2010和2011年的问题,但我还是很好奇,为什么之前的方式不管用,如果有人有建议的话。

1 个回答

7

你需要给 SgmlLinkExtractor 传递 deny 参数,这样它才能收集到要 follow 的链接。而且,如果这些规则都调用同一个函数 parse_item,你就不需要创建那么多 Rule 了。我会把你的代码写成这样:

rules = (
        Rule(SgmlLinkExtractor(
                    allow = ('\d\d\d\d/(92[8-9]|9[3-9][0-9]|\d\d\d\d)/index\.htm', ),
                    deny = ('culture\.htm', 'feature\.htm'),
                    ), 
            follow = True
        ),
        Rule(SgmlLinkExtractor(
                allow = (
                    'fr[0-9].htm', 
                    'eg[0-9]*.htm',
                    'ec[0-9]*.htm',
                    'op[0-9]*.htm',
                    'sc[0-9]*.htm',
                    're[0-9]*.htm',
                    'in[0-9]*.htm',
                    )
                ), 
                callback = 'parse_item',
        ),
    )

如果你在规则中使用的是真实的 URL 模式来调用 parse_item,那么可以简化成这样:

 Rule(SgmlLinkExtractor(
                allow = ('(fr|eg|ec|op|sc|re|in)[0-9]*\.htm', ), 
                callback = 'parse_item',
        ),
 )

撰写回答